diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 9d352defa2..8e0af22781 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1529,6 +1529,15 @@ int arch_vcpu_reset(struct vcpu *v) return 0; } +static void cf_check +time_area_populate(void *map, struct vcpu *v) +{ + if ( is_pv_vcpu(v) ) + v->arch.pv.pending_system_time.version = 0; + + force_update_secondary_system_time(v, map); +} + long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) { long rc = 0; @@ -1567,6 +1576,25 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) break; } + case VCPUOP_register_vcpu_time_phys_area: + { + struct vcpu_register_time_memory_area area; + + rc = -EFAULT; + if ( copy_from_guest(&area.addr.p, arg, 1) ) + break; + + rc = map_guest_area(v, area.addr.p, + sizeof(vcpu_time_info_t), + &v->arch.time_guest_area, + time_area_populate); + if ( rc == -ERESTART ) + rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iih", + cmd, vcpuid, arg); + + break; + } + case VCPUOP_get_physid: { struct vcpu_get_physid cpu_id; diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h index e0bd28e424..619e667938 100644 --- a/xen/arch/x86/include/asm/domain.h +++ b/xen/arch/x86/include/asm/domain.h @@ -692,6 +692,8 @@ void domain_cpu_policy_changed(struct domain *d); bool update_secondary_system_time(struct vcpu *, struct vcpu_time_info *); +void force_update_secondary_system_time(struct vcpu *, + struct vcpu_time_info *); void vcpu_show_registers(const struct vcpu *); diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 332d2d79ae..73df1639a3 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -1628,6 +1628,16 @@ void force_update_vcpu_system_time(struct vcpu *v) __update_vcpu_system_time(v, 1); } +void force_update_secondary_system_time(struct vcpu *v, + struct vcpu_time_info *map) +{ + struct vcpu_time_info u; + + collect_time_info(v, &u); + u.version = -1; /* Compensate for version_update_end(). */ + write_time_guest_area(map, &u); +} + static void update_domain_rtc(void) { struct domain *d; diff --git a/xen/arch/x86/x86_64/domain.c b/xen/arch/x86/x86_64/domain.c index 494b0b54e6..a02d4f569e 100644 --- a/xen/arch/x86/x86_64/domain.c +++ b/xen/arch/x86/x86_64/domain.c @@ -115,6 +115,7 @@ compat_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) case VCPUOP_send_nmi: case VCPUOP_get_physid: + case VCPUOP_register_vcpu_time_phys_area: rc = do_vcpu_op(cmd, vcpuid, arg); break; diff --git a/xen/include/public/vcpu.h b/xen/include/public/vcpu.h index 9dac0f9748..8fb0bd1b6c 100644 --- a/xen/include/public/vcpu.h +++ b/xen/include/public/vcpu.h @@ -209,6 +209,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_get_physid_t); * segment limit). It can then apply the normal algorithm to compute * system time from the tsc. * + * New code wants to prefer VCPUOP_register_vcpu_time_phys_area, and only + * fall back to the operation here for backwards compatibility. + * * @extra_arg == pointer to vcpu_register_time_info_memory_area structure. */ #define VCPUOP_register_vcpu_time_memory_area 13 @@ -235,6 +238,7 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_register_time_memory_area_t); * VMASST_TYPE_runstate_update_flag engaged by the domain. */ #define VCPUOP_register_runstate_phys_area 14 +#define VCPUOP_register_vcpu_time_phys_area 15 #endif /* __XEN_PUBLIC_VCPU_H__ */