Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.1:kernel-2.6.32
xen
20339-register-vcpu-time-info.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 20339-register-vcpu-time-info.patch of Package xen
# HG changeset patch # User Keir Fraser <keir.fraser@citrix.com> # 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@citrix.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com> --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -860,6 +860,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; --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -21,6 +21,7 @@ #include <xen/smp.h> #include <xen/irq.h> #include <xen/softirq.h> +#include <xen/guest_access.h> #include <asm/io.h> #include <asm/msr.h> #include <asm/mpspec.h> @@ -787,23 +788,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)++; -} +/* 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) -void update_vcpu_system_time(struct vcpu *v) +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; @@ -811,26 +804,66 @@ void update_vcpu_system_time(struct vcpu t = &this_cpu(cpu_time); u = &vcpu_info(v, time); - if ( u->tsc_timestamp == t->local_tsc_stamp ) + if ( !force && u->tsc_timestamp == t->local_tsc_stamp ) return; - version_update_begin(&u->version); + memset(&_u, 0, sizeof(_u)); + + _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; - 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); - 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 userspace 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); } --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -7,6 +7,7 @@ #include <asm/hvm/domain.h> #include <asm/e820.h> #include <asm/pirq.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) @@ -364,6 +365,9 @@ struct arch_vcpu struct mapcache_vcpu mapcache; #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. */ --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -38,4 +38,6 @@ void pit_broadcast_enter(void); void pit_broadcast_exit(void); int pit_broadcast_is_available(void); +void force_update_vcpu_system_time(struct vcpu *v); + #endif /* __X86_TIME_H__ */ --- a/xen/include/public/vcpu.h +++ b/xen/include/public/vcpu.h @@ -200,6 +200,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__ */ /*
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor