[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v4 14/39] arm/p2m: Add HVMOP_altp2m_set_domain_state



The HVMOP_altp2m_set_domain_state allows to activate altp2m on a
specific domain. This commit adopts the x86
HVMOP_altp2m_set_domain_state implementation.

Signed-off-by: Sergej Proskurin <proskurin@xxxxxxxxxxxxx>
---
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
---
v2: Dynamically allocate memory for altp2m views only when needed.
    Move altp2m related helpers to altp2m.c.
    p2m_flush_tlb is made publicly accessible.

v3: Cosmetic fixes.

    Removed call to "p2m_alloc_table" in "altp2m_init_helper" as the
    entire p2m allocation is now done within the function
    "p2m_init_one". The same applies to the call of the function
    "p2m_flush_tlb" from "p2m_init_one".

    Removed the "altp2m_enabled" check in HVMOP_altp2m_set_domain_state
    case as it has been moved in front of the switch statement in
    "do_altp2m_op".

    Changed the order of setting the new altp2m state (depending on
    setting/resetting the state) in HVMOP_altp2m_set_domain_state case.

    Removed the call to altp2m_vcpu_reset from altp2m_vcpu_initialize,
    as the p2midx is set right after the call to 0, representing the
    default view.

    Moved the define "vcpu_altp2m" from domain.h to altp2m.h to avoid
    defining altp2m-related functionality in multiple files. Also renamed
    "vcpu_altp2m" to "altp2m_vcpu".

    Declared the function "p2m_flush_tlb" as static, as it is not called
    from altp2m.h anymore.

    Exported the function "altp2m_get_altp2m" in altp2m.h.

    Exchanged the check "altp2m_vttbr[idx] == INVALID_VTTBR" for
    "altp2m_p2m[idx] == NULL" in "altp2m_init_by_id".

    Set the field p2m->access_required to false by default.

v4: Removed unnecessary initialization in "altp2m_init_helper".

    Move the field "active_vcpus" in "struct p2m_domain" out of this
    commit.

    Set "d->arch.altp2m_active" to the provided new state only once instead of
    for each vCPU.

    Move the definition of the macro INVALID_ALTP2M to a common place in
    a separate commit.

    ARM supports an external-only interface to the altp2m subsystem,
    i.e., the guest does not have access to the altp2m subsystem. Thus,
    we remove the check for the current vcpu in the function
    altp2m_vcpu_initialize; there is no scenario in which a guest is
    allowed to initialize the altp2m subsystem for itself.

    Cosmetic fixes.
---
 xen/arch/arm/altp2m.c        | 97 ++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/hvm.c           | 30 +++++++++++++-
 xen/include/asm-arm/altp2m.h | 10 +++++
 xen/include/asm-arm/domain.h |  3 ++
 4 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c
index 9c06055a94..43e95c5681 100644
--- a/xen/arch/arm/altp2m.c
+++ b/xen/arch/arm/altp2m.c
@@ -20,6 +20,103 @@
 #include <asm/p2m.h>
 #include <asm/altp2m.h>
 
+struct p2m_domain *altp2m_get_altp2m(struct vcpu *v)
+{
+    unsigned int idx = v->arch.ap2m_idx;
+
+    if ( idx == INVALID_ALTP2M )
+        return NULL;
+
+    BUG_ON(idx >= MAX_ALTP2M);
+
+    return v->domain->arch.altp2m_p2m[idx];
+}
+
+static void altp2m_vcpu_reset(struct vcpu *v)
+{
+    v->arch.ap2m_idx = INVALID_ALTP2M;
+}
+
+void altp2m_vcpu_initialize(struct vcpu *v)
+{
+    /*
+     * ARM supports an external-only interface to the altp2m subsystem, i.e.,
+     * the guest does not have access to the altp2m subsystem. Thus, we can
+     * simply pause the vcpu, as there is no scenario in which we initialize
+     * altp2m on the current vcpu. That is, the vcpu must be paused every time
+     * we initialize altp2m.
+     */
+    vcpu_pause(v);
+
+    v->arch.ap2m_idx = 0;
+    atomic_inc(&altp2m_get_altp2m(v)->active_vcpus);
+
+    vcpu_unpause(v);
+}
+
+void altp2m_vcpu_destroy(struct vcpu *v)
+{
+    struct p2m_domain *p2m;
+
+    if ( v != current )
+        vcpu_pause(v);
+
+    if ( (p2m = altp2m_get_altp2m(v)) )
+        atomic_dec(&p2m->active_vcpus);
+
+    altp2m_vcpu_reset(v);
+
+    if ( v != current )
+        vcpu_unpause(v);
+}
+
+static int altp2m_init_helper(struct domain *d, unsigned int idx)
+{
+    int rc;
+    struct p2m_domain *p2m = d->arch.altp2m_p2m[idx];
+
+    ASSERT(p2m == NULL);
+
+    /* Allocate a new, zeroed altp2m view. */
+    p2m = xzalloc(struct p2m_domain);
+    if ( p2m == NULL)
+        return -ENOMEM;
+
+    p2m->p2m_class = p2m_alternate;
+
+    /* Initialize the new altp2m view. */
+    rc = p2m_init_one(d, p2m);
+    if ( rc )
+        goto err;
+
+    d->arch.altp2m_p2m[idx] = p2m;
+
+    return rc;
+
+err:
+    xfree(p2m);
+    d->arch.altp2m_p2m[idx] = NULL;
+
+    return rc;
+}
+
+int altp2m_init_by_id(struct domain *d, unsigned int idx)
+{
+    int rc = -EINVAL;
+
+    if ( idx >= MAX_ALTP2M )
+        return rc;
+
+    altp2m_lock(d);
+
+    if ( d->arch.altp2m_p2m[idx] == NULL )
+        rc = altp2m_init_helper(d, idx);
+
+    altp2m_unlock(d);
+
+    return rc;
+}
+
 int altp2m_init(struct domain *d)
 {
     spin_lock_init(&d->arch.altp2m_lock);
diff --git a/xen/arch/arm/hvm.c b/xen/arch/arm/hvm.c
index 43b8352cb7..ec8e259797 100644
--- a/xen/arch/arm/hvm.c
+++ b/xen/arch/arm/hvm.c
@@ -90,8 +90,36 @@ static int do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg)
         break;
 
     case HVMOP_altp2m_set_domain_state:
-        rc = -EOPNOTSUPP;
+    {
+        struct vcpu *v;
+        bool ostate, nstate;
+
+        ostate = d->arch.altp2m_active;
+        nstate = !!a.u.domain_state.state;
+
+        /* If the alternate p2m state has changed, handle appropriately */
+        if ( (nstate != ostate) &&
+             (ostate || !(rc = altp2m_init_by_id(d, 0))) )
+        {
+            d->arch.altp2m_active = nstate;
+
+            for_each_vcpu( d, v )
+            {
+                if ( !ostate )
+                    altp2m_vcpu_initialize(v);
+                else
+                    altp2m_vcpu_destroy(v);
+            }
+
+            /*
+             * The altp2m_active state has been deactivated. It is now safe to
+             * flush all altp2m views -- including altp2m[0].
+             */
+            if ( ostate )
+                altp2m_flush_complete(d);
+        }
         break;
+    }
 
     case HVMOP_altp2m_vcpu_enable_notify:
         rc = -EOPNOTSUPP;
diff --git a/xen/include/asm-arm/altp2m.h b/xen/include/asm-arm/altp2m.h
index e116cce25f..2ef88cec35 100644
--- a/xen/include/asm-arm/altp2m.h
+++ b/xen/include/asm-arm/altp2m.h
@@ -43,6 +43,16 @@ static inline uint16_t altp2m_vcpu_idx(const struct vcpu *v)
 int altp2m_init(struct domain *d);
 void altp2m_teardown(struct domain *d);
 
+void altp2m_vcpu_initialize(struct vcpu *v);
+void altp2m_vcpu_destroy(struct vcpu *v);
+
+/* Get current alternate p2m table. */
+struct p2m_domain *altp2m_get_altp2m(struct vcpu *v);
+
+/* Make a specific alternate p2m valid. */
+int altp2m_init_by_id(struct domain *d,
+                      unsigned int idx);
+
 /* Flush all the alternate p2m's for a domain. */
 void altp2m_flush_complete(struct domain *d);
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 668f398dbf..fc16cb81fd 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -293,6 +293,9 @@ struct arch_vcpu
     struct vtimer phys_timer;
     struct vtimer virt_timer;
     bool_t vtimer_initialized;
+
+    /* Alternate p2m index */
+    uint16_t ap2m_idx;
 }  __cacheline_aligned;
 
 void vcpu_show_execution_state(struct vcpu *);
-- 
2.13.3


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.