| From ae580956fc0ed8feb794b6392df59ff5de673565 Mon Sep 17 00:00:00 2001 |
| From: David Edmondson <david.edmondson@oracle.com> |
| Date: Mon, 5 Jul 2021 11:46:31 +0100 |
| Subject: [PATCH 7/7] target/i386: Populate x86_ext_save_areas offsets using |
| cpuid where possible |
| |
| RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com> |
| RH-MergeRequest: 113: non-av 8.5z: Fix XSAVE on newer CPUs |
| RH-Commit: [7/7] 145fc1dd5232673e2070423a027cad38fa4c4890 |
| RH-Bugzilla: 2065239 |
| RH-Acked-by: Jon Maloy <jmaloy@redhat.com> |
| RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com> |
| RH-Acked-by: Bandan Das <None> |
| |
| Rather than relying on the X86XSaveArea structure definition, |
| determine the offset of XSAVE state areas using CPUID leaf 0xd where |
| possible (KVM and HVF). |
| |
| Signed-off-by: David Edmondson <david.edmondson@oracle.com> |
| Message-Id: <20210705104632.2902400-8-david.edmondson@oracle.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| (cherry picked from commit fea4500841024195ec701713e05b92ebf667f192) |
| dgilbert: Hairy backport, since we've not got Claudio's cpu |
| accelerator split |
| |
| target/i386/cpu.c | 65 +++++++++++++++++++++++++++++++++++-------- |
| target/i386/cpu.h | 2 +- |
| target/i386/hvf/hvf.c | 17 ++++------- |
| target/i386/kvm.c | 7 +++++ |
| 4 files changed, 66 insertions(+), 25 deletions(-) |
| |
| diff --git a/target/i386/cpu.c b/target/i386/cpu.c |
| index a030030299..c52eae1f0d 100644 |
| |
| |
| @@ -1504,48 +1504,37 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { |
| }; |
| #undef REGISTER |
| |
| -const ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { |
| +ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { |
| [XSTATE_FP_BIT] = { |
| /* x87 FP state component is always enabled if XSAVE is supported */ |
| .feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, |
| - /* x87 state is in the legacy region of the XSAVE area */ |
| - .offset = 0, |
| .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader), |
| }, |
| [XSTATE_SSE_BIT] = { |
| /* SSE state component is always enabled if XSAVE is supported */ |
| .feature = FEAT_1_ECX, .bits = CPUID_EXT_XSAVE, |
| - /* SSE state is in the legacy region of the XSAVE area */ |
| - .offset = 0, |
| .size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader), |
| }, |
| [XSTATE_YMM_BIT] = |
| { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, |
| - .offset = offsetof(X86XSaveArea, avx_state), |
| .size = sizeof(XSaveAVX) }, |
| [XSTATE_BNDREGS_BIT] = |
| { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, |
| - .offset = offsetof(X86XSaveArea, bndreg_state), |
| .size = sizeof(XSaveBNDREG) }, |
| [XSTATE_BNDCSR_BIT] = |
| { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX, |
| - .offset = offsetof(X86XSaveArea, bndcsr_state), |
| .size = sizeof(XSaveBNDCSR) }, |
| [XSTATE_OPMASK_BIT] = |
| { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, |
| - .offset = offsetof(X86XSaveArea, opmask_state), |
| .size = sizeof(XSaveOpmask) }, |
| [XSTATE_ZMM_Hi256_BIT] = |
| { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, |
| - .offset = offsetof(X86XSaveArea, zmm_hi256_state), |
| .size = sizeof(XSaveZMM_Hi256) }, |
| [XSTATE_Hi16_ZMM_BIT] = |
| { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F, |
| - .offset = offsetof(X86XSaveArea, hi16_zmm_state), |
| .size = sizeof(XSaveHi16_ZMM) }, |
| [XSTATE_PKRU_BIT] = |
| { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, |
| - .offset = offsetof(X86XSaveArea, pkru_state), |
| .size = sizeof(XSavePKRU) }, |
| }; |
| |
| @@ -5237,6 +5226,52 @@ static void x86_cpu_apply_version_props(X86CPU *cpu, X86CPUModel *model) |
| assert(vdef->version == version); |
| } |
| |
| +static void kvm_cpu_xsave_init(void) |
| +{ |
| + static bool first = true; |
| + KVMState *s = kvm_state; |
| + int i; |
| + |
| + if (!first) { |
| + return; |
| + } |
| + first = false; |
| + |
| + /* x87 and SSE states are in the legacy region of the XSAVE area. */ |
| + x86_ext_save_areas[XSTATE_FP_BIT].offset = 0; |
| + x86_ext_save_areas[XSTATE_SSE_BIT].offset = 0; |
| + |
| + for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) { |
| + ExtSaveArea *esa = &x86_ext_save_areas[i]; |
| + |
| + if (esa->size) { |
| + int sz = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EAX); |
| + if (sz != 0) { |
| + assert(esa->size == sz); |
| + esa->offset = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EBX); |
| + } |
| + } |
| + } |
| +} |
| + |
| +static void tcg_cpu_xsave_init(void) |
| +{ |
| +#define XO(bit, field) \ |
| + x86_ext_save_areas[bit].offset = offsetof(X86XSaveArea, field); |
| + |
| + XO(XSTATE_FP_BIT, legacy); |
| + XO(XSTATE_SSE_BIT, legacy); |
| + XO(XSTATE_YMM_BIT, avx_state); |
| + XO(XSTATE_BNDREGS_BIT, bndreg_state); |
| + XO(XSTATE_BNDCSR_BIT, bndcsr_state); |
| + XO(XSTATE_OPMASK_BIT, opmask_state); |
| + XO(XSTATE_ZMM_Hi256_BIT, zmm_hi256_state); |
| + XO(XSTATE_Hi16_ZMM_BIT, hi16_zmm_state); |
| + XO(XSTATE_PKRU_BIT, pkru_state); |
| + |
| +#undef XO |
| +} |
| + |
| /* Load data from X86CPUDefinition into a X86CPU object |
| */ |
| static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model, Error **errp) |
| @@ -7147,6 +7182,12 @@ static void x86_cpu_initfn(Object *obj) |
| if (xcc->model) { |
| x86_cpu_load_model(cpu, xcc->model, &error_abort); |
| } |
| + |
| + if (kvm_enabled()) { |
| + kvm_cpu_xsave_init(); |
| + } else if (tcg_enabled()) { |
| + tcg_cpu_xsave_init(); |
| + } |
| } |
| |
| static int64_t x86_cpu_get_arch_id(CPUState *cs) |
| diff --git a/target/i386/cpu.h b/target/i386/cpu.h |
| index cff2914203..53895a97dd 100644 |
| |
| |
| @@ -1344,7 +1344,7 @@ typedef struct ExtSaveArea { |
| |
| #define XSAVE_STATE_AREA_COUNT (XSTATE_PKRU_BIT + 1) |
| |
| -extern const ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT]; |
| +extern ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT]; |
| |
| typedef enum TPRAccess { |
| TPR_ACCESS_READ, |
| diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c |
| index bbede52fb7..de29137bec 100644 |
| |
| |
| @@ -612,18 +612,11 @@ int hvf_init_vcpu(CPUState *cpu) |
| x86cpu->env.xsave_buf_len = 4096; |
| x86cpu->env.xsave_buf = qemu_memalign(4096, x86cpu->env.xsave_buf_len); |
| |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_STAR, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_LSTAR, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_CSTAR, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FMASK, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FSBASE, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_GSBASE, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_KERNELGSBASE, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_TSC_AUX, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_TSC, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_CS, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_EIP, 1); |
| - hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_ESP, 1); |
| + /* |
| + * The allocated storage must be large enough for all of the |
| + * possible XSAVE state components. |
| + */ |
| + assert(hvf_get_supported_cpuid(0xd, 0, R_ECX) <= x86cpu->env.xsave_buf_len); |
| |
| return 0; |
| } |
| diff --git a/target/i386/kvm.c b/target/i386/kvm.c |
| index 8167587445..548c5e94bb 100644 |
| |
| |
| @@ -1829,6 +1829,13 @@ int kvm_arch_init_vcpu(CPUState *cs) |
| env->xsave_buf_len = sizeof(struct kvm_xsave); |
| env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len); |
| memset(env->xsave_buf, 0, env->xsave_buf_len); |
| + |
| + /* |
| + * The allocated storage must be large enough for all of the |
| + * possible XSAVE state components. |
| + */ |
| + assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX) |
| + <= env->xsave_buf_len); |
| } |
| |
| max_nested_state_len = kvm_max_nested_state_length(); |
| -- |
| 2.27.0 |
| |