From 0cb1fcb0855118a04612b957c3685c4f8b31219a Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 2 Oct 2016 17:28:11 +0100 Subject: [PATCH] x86/hvm: Move hvm_funcs.cpuid_intercept() handling into hvm_cpuid() This reduces the net complexity of CPUID handling by having all adjustments in the same place. Remove the now-unused hvm_funcs.cpuid_intercept infrastructure. The SYSCALL feature hiding is tweaked when moved. In principle, an administrator can choose to explicitly hide the SYSCALL feature from the guest, as it has a separate feature bit. If this is the case, the feature shouldn't be set behind the back of the administrators wishes. (Not that many 64bit OSes would function in this scenario.) In reality, SYSCALL will always be set in edx at this point. Signed-off-by: Andrew Cooper Reviewed-by: Boris Ostrovsky Acked-by: Kevin Tian Reviewed-by: Jan Beulich --- xen/arch/x86/hvm/emulate.c | 2 +- xen/arch/x86/hvm/hvm.c | 27 ++++++++++++++++++------ xen/arch/x86/hvm/svm/svm.c | 39 ++--------------------------------- xen/arch/x86/hvm/vmx/vmx.c | 31 ++-------------------------- xen/include/asm-x86/hvm/hvm.h | 3 --- 5 files changed, 26 insertions(+), 76 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index ed5ff91ce0..816739f35e 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1566,7 +1566,7 @@ int hvmemul_cpuid( hvm_check_cpuid_faulting(current) ) return X86EMUL_EXCEPTION; - hvm_funcs.cpuid_intercept(eax, ebx, ecx, edx); + hvm_cpuid(*eax, eax, ebx, ecx, edx); return X86EMUL_OKAY; } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 4bb4193915..f75e45d940 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -906,12 +906,7 @@ const char *hvm_efer_valid(const struct vcpu *v, uint64_t value, ASSERT(v->domain == current->domain); hvm_cpuid(0x80000000, &level, NULL, NULL, NULL); if ( (level >> 16) == 0x8000 && level > 0x80000000 ) - { - unsigned int dummy; - - level = 0x80000001; - hvm_funcs.cpuid_intercept(&level, &dummy, &ext1_ecx, &ext1_edx); - } + hvm_cpuid(0x80000001, NULL, NULL, &ext1_ecx, &ext1_edx); } else { @@ -3618,6 +3613,12 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, if ( !(hvm_pae_enabled(v) || hvm_long_mode_enabled(v)) ) *edx &= ~cpufeat_mask(X86_FEATURE_PSE36); } + + /* SYSCALL is hidden outside of long mode on Intel. */ + if ( d->arch.x86_vendor == X86_VENDOR_INTEL && + !hvm_long_mode_enabled(v)) + *edx &= ~cpufeat_mask(X86_FEATURE_SYSCALL); + break; case 0x80000007: @@ -3642,6 +3643,20 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, *ebx &= hvm_featureset[FEATURESET_e8b]; break; + + case 0x8000001c: + if ( !cpu_has_svm ) + { + *eax = *ebx = *ecx = *edx = 0; + break; + } + + if ( cpu_has_lwp && (v->arch.xcr0 & XSTATE_LWP) ) + /* Turn on available bit and other features specified in lwp_cfg. */ + *eax = (*edx & v->arch.hvm_svm.guest_lwp_cfg) | 1; + else + *eax = 0; + break; } } diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index c7d02bc894..bb8273b30b 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1565,41 +1565,6 @@ static void svm_fpu_dirty_intercept(void) vmcb_set_cr0(vmcb, vmcb_get_cr0(vmcb) & ~X86_CR0_TS); } -static void svm_cpuid_intercept( - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - unsigned int input = *eax; - struct vcpu *v = current; - - hvm_cpuid(input, eax, ebx, ecx, edx); - - switch (input) { - case 0x8000001c: - { - /* LWP capability CPUID */ - uint64_t lwp_cfg = v->arch.hvm_svm.guest_lwp_cfg; - - if ( cpu_has_lwp ) - { - if ( !(v->arch.xcr0 & XSTATE_LWP) ) - { - *eax = 0x0; - break; - } - - /* turn on available bit and other features specified in lwp_cfg */ - *eax = (*edx & lwp_cfg) | 0x00000001; - } - break; - } - default: - break; - } - - HVMTRACE_5D (CPUID, input, *eax, *ebx, *ecx, *edx); -} - static void svm_vmexit_do_cpuid(struct cpu_user_regs *regs) { unsigned int eax, ebx, ecx, edx, inst_len; @@ -1612,7 +1577,8 @@ static void svm_vmexit_do_cpuid(struct cpu_user_regs *regs) ecx = regs->ecx; edx = regs->edx; - svm_cpuid_intercept(&eax, &ebx, &ecx, &edx); + hvm_cpuid(regs->_eax, &eax, &ebx, &ecx, &edx); + HVMTRACE_5D(CPUID, regs->_eax, eax, ebx, ecx, edx); regs->eax = eax; regs->ebx = ebx; @@ -2244,7 +2210,6 @@ static struct hvm_function_table __initdata svm_function_table = { .init_hypercall_page = svm_init_hypercall_page, .event_pending = svm_event_pending, .invlpg = svm_invlpg, - .cpuid_intercept = svm_cpuid_intercept, .wbinvd_intercept = svm_wbinvd_intercept, .fpu_dirty_intercept = svm_fpu_dirty_intercept, .msr_read_intercept = svm_msr_read_intercept, diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 505cdea587..499b300d2e 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -73,9 +73,6 @@ static void vmx_install_vlapic_mapping(struct vcpu *v); static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr); static void vmx_update_guest_efer(struct vcpu *v); static void vmx_update_guest_vendor(struct vcpu *v); -static void vmx_cpuid_intercept( - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx); static void vmx_wbinvd_intercept(void); static void vmx_fpu_dirty_intercept(void); static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content); @@ -2105,7 +2102,6 @@ static struct hvm_function_table __initdata vmx_function_table = { .invlpg = vmx_invlpg, .cpu_up = vmx_cpu_up, .cpu_down = vmx_cpu_down, - .cpuid_intercept = vmx_cpuid_intercept, .wbinvd_intercept = vmx_wbinvd_intercept, .fpu_dirty_intercept = vmx_fpu_dirty_intercept, .msr_read_intercept = vmx_msr_read_intercept, @@ -2341,30 +2337,6 @@ static void vmx_fpu_dirty_intercept(void) } } -static void vmx_cpuid_intercept( - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) -{ - unsigned int input = *eax; - struct vcpu *v = current; - - hvm_cpuid(input, eax, ebx, ecx, edx); - - switch ( input ) - { - case 0x80000001: - /* SYSCALL is visible iff running in long mode. */ - if ( hvm_long_mode_enabled(v) ) - *edx |= cpufeat_mask(X86_FEATURE_SYSCALL); - else - *edx &= ~(cpufeat_mask(X86_FEATURE_SYSCALL)); - - break; - } - - HVMTRACE_5D (CPUID, input, *eax, *ebx, *ecx, *edx); -} - static int vmx_do_cpuid(struct cpu_user_regs *regs) { unsigned int eax, ebx, ecx, edx; @@ -2384,7 +2356,8 @@ static int vmx_do_cpuid(struct cpu_user_regs *regs) leaf = regs->eax; subleaf = regs->ecx; - vmx_cpuid_intercept(&eax, &ebx, &ecx, &edx); + hvm_cpuid(leaf, &eax, &ebx, &ecx, &edx); + HVMTRACE_5D(CPUID, leaf, eax, ebx, ecx, edx); regs->eax = eax; regs->ebx = ebx; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index b37b335a86..1abe743293 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -161,9 +161,6 @@ struct hvm_function_table { unsigned int (*get_insn_bytes)(struct vcpu *v, uint8_t *buf); /* Instruction intercepts: non-void return values are X86EMUL codes. */ - void (*cpuid_intercept)( - unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx); void (*wbinvd_intercept)(void); void (*fpu_dirty_intercept)(void); int (*msr_read_intercept)(unsigned int msr, uint64_t *msr_content); -- 2.39.5