diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3110,6 +3110,37 @@ break; } + case HVMOP_enable_pv: { + struct xen_hvm_pv_type a; + struct domain *d; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + rc = rcu_lock_target_domain_by_id(DOMID_SELF, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto param_fail5; + + rc = xsm_hvm_param(d, op); + if ( rc ) + goto param_fail5; + + /* This would be called by BSP, other vcpus are adjusted during the + * start-up */ + if (a.flags & HVM_PV_CLOCK) { + d->hvm_pv_enabled |= XEN_HVM_PV_CLOCK_ENABLED; + update_domain_wallclock_time(d); + hvm_funcs.set_tsc_offset(current, 0); + } +param_fail5: + rcu_unlock_domain(d); + break; + } + default: { gdprintk(XENLOG_WARNING, "Bad HVM op %ld.\n", op); diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -289,6 +289,10 @@ return X86EMUL_RETRY; hvm_vcpu_reset_state(v, trampoline_vector << 8, 0); + + /* Adjust TSC for PV clock */ + if (is_hvm_pv_clock_enabled_domain(v->domain)) + hvm_funcs.set_tsc_offset(v, 0); vcpu_unpause(v); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -686,6 +686,7 @@ struct domain *d = current->domain; /* Optionally shift out of the way of Viridian architectural leaves. */ uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; + unsigned int tmp_eax, tmp_ebx, tmp_ecx, tmp_edx; idx -= base; if ( idx > 3 ) @@ -716,6 +717,14 @@ *edx = 0; /* Features 2 */ if ( !is_hvm_vcpu(current) ) *ecx |= XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD; + + /* Check if additional feature specified, e.g. Hybrid */ + if ( !is_viridian_domain(d) ) { + domain_cpuid(d, 0x40000002, 0, + &tmp_eax, &tmp_ebx, &tmp_ecx, &tmp_edx); + if (tmp_edx != 0) + *edx = tmp_edx & XEN_CPUID_FEAT2_MASK; + } break; case 3: diff --git a/xen/include/public/arch-x86/cpuid.h b/xen/include/public/arch-x86/cpuid.h --- a/xen/include/public/arch-x86/cpuid.h +++ b/xen/include/public/arch-x86/cpuid.h @@ -65,4 +65,11 @@ #define _XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD 0 #define XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD (1u<<0) +/* Mask unsupported CPUID specified by user */ +#define XEN_CPUID_FEAT2_MASK 0x3ul +#define _XEN_CPUID_FEAT2_HVM_PV 0 +#define XEN_CPUID_FEAT2_HVM_PV (1u<<0) +#define _XEN_CPUID_FEAT2_HVM_PV_CLOCK 1 +#define XEN_CPUID_FEAT2_HVM_PV_CLOCK (1u<<1) + #endif /* __XEN_PUBLIC_ARCH_X86_CPUID_H__ */ diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -127,6 +127,13 @@ typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_type_t); +/* Enable PV extended HVM features. Should called by BSP */ +#define HVMOP_enable_pv 9 +struct xen_hvm_pv_type { + /* The features want to enable */ + uint32_t flags; +#define HVM_PV_CLOCK (1ull<<0) +}; #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -311,6 +311,9 @@ /* Memory paging support */ struct mem_event_domain mem_event; + +#define XEN_HVM_PV_CLOCK_ENABLED (1u << 0) + uint64_t hvm_pv_enabled; }; struct domain_setup_info @@ -597,6 +600,9 @@ #define is_hvm_vcpu(v) (is_hvm_domain(v->domain)) #define need_iommu(d) ((d)->need_iommu) +#define is_hvm_pv_clock_enabled_domain(d) \ + ((d)->hvm_pv_enabled & XEN_HVM_PV_CLOCK_ENABLED) + void set_vcpu_migration_delay(unsigned int delay); unsigned int get_vcpu_migration_delay(void);