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

[Xen-changelog] [xen-unstable] Allow guests to register secondary vcpu_time_info



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1255949916 -3600
# Node ID ad2fd7b94bd32e4256640a908ca3c8b40f505021
# Parent  5f28661bb2bbfd903b79d52e2aeabc4e4cb1f4d8
Allow guests to register secondary vcpu_time_info

Allow a guest to register a second location for the VCPU time info
structure for each vcpu.  This is intended to allow the guest kernel
to map this information into a usermode accessible page, so that
usermode can efficiently calculate system time from the TSC without
having to make a syscall.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/domain.c        |   19 +++++++
 xen/arch/x86/time.c          |  107 ++++++++++++++++++++++++++++---------------
 xen/include/asm-x86/domain.h |    4 +
 xen/include/asm-x86/time.h   |    2 
 xen/include/public/vcpu.h    |   28 +++++++++++
 5 files changed, 125 insertions(+), 35 deletions(-)

diff -r 5f28661bb2bb -r ad2fd7b94bd3 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Mon Oct 19 10:57:58 2009 +0100
+++ b/xen/arch/x86/domain.c     Mon Oct 19 11:58:36 2009 +0100
@@ -962,6 +962,25 @@ arch_do_vcpu_op(
         break;
     }
 
+    case VCPUOP_register_vcpu_time_memory_area:
+    {
+        struct vcpu_register_time_memory_area area;
+
+        rc = -EFAULT;
+        if ( copy_from_guest(&area, arg, 1) )
+            break;
+
+        if ( !guest_handle_okay(area.addr.h, 1) )
+            break;
+
+        rc = 0;
+        v->arch.time_info_guest = area.addr.h;
+
+        force_update_vcpu_system_time(v);
+
+        break;
+    }
+
     case VCPUOP_get_physid:
     {
         struct vcpu_get_physid cpu_id;
diff -r 5f28661bb2bb -r ad2fd7b94bd3 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Mon Oct 19 10:57:58 2009 +0100
+++ b/xen/arch/x86/time.c       Mon Oct 19 11:58:36 2009 +0100
@@ -22,6 +22,7 @@
 #include <xen/irq.h>
 #include <xen/softirq.h>
 #include <xen/keyhandler.h>
+#include <xen/guest_access.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/mpspec.h>
@@ -807,23 +808,15 @@ s_time_t get_s_time(void)
     return now;
 }
 
-static inline void version_update_begin(u32 *version)
-{
-    /* Explicitly OR with 1 just in case version number gets out of sync. */
-    *version = (*version + 1) | 1;
-    wmb();
-}
-
-static inline void version_update_end(u32 *version)
-{
-    wmb();
-    (*version)++;
-}
-
-void update_vcpu_system_time(struct vcpu *v)
+/* Explicitly OR with 1 just in case version number gets out of sync. */
+#define version_update_begin(v) (((v)+1)|1)
+#define version_update_end(v)   ((v)+1)
+
+static void __update_vcpu_system_time(struct vcpu *v, int force)
 {
     struct cpu_time       *t;
-    struct vcpu_time_info *u;
+    struct vcpu_time_info *u, _u;
+    XEN_GUEST_HANDLE(vcpu_time_info_t) user_u;
 
     if ( v->vcpu_info == NULL )
         return;
@@ -831,35 +824,79 @@ void update_vcpu_system_time(struct vcpu
     t = &this_cpu(cpu_time);
     u = &vcpu_info(v, time);
 
+    /* Don't bother unless timestamps have changed or we are forced. */
+    if ( !force && (u->tsc_timestamp == (v->domain->arch.vtsc
+                                         ? t->stime_local_stamp
+                                         : t->local_tsc_stamp)) )
+        return;
+
+    memset(&_u, 0, sizeof(_u));
+
     if ( v->domain->arch.vtsc )
     {
-        if ( u->tsc_timestamp == t->stime_local_stamp )
-            return;
-        version_update_begin(&u->version);
-        u->tsc_timestamp     = t->stime_local_stamp;
-        u->system_time       = t->stime_local_stamp;
-        u->tsc_to_system_mul = 0x80000000u;
-        u->tsc_shift         = 1;
-        version_update_end(&u->version);
-    }
-    else if ( u->tsc_timestamp != t->local_tsc_stamp )
-    {
-        version_update_begin(&u->version);
-        u->tsc_timestamp     = t->local_tsc_stamp;
-        u->system_time       = t->stime_local_stamp;
-        u->tsc_to_system_mul = t->tsc_scale.mul_frac;
-        u->tsc_shift         = (s8)t->tsc_scale.shift;
-        version_update_end(&u->version);
-    }
+        _u.tsc_timestamp     = t->stime_local_stamp;
+        _u.system_time       = t->stime_local_stamp;
+        _u.tsc_to_system_mul = 0x80000000u;
+        _u.tsc_shift         = 1;
+    }
+    else
+    {
+        _u.tsc_timestamp     = t->local_tsc_stamp;
+        _u.system_time       = t->stime_local_stamp;
+        _u.tsc_to_system_mul = t->tsc_scale.mul_frac;
+        _u.tsc_shift         = (s8)t->tsc_scale.shift;
+    }
+
+    /* 1. Update guest kernel version. */
+    _u.version = u->version = version_update_begin(u->version);
+    wmb();
+    /* 2. Update all other guest kernel fields. */
+    *u = _u;
+    wmb();
+    /* 3. Update guest kernel version. */
+    u->version = version_update_end(u->version);
+
+    user_u = v->arch.time_info_guest;
+    if ( !guest_handle_is_null(user_u) )
+    {
+        /* 1. Update userspace version. */
+        __copy_field_to_guest(user_u, &_u, version);
+        wmb();
+        /* 2. Update all other userspavce fields. */
+        __copy_to_guest(user_u, &_u, 1);
+        wmb();
+        /* 3. Update userspace version. */
+        _u.version = version_update_end(_u.version);
+        __copy_field_to_guest(user_u, &_u, version);
+    }
+}
+
+void update_vcpu_system_time(struct vcpu *v)
+{
+    __update_vcpu_system_time(v, 0);
+}
+
+void force_update_vcpu_system_time(struct vcpu *v)
+{
+    __update_vcpu_system_time(v, 1);
 }
 
 void update_domain_wallclock_time(struct domain *d)
 {
+    uint32_t *wc_version;
+
     spin_lock(&wc_lock);
-    version_update_begin(&shared_info(d, wc_version));
+
+    wc_version = &shared_info(d, wc_version);
+    *wc_version = version_update_begin(*wc_version);
+    wmb();
+
     shared_info(d, wc_sec)  = wc_sec + d->time_offset_seconds;
     shared_info(d, wc_nsec) = wc_nsec;
-    version_update_end(&shared_info(d, wc_version));
+
+    wmb();
+    *wc_version = version_update_end(*wc_version);
+
     spin_unlock(&wc_lock);
 }
 
diff -r 5f28661bb2bb -r ad2fd7b94bd3 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Mon Oct 19 10:57:58 2009 +0100
+++ b/xen/include/asm-x86/domain.h      Mon Oct 19 11:58:36 2009 +0100
@@ -6,6 +6,7 @@
 #include <asm/hvm/vcpu.h>
 #include <asm/hvm/domain.h>
 #include <asm/e820.h>
+#include <public/vcpu.h>
 
 #define has_32bit_shinfo(d)    ((d)->arch.has_32bit_shinfo)
 #define is_pv_32bit_domain(d)  ((d)->arch.is_32bit_pv)
@@ -418,6 +419,9 @@ struct arch_vcpu
     uint32_t gdbsx_vcpu_event;
 #endif 
 
+    /* A secondary copy of the vcpu time info. */
+    XEN_GUEST_HANDLE(vcpu_time_info_t) time_info_guest;
+
 } __cacheline_aligned;
 
 /* Shorthands to improve code legibility. */
diff -r 5f28661bb2bb -r ad2fd7b94bd3 xen/include/asm-x86/time.h
--- a/xen/include/asm-x86/time.h        Mon Oct 19 10:57:58 2009 +0100
+++ b/xen/include/asm-x86/time.h        Mon Oct 19 11:58:36 2009 +0100
@@ -43,4 +43,6 @@ uint64_t ns_to_acpi_pm_tick(uint64_t ns)
 
 void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs);
 
+void force_update_vcpu_system_time(struct vcpu *v);
+
 #endif /* __X86_TIME_H__ */
diff -r 5f28661bb2bb -r ad2fd7b94bd3 xen/include/public/vcpu.h
--- a/xen/include/public/vcpu.h Mon Oct 19 10:57:58 2009 +0100
+++ b/xen/include/public/vcpu.h Mon Oct 19 11:58:36 2009 +0100
@@ -202,6 +202,34 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_get_physid_
 #define xen_vcpu_physid_to_x86_acpiid(physid) \
     ((((uint32_t)((physid)>>32)) >= 0xff) ? 0xff : ((uint8_t)((physid)>>32)))
 
+/* 
+ * Register a memory location to get a secondary copy of the vcpu time
+ * parameters.  The master copy still exists as part of the vcpu shared
+ * memory area, and this secondary copy is updated whenever the master copy
+ * is updated (and using the same versioning scheme for synchronisation).
+ *
+ * The intent is that this copy may be mapped (RO) into userspace so
+ * that usermode can compute system time using the time info and the
+ * tsc.  Usermode will see an array of vcpu_time_info structures, one
+ * for each vcpu, and choose the right one by an existing mechanism
+ * which allows it to get the current vcpu number (such as via a
+ * segment limit).  It can then apply the normal algorithm to compute
+ * system time from the tsc.
+ *
+ * @extra_arg == pointer to vcpu_register_time_info_memory_area structure.
+ */
+#define VCPUOP_register_vcpu_time_memory_area   13
+DEFINE_XEN_GUEST_HANDLE(vcpu_time_info_t);
+struct vcpu_register_time_memory_area {
+    union {
+        XEN_GUEST_HANDLE(vcpu_time_info_t) h;
+        struct vcpu_time_info *v;
+        uint64_t p;
+    } addr;
+};
+typedef struct vcpu_register_time_memory_area vcpu_register_time_memory_area_t;
+DEFINE_XEN_GUEST_HANDLE(vcpu_register_time_memory_area_t);
+
 #endif /* __XEN_PUBLIC_VCPU_H__ */
 
 /*

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


 


Rackspace

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