Re: [PATCH v2 08/25] KVM: VMX: Initialize VMCS FRED fields

From: Chao Gao
Date: Fri Apr 19 2024 - 10:02:01 EST


On Wed, Feb 07, 2024 at 09:26:28AM -0800, Xin Li wrote:
>Initialize host VMCS FRED fields with host FRED MSRs' value and
>guest VMCS FRED fields to 0.
>
>FRED CPU states are managed in 9 new FRED MSRs, as well as a few
>existing CPU registers and MSRs, e.g., CR4.FRED. To support FRED
>context management, new VMCS fields corresponding to most of FRED
>CPU state MSRs are added to both the host-state and guest-state
>areas of VMCS.
>
>Specifically no VMCS fields are added for FRED RSP0 and SSP0 MSRs,
>because the 2 FRED MSRs are used during ring 3 event delivery only,
>thus KVM, running on ring 0, can run safely even with guest FRED
>RSP0 and SSP0. It can be deferred to load host FRED RSP0 and SSP0
>until before returning to user level.
>
>Signed-off-by: Xin Li <xin3.li@xxxxxxxxx>
>Tested-by: Shan Kang <shan.kang@xxxxxxxxx>
>---
>
>Changes since v1:
>* Use kvm_cpu_cap_has() instead of cpu_feature_enabled() to decouple
> KVM's capability to virtualize a feature and host's enabling of a
> feature (Chao Gao).
>* Move guest FRED states init into __vmx_vcpu_reset() (Chao Gao).
>---
> arch/x86/include/asm/vmx.h | 16 ++++++++++++++++
> arch/x86/kvm/vmx/vmx.c | 34 ++++++++++++++++++++++++++++++++++
> 2 files changed, 50 insertions(+)
>
>diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
>index cb14f7e315f5..4889754415b5 100644
>--- a/arch/x86/include/asm/vmx.h
>+++ b/arch/x86/include/asm/vmx.h
>@@ -280,12 +280,28 @@ 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_RSP1 = 0x0000281c,
>+ GUEST_IA32_FRED_RSP2 = 0x0000281e,
>+ GUEST_IA32_FRED_RSP3 = 0x00002820,
>+ GUEST_IA32_FRED_STKLVLS = 0x00002822,
>+ GUEST_IA32_FRED_SSP1 = 0x00002824,
>+ GUEST_IA32_FRED_SSP2 = 0x00002826,
>+ GUEST_IA32_FRED_SSP3 = 0x00002828,
> 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_RSP1 = 0x00002c0a,
>+ HOST_IA32_FRED_RSP2 = 0x00002c0c,
>+ HOST_IA32_FRED_RSP3 = 0x00002c0e,
>+ HOST_IA32_FRED_STKLVLS = 0x00002c10,
>+ HOST_IA32_FRED_SSP1 = 0x00002c12,
>+ HOST_IA32_FRED_SSP2 = 0x00002c14,
>+ HOST_IA32_FRED_SSP3 = 0x00002c16,
> 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 d58ed2d3d379..b7b772183ee4 100644
>--- a/arch/x86/kvm/vmx/vmx.c
>+++ b/arch/x86/kvm/vmx/vmx.c
>@@ -1470,6 +1470,18 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu,
> (unsigned long)(cpu_entry_stack(cpu) + 1));
> }
>
>+#ifdef CONFIG_X86_64

is this #ifdeffery neccesary?

I assume kvm_cpu_cap_has(X86_FEATURE_FRED) is always false for !CONFIG_X86_64.
Looks most of FRED changes in core kernel don't have such #ifdeffery.

>+ /* Per-CPU FRED MSRs */

Please explain why these six MSRs are updated here and why only they are updated in this
comment.

>+ if (kvm_cpu_cap_has(X86_FEATURE_FRED)) {
>+ vmcs_write64(HOST_IA32_FRED_RSP1, read_msr(MSR_IA32_FRED_RSP1));
>+ vmcs_write64(HOST_IA32_FRED_RSP2, read_msr(MSR_IA32_FRED_RSP2));
>+ vmcs_write64(HOST_IA32_FRED_RSP3, read_msr(MSR_IA32_FRED_RSP3));
>+ vmcs_write64(HOST_IA32_FRED_SSP1, read_msr(MSR_IA32_FRED_SSP1));
>+ vmcs_write64(HOST_IA32_FRED_SSP2, read_msr(MSR_IA32_FRED_SSP2));
>+ vmcs_write64(HOST_IA32_FRED_SSP3, read_msr(MSR_IA32_FRED_SSP3));
>+ }
>+#endif
>+
> vmx->loaded_vmcs->cpu = cpu;
> }
> }
>@@ -4321,6 +4333,15 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
> */
> vmcs_write16(HOST_DS_SELECTOR, 0);
> vmcs_write16(HOST_ES_SELECTOR, 0);
>+
>+ /*
>+ * FRED MSRs are per-cpu, however FRED CONFIG and STKLVLS MSRs
>+ * are the same on all CPUs, thus they are initialized here.
>+ */
>+ if (kvm_cpu_cap_has(X86_FEATURE_FRED)) {
>+ vmcs_write64(HOST_IA32_FRED_CONFIG, read_msr(MSR_IA32_FRED_CONFIG));
>+ vmcs_write64(HOST_IA32_FRED_STKLVLS, read_msr(MSR_IA32_FRED_STKLVLS));
>+ }
> #else
> vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */
> vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */
>@@ -4865,6 +4886,19 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu)
> */
> vmx->pi_desc.nv = POSTED_INTR_VECTOR;
> vmx->pi_desc.sn = 1;
>+
>+#ifdef CONFIG_X86_64

ditto

>+ if (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);
>+ }
>+#endif
> }
>
> static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>--
>2.43.0
>
>