From: "Xin Li (Intel)" Initialize host VMCS FRED fields with host FRED MSRs' value and guest VMCS FRED fields to 0. FRED CPU state is managed in 9 new FRED MSRs: IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP0, IA32_FRED_RSP1, IA32_FRED_RSP2, IA32_FRED_RSP3, IA32_FRED_SSP1, IA32_FRED_SSP2, IA32_FRED_SSP3, as well as a few existing CPU registers and MSRs: CR4.FRED, IA32_STAR, IA32_KERNEL_GS_BASE, IA32_PL0_SSP (also known as IA32_FRED_SSP0). CR4, IA32_KERNEL_GS_BASE and IA32_STAR are already well managed. Except IA32_FRED_RSP0 and IA32_FRED_SSP0, all other FRED CPU state MSRs have corresponding VMCS fields in both the host-state and guest-state areas. So KVM just needs to initialize them, and with proper VM entry/exit FRED controls, a FRED CPU will keep tracking host and guest FRED CPU state in VMCS automatically. Signed-off-by: Xin Li (Intel) Signed-off-by: Sohil Mehta Reviewed-by: Chao Gao Reviewed-by: Binbin Wu --- v10: - s/rdmsrl/rdmsrq (Chao) - Remove a terse comment which doesn't help at all (Sean). - Replace direct, raw use of __this_cpu_ist_top_va() with a self- explanatory this_cpu_fred_rsp() helper for better readability (Sean). - Add cpu_feature_enabled(X86_FEATURE_FRED) to patch out accesses to VMCS FRED fields (Sean). - Remove "#ifdef CONFIG_X86_64" after switching to this_cpu_fred_rsp() (Sean). --- arch/x86/include/asm/kvm_host.h | 3 +++ arch/x86/include/asm/vmx.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx/vmx.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 683bb8bf43a9..8d3999772ac2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -294,6 +294,9 @@ struct kvm_host_values { u64 xss; u64 s_cet; u64 arch_capabilities; + + u64 fred_config; + u64 fred_stklvls; }; extern struct kvm_host_values kvm_host; diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 682f09933612..4720619f09ac 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -306,12 +306,44 @@ enum vmcs_field { GUEST_BNDCFGS_HIGH = 0x00002813, GUEST_IA32_RTIT_CTL = 0x00002814, GUEST_IA32_RTIT_CTL_HIGH = 0x00002815, + GUEST_IA32_FRED_CONFIG = 0x0000281a, + GUEST_IA32_FRED_CONFIG_HIGH = 0x0000281b, + GUEST_IA32_FRED_RSP1 = 0x0000281c, + GUEST_IA32_FRED_RSP1_HIGH = 0x0000281d, + GUEST_IA32_FRED_RSP2 = 0x0000281e, + GUEST_IA32_FRED_RSP2_HIGH = 0x0000281f, + GUEST_IA32_FRED_RSP3 = 0x00002820, + GUEST_IA32_FRED_RSP3_HIGH = 0x00002821, + GUEST_IA32_FRED_STKLVLS = 0x00002822, + GUEST_IA32_FRED_STKLVLS_HIGH = 0x00002823, + GUEST_IA32_FRED_SSP1 = 0x00002824, + GUEST_IA32_FRED_SSP1_HIGH = 0x00002825, + GUEST_IA32_FRED_SSP2 = 0x00002826, + GUEST_IA32_FRED_SSP2_HIGH = 0x00002827, + GUEST_IA32_FRED_SSP3 = 0x00002828, + GUEST_IA32_FRED_SSP3_HIGH = 0x00002829, HOST_IA32_PAT = 0x00002c00, HOST_IA32_PAT_HIGH = 0x00002c01, HOST_IA32_EFER = 0x00002c02, HOST_IA32_EFER_HIGH = 0x00002c03, HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05, + HOST_IA32_FRED_CONFIG = 0x00002c08, + HOST_IA32_FRED_CONFIG_HIGH = 0x00002c09, + HOST_IA32_FRED_RSP1 = 0x00002c0a, + HOST_IA32_FRED_RSP1_HIGH = 0x00002c0b, + HOST_IA32_FRED_RSP2 = 0x00002c0c, + HOST_IA32_FRED_RSP2_HIGH = 0x00002c0d, + HOST_IA32_FRED_RSP3 = 0x00002c0e, + HOST_IA32_FRED_RSP3_HIGH = 0x00002c0f, + HOST_IA32_FRED_STKLVLS = 0x00002c10, + HOST_IA32_FRED_STKLVLS_HIGH = 0x00002c11, + HOST_IA32_FRED_SSP1 = 0x00002c12, + HOST_IA32_FRED_SSP1_HIGH = 0x00002c13, + HOST_IA32_FRED_SSP2 = 0x00002c14, + HOST_IA32_FRED_SSP2_HIGH = 0x00002c15, + HOST_IA32_FRED_SSP3 = 0x00002c16, + HOST_IA32_FRED_SSP3_HIGH = 0x00002c17, PIN_BASED_VM_EXEC_CONTROL = 0x00004000, CPU_BASED_VM_EXEC_CONTROL = 0x00004002, EXCEPTION_BITMAP = 0x00004004, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 2a2218e0983b..dc80ca5f804d 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1562,6 +1562,12 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu) (unsigned long)(cpu_entry_stack(cpu) + 1)); } + if (cpu_feature_enabled(X86_FEATURE_FRED) && kvm_cpu_cap_has(X86_FEATURE_FRED)) { + vmcs_write64(HOST_IA32_FRED_RSP1, this_cpu_fred_rsp(FRED_STACK_LEVEL_1)); + vmcs_write64(HOST_IA32_FRED_RSP2, this_cpu_fred_rsp(FRED_STACK_LEVEL_2)); + vmcs_write64(HOST_IA32_FRED_RSP3, this_cpu_fred_rsp(FRED_STACK_LEVEL_3)); + } + vmx->loaded_vmcs->cpu = cpu; } } @@ -4500,6 +4506,17 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx) */ vmcs_write16(HOST_DS_SELECTOR, 0); vmcs_write16(HOST_ES_SELECTOR, 0); + + if (cpu_feature_enabled(X86_FEATURE_FRED) && kvm_cpu_cap_has(X86_FEATURE_FRED)) { + /* FRED CONFIG and STKLVLS are the same on all CPUs */ + vmcs_write64(HOST_IA32_FRED_CONFIG, kvm_host.fred_config); + vmcs_write64(HOST_IA32_FRED_STKLVLS, kvm_host.fred_stklvls); + + /* Linux doesn't support kernel shadow stacks, thus SSPs are 0s */ + vmcs_write64(HOST_IA32_FRED_SSP1, 0); + vmcs_write64(HOST_IA32_FRED_SSP2, 0); + vmcs_write64(HOST_IA32_FRED_SSP3, 0); + } #else vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ @@ -5030,6 +5047,17 @@ static void init_vmcs(struct vcpu_vmx *vmx) } vmx_setup_uret_msrs(vmx); + + if (cpu_feature_enabled(X86_FEATURE_FRED) && kvm_cpu_cap_has(X86_FEATURE_FRED)) { + vmcs_write64(GUEST_IA32_FRED_CONFIG, 0); + vmcs_write64(GUEST_IA32_FRED_RSP1, 0); + vmcs_write64(GUEST_IA32_FRED_RSP2, 0); + vmcs_write64(GUEST_IA32_FRED_RSP3, 0); + vmcs_write64(GUEST_IA32_FRED_STKLVLS, 0); + vmcs_write64(GUEST_IA32_FRED_SSP1, 0); + vmcs_write64(GUEST_IA32_FRED_SSP2, 0); + vmcs_write64(GUEST_IA32_FRED_SSP3, 0); + } } static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu) @@ -8883,6 +8911,11 @@ __init int vmx_hardware_setup(void) kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_IGNORE_GUEST_PAT; + if (cpu_feature_enabled(X86_FEATURE_FRED) && kvm_cpu_cap_has(X86_FEATURE_FRED)) { + rdmsrq(MSR_IA32_FRED_CONFIG, kvm_host.fred_config); + rdmsrq(MSR_IA32_FRED_STKLVLS, kvm_host.fred_stklvls); + } + return 0; } -- 2.43.0