diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index c8ce6c1880..0ca37bc758 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -881,9 +881,13 @@ Possible values for a single feature bit: 'k' -> pass through the host bit value 's' -> as 'k' but preserve across save/restore and migration (not implemented) +Note: when specifying B for hypervisor leaves (0x4000xxxx major group) +only the lowest 8 bits of leaf's 0x4000xx00 EAX register are processed, the rest +are ignored (these 8 bits signify maximum number of hypervisor leaves). + List of keys taking a value: -apicidsize brandid clflush family localapicid maxleaf model nc proccount procpkg -stepping +apicidsize brandid clflush family localapicid maxleaf maxhvleaf model nc +proccount procpkg stepping List of keys taking a character: 3dnow 3dnowext 3dnowprefetch abm acpi aes altmovcr8 apic avx clfsh cmov diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index 71917e30c9..6a02bf011d 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -561,6 +561,17 @@ static int xc_cpuid_policy( { xc_dominfo_t info; + /* + * For hypervisor leaves (0x4000XXXX) only 0x4000xx00.EAX[7:0] bits (max + * number of leaves) can be set by user. Hypervisor will enforce this so + * all other bits are don't-care and we can set them to zero. + */ + if ( (input[0] & 0xffff0000) == 0x40000000 ) + { + regs[0] = regs[1] = regs[2] = regs[3] = 0; + return 0; + } + if ( xc_domain_getinfo(xch, domid, 1, &info) == 0 ) return -EINVAL; diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c index dd21b78864..d1ea50d1ef 100644 --- a/tools/libxl/libxl_cpuid.c +++ b/tools/libxl/libxl_cpuid.c @@ -187,6 +187,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str) {"svm_vmcbclean",0x8000000a, NA, CPUID_REG_EDX, 5, 1}, {"svm_decode", 0x8000000a, NA, CPUID_REG_EDX, 7, 1}, {"svm_pausefilt",0x8000000a, NA, CPUID_REG_EDX, 10, 1}, + {"maxhvleaf", 0x40000000, NA, CPUID_REG_EAX, 0, 8}, {NULL, 0, NA, CPUID_REG_INV, 0, 0} }; diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 45070bb974..d6114f86e4 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -677,15 +677,19 @@ int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, struct domain *d = current->domain; /* Optionally shift out of the way of Viridian architectural leaves. */ uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; - uint32_t limit; + uint32_t limit, dummy; idx -= base; + if ( idx > XEN_CPUID_MAX_NUM_LEAVES ) + return 0; /* Avoid unnecessary pass through domain_cpuid() */ - /* - * Some Solaris PV drivers fail if max > base + 2. Help them out by - * hiding the PVRDTSCP leaf if PVRDTSCP is disabled. - */ - limit = (d->arch.tsc_mode < TSC_MODE_PVRDTSCP) ? 2 : 3; + /* Number of leaves may be user-specified */ + domain_cpuid(d, base, 0, &limit, &dummy, &dummy, &dummy); + limit &= 0xff; + if ( limit < 2 ) + limit = 2; + else if ( limit > XEN_CPUID_MAX_NUM_LEAVES ) + limit = XEN_CPUID_MAX_NUM_LEAVES; if ( idx > limit ) return 0; diff --git a/xen/include/public/arch-x86/cpuid.h b/xen/include/public/arch-x86/cpuid.h index d9bd62714f..19fc9ddf70 100644 --- a/xen/include/public/arch-x86/cpuid.h +++ b/xen/include/public/arch-x86/cpuid.h @@ -65,4 +65,6 @@ #define _XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD 0 #define XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD (1u<<0) +#define XEN_CPUID_MAX_NUM_LEAVES 3 + #endif /* __XEN_PUBLIC_ARCH_X86_CPUID_H__ */