WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Implement VCPUOP_register_vcpu_info

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Implement VCPUOP_register_vcpu_info
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 04 Jun 2007 03:15:26 -0700
Delivery-date: Mon, 04 Jun 2007 03:15:52 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
# Date 1180000047 -3600
# Node ID 020530a6ff5c24c3a8289f8f687ce2f10aff5ca7
# Parent  471478a1b89e2681c3b1efa3abde6ec47eb36d05
Implement VCPUOP_register_vcpu_info

This change implements the VCPUOP_register_vcpu_info vcpu_op.  This
allows a guest to choose where each VCPU's vcpu_info structure is
placed within its address space, allowing it to put it somewhere which
is easily accessible via some per-cpu data access mechanism.

When changing the mapping of the vcpu info, there's no obvious way to
prevent the other vcpus from getting a stale pointer of the vcpu_info,
which could result in them accessing bad memory (stale pointers to the
shared_info page are not a problem, because its always valid).  To
avoid this, we prevent guests from changing the vcpu_info location
more than once, since there's no obvious need to allow them to do this
at this point.

(If we really want to allow guests to update the vcpu_info location
more than once, then some sort of RCU wait between updating the
pointer and performing the unmap may be the way to do it.)

Signed-off-by: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
---
 xen/arch/x86/domain.c     |  102 ++++++++++++++++++++++++++++++++++++++++++++++
 xen/common/domain.c       |    1 
 xen/include/public/vcpu.h |    3 -
 xen/include/xen/sched.h   |    1 
 4 files changed, 105 insertions(+), 2 deletions(-)

diff -r 471478a1b89e -r 020530a6ff5c xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Thu May 24 10:45:03 2007 +0100
+++ b/xen/arch/x86/domain.c     Thu May 24 10:47:27 2007 +0100
@@ -28,6 +28,7 @@
 #include <xen/event.h>
 #include <xen/console.h>
 #include <xen/percpu.h>
+#include <xen/compat.h>
 #include <asm/regs.h>
 #include <asm/mc146818rtc.h>
 #include <asm/system.h>
@@ -49,6 +50,8 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu)
 DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
 DEFINE_PER_CPU(__u64, efer);
 
+static void unmap_vcpu_info(struct vcpu *v);
+
 static void paravirt_ctxt_switch_from(struct vcpu *v);
 static void paravirt_ctxt_switch_to(struct vcpu *v);
 
@@ -728,11 +731,94 @@ int arch_set_info_guest(
 
 int arch_vcpu_reset(struct vcpu *v)
 {
+    unmap_vcpu_info(v);
     destroy_gdt(v);
     vcpu_destroy_pagetables(v);
     return 0;
 }
 
+/* 
+ * Unmap the vcpu info page if the guest decided to place it somewhere
+ * else.  This is only used from arch_vcpu_reset, so there's no need
+ * to do anything clever.
+ */
+static void
+unmap_vcpu_info(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    unsigned long mfn;
+
+    if ( v->vcpu_info_mfn == INVALID_MFN )
+        return;
+
+    mfn = v->vcpu_info_mfn;
+    unmap_domain_page_global( v->vcpu_info );
+
+    v->vcpu_info = shared_info_addr(d, vcpu_info[v->vcpu_id]);
+    v->vcpu_info_mfn = INVALID_MFN;
+
+    put_page_and_type(mfn_to_page(mfn));
+}
+
+/* 
+ * Map a guest page in and point the vcpu_info pointer at it.  This
+ * makes sure that the vcpu_info is always pointing at a valid piece
+ * of memory, and it sets a pending event to make sure that a pending
+ * event doesn't get missed.
+ */
+static int
+map_vcpu_info(struct vcpu *v, unsigned long mfn, unsigned offset)
+{
+    struct domain *d = v->domain;
+    void *mapping;
+    vcpu_info_t *new_info;
+    int i;
+
+    if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
+        return -EINVAL;
+
+    if ( mfn == INVALID_MFN ||
+         v->vcpu_info_mfn != INVALID_MFN )
+        return -EINVAL;
+
+    mfn = gmfn_to_mfn(d, mfn);
+    if ( !mfn_valid(mfn) ||
+         !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
+        return -EINVAL;
+
+    mapping = map_domain_page_global(mfn);
+    if ( mapping == NULL )
+    {
+        put_page_and_type(mfn_to_page(mfn));
+        return -ENOMEM;
+    }
+
+    new_info = (vcpu_info_t *)(mapping + offset);
+
+    memcpy(new_info, v->vcpu_info, sizeof(*new_info));
+
+    v->vcpu_info = new_info;
+    v->vcpu_info_mfn = mfn;
+
+    /* make sure all the pointers are uptodate before setting pending */
+    wmb();
+
+    /* Mark everything as being pending just to make sure nothing gets
+       lost.  The domain will get a spurious event, but it can
+       cope. */
+    vcpu_info(v, evtchn_upcall_pending) = 1;
+    for ( i = 0; i < BITS_PER_GUEST_LONG(d); i++ )
+        set_bit(i, vcpu_info_addr(v, evtchn_pending_sel));
+
+    /* Only bother to update time for the current vcpu.  If we're
+     * operating on another vcpu, then it had better not be running at
+     * the time. */
+    if ( v == current )
+         update_vcpu_system_time(v);
+
+    return 0;
+}
+
 long
 arch_do_vcpu_op(
     int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg)
@@ -765,6 +851,22 @@ arch_do_vcpu_op(
             vcpu_runstate_get(v, &runstate);
             __copy_to_guest(runstate_guest(v), &runstate, 1);
         }
+
+        break;
+    }
+
+    case VCPUOP_register_vcpu_info:
+    {
+        struct domain *d = v->domain;
+        struct vcpu_register_vcpu_info info;
+
+        rc = -EFAULT;
+        if ( copy_from_guest(&info, arg, 1) )
+            break;
+
+        LOCK_BIGLOCK(d);
+        rc = map_vcpu_info(v, info.mfn, info.offset);
+        UNLOCK_BIGLOCK(d);
 
         break;
     }
diff -r 471478a1b89e -r 020530a6ff5c xen/common/domain.c
--- a/xen/common/domain.c       Thu May 24 10:45:03 2007 +0100
+++ b/xen/common/domain.c       Thu May 24 10:47:27 2007 +0100
@@ -136,6 +136,7 @@ struct vcpu *alloc_vcpu(
 
     v->domain = d;
     v->vcpu_id = vcpu_id;
+    v->vcpu_info_mfn = INVALID_MFN;
 
     v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
     v->runstate.state_entry_time = NOW();
diff -r 471478a1b89e -r 020530a6ff5c xen/include/public/vcpu.h
--- a/xen/include/public/vcpu.h Thu May 24 10:45:03 2007 +0100
+++ b/xen/include/public/vcpu.h Thu May 24 10:47:27 2007 +0100
@@ -168,8 +168,7 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_set_singles
  * The pointer need not be page aligned, but the structure must not
  * cross a page boundary.
  *
- * If the specified mfn is INVALID_MFN, then it reverts to using the
- * vcpu_info structure in the shared_info page.
+ * This may be called only once per vcpu.
  */
 #define VCPUOP_register_vcpu_info   10  /* arg == struct vcpu_info */
 struct vcpu_register_vcpu_info {
diff -r 471478a1b89e -r 020530a6ff5c xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Thu May 24 10:45:03 2007 +0100
+++ b/xen/include/xen/sched.h   Thu May 24 10:47:27 2007 +0100
@@ -75,6 +75,7 @@ struct vcpu
     int              processor;
 
     vcpu_info_t     *vcpu_info;
+    unsigned long    vcpu_info_mfn;
 
     struct domain   *domain;
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>