Message ID | 20240219074733.122080-23-weijiang.yang@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Enable CET Virtualization | expand |
On Sun, Feb 18, 2024, Yang Weijiang wrote: > @@ -7767,6 +7771,41 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) > vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i * 4)); > } > > +static void vmx_update_intercept_for_cet_msr(struct kvm_vcpu *vcpu) > +{ > + bool incpt; > + > + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { > + incpt = !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); > + > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, > + MSR_TYPE_RW, incpt); > + vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB, > + MSR_TYPE_RW, incpt); > + if (!incpt) > + return; Hmm, I find this is unnecessarily confusing and brittle. E.g. in the unlikely event more CET stuff comes along, this lurking return could cause problems. Why not handle S_CET and U_CET in a single common path? IMO, this is less error prone, and more clearly captures the relationship between S/U_CET, SHSTK, and IBT. Updating MSR intercepts is not a hot path, so the overhead of checking guest CPUID multiple times should be a non-issue. And eventually KVM should effectively cache all of those lookups, i.e. the cost will be negilible. bool incpt; if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { incpt = !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, MSR_TYPE_RW, incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, MSR_TYPE_RW, incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, MSR_TYPE_RW, incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, MSR_TYPE_RW, incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB, MSR_TYPE_RW, incpt); } if (kvm_cpu_cap_has(X86_FEATURE_SHSTK) || kvm_cpu_cap_has(X86_FEATURE_IBT)) { incpt = !guest_cpuid_has(vcpu, X86_FEATURE_IBT) && !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, MSR_TYPE_RW, incpt); vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, incpt); }
On 5/2/2024 7:07 AM, Sean Christopherson wrote: > On Sun, Feb 18, 2024, Yang Weijiang wrote: >> @@ -7767,6 +7771,41 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) >> vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i * 4)); >> } >> >> +static void vmx_update_intercept_for_cet_msr(struct kvm_vcpu *vcpu) >> +{ >> + bool incpt; >> + >> + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { >> + incpt = !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); >> + >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, >> + MSR_TYPE_RW, incpt); >> + vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB, >> + MSR_TYPE_RW, incpt); >> + if (!incpt) >> + return; > Hmm, I find this is unnecessarily confusing and brittle. E.g. in the unlikely > event more CET stuff comes along, this lurking return could cause problems. > > Why not handle S_CET and U_CET in a single common path? IMO, this is less error > prone, and more clearly captures the relationship between S/U_CET, SHSTK, and IBT. > Updating MSR intercepts is not a hot path, so the overhead of checking guest CPUID > multiple times should be a non-issue. And eventually KVM should effectively cache > all of those lookups, i.e. the cost will be negilible. > > bool incpt; > > if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { > incpt = !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); > > vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, > MSR_TYPE_RW, incpt); > vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, > MSR_TYPE_RW, incpt); > vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, > MSR_TYPE_RW, incpt); > vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, > MSR_TYPE_RW, incpt); > vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB, > MSR_TYPE_RW, incpt); > } > > if (kvm_cpu_cap_has(X86_FEATURE_SHSTK) || > kvm_cpu_cap_has(X86_FEATURE_IBT)) { > incpt = !guest_cpuid_has(vcpu, X86_FEATURE_IBT) && > !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); > > vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, > MSR_TYPE_RW, incpt); > vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, > MSR_TYPE_RW, incpt); > } It looks fine to me, will apply it, thanks!
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index ff2296fa7d39..24e921c4e7e3 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -159,7 +159,7 @@ module_param(allow_smaller_maxphyaddr, bool, S_IRUGO); /* * List of MSRs that can be directly passed to the guest. - * In addition to these x2apic and PT MSRs are handled specially. + * In addition to these x2apic/PT/CET MSRs are handled specially. */ static u32 vmx_possible_passthrough_msrs[MAX_POSSIBLE_PASSTHROUGH_MSRS] = { MSR_IA32_SPEC_CTRL, @@ -692,6 +692,10 @@ static bool is_valid_passthrough_msr(u32 msr) case MSR_LBR_CORE_TO ... MSR_LBR_CORE_TO + 8: /* LBR MSRs. These are handled in vmx_update_intercept_for_lbr_msrs() */ return true; + case MSR_IA32_U_CET: + case MSR_IA32_S_CET: + case MSR_IA32_PL0_SSP ... MSR_IA32_INT_SSP_TAB: + return true; } r = possible_passthrough_msr_slot(msr) != -ENOENT; @@ -7767,6 +7771,41 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i * 4)); } +static void vmx_update_intercept_for_cet_msr(struct kvm_vcpu *vcpu) +{ + bool incpt; + + if (kvm_cpu_cap_has(X86_FEATURE_SHSTK)) { + incpt = !guest_cpuid_has(vcpu, X86_FEATURE_SHSTK); + + vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL0_SSP, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL1_SSP, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL2_SSP, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PL3_SSP, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_INT_SSP_TAB, + MSR_TYPE_RW, incpt); + if (!incpt) + return; + } + + if (kvm_cpu_cap_has(X86_FEATURE_IBT)) { + incpt = !guest_cpuid_has(vcpu, X86_FEATURE_IBT); + + vmx_set_intercept_for_msr(vcpu, MSR_IA32_U_CET, + MSR_TYPE_RW, incpt); + vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, + MSR_TYPE_RW, incpt); + } +} + static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -7845,6 +7884,8 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) /* Refresh #PF interception to account for MAXPHYADDR changes. */ vmx_update_exception_bitmap(vcpu); + + vmx_update_intercept_for_cet_msr(vcpu); } static u64 vmx_get_perf_capabilities(void)