x86: correct CPUID output for out of bounds input Another place where we should try to behave sufficiently close to how real hardware does; see the code comments. Signed-off-by: Jan Beulich --- v2: Uniformly return zero for out of range leaves. Only consider basic and extended groups as valid. Avoid recursion in hvm_cpuid(). --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3364,6 +3364,27 @@ void hvm_cpuid(unsigned int input, unsig if ( cpuid_hypervisor_leaves(input, count, eax, ebx, ecx, edx) ) return; + if ( input & 0x7fffffff ) + { + /* + * Requests outside the supported leaf ranges return zero on AMD + * and the highest basic leaf output on Intel. Uniformly follow + * the AMD model as the more sane one. + */ + unsigned int limit; + + domain_cpuid(d, (input >> 16) != 0x8000 ? 0 : 0x80000000, 0, + &limit, &dummy, &dummy, &dummy); + if ( input > limit ) + { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + return; + } + } + domain_cpuid(d, input, count, eax, ebx, ecx, edx); switch ( input ) --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -952,6 +952,29 @@ void pv_cpuid(struct cpu_user_regs *regs if ( cpuid_hypervisor_leaves(leaf, subleaf, &a, &b, &c, &d) ) goto out; + if ( leaf & 0x7fffffff ) + { + /* + * Requests outside the supported leaf ranges return zero on AMD + * and the highest basic leaf output on Intel. Uniformly follow + * the AMD model as the more sane one. + */ + unsigned int limit = (leaf >> 16) != 0x8000 ? 0 : 0x80000000, dummy; + + if ( !is_control_domain(currd) && !is_hardware_domain(currd) ) + domain_cpuid(currd, limit, 0, &limit, &dummy, &dummy, &dummy); + else + limit = cpuid_eax(limit); + if ( leaf > limit ) + { + regs->eax = 0; + regs->ebx = 0; + regs->ecx = 0; + regs->edx = 0; + return; + } + } + if ( !is_control_domain(currd) && !is_hardware_domain(currd) ) domain_cpuid(currd, leaf, subleaf, &a, &b, &c, &d); else