Skip to content

Commit dd50294

Browse files
yamahatabonzini
authored andcommitted
KVM: TDX: Implement callbacks for MSR operations
Add functions to implement MSR related callbacks, .set_msr(), .get_msr(), and .has_emulated_msr(), for preparation of handling hypercalls from TDX guest for PV RDMSR and WRMSR. Ignore KVM_REQ_MSR_FILTER_CHANGED for TDX. There are three classes of MSR virtualization for TDX. - Non-configurable: TDX module directly virtualizes it. VMM can't configure it, the value set by KVM_SET_MSRS is ignored. - Configurable: TDX module directly virtualizes it. VMM can configure it at VM creation time. The value set by KVM_SET_MSRS is used. - #VE case: TDX guest would issue TDG.VP.VMCALL<INSTRUCTION.{WRMSR,RDMSR}> and VMM handles the MSR hypercall. The value set by KVM_SET_MSRS is used. For the MSRs belonging to the #VE case, the TDX module injects #VE to the TDX guest upon RDMSR or WRMSR. The exact list of such MSRs is defined in TDX Module ABI Spec. Upon #VE, the TDX guest may call TDG.VP.VMCALL<INSTRUCTION.{WRMSR,RDMSR}>, which are defined in GHCI (Guest-Host Communication Interface) so that the host VMM (e.g. KVM) can virtualize the MSRs. TDX doesn't allow VMM to configure interception of MSR accesses. Ignore KVM_REQ_MSR_FILTER_CHANGED for TDX guest. If the userspace has set any MSR filters, it will be applied when handling TDG.VP.VMCALL<INSTRUCTION.{WRMSR,RDMSR}> in a later patch. Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> Co-developed-by: Binbin Wu <binbin.wu@linux.intel.com> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-ID: <20250227012021.1778144-9-binbin.wu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 7ddf314 commit dd50294

File tree

3 files changed

+119
-4
lines changed

3 files changed

+119
-4
lines changed

arch/x86/kvm/vmx/main.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,48 @@ static int vt_handle_exit(struct kvm_vcpu *vcpu,
193193
return vmx_handle_exit(vcpu, fastpath);
194194
}
195195

196+
static int vt_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
197+
{
198+
if (unlikely(is_td_vcpu(vcpu)))
199+
return tdx_set_msr(vcpu, msr_info);
200+
201+
return vmx_set_msr(vcpu, msr_info);
202+
}
203+
204+
/*
205+
* The kvm parameter can be NULL (module initialization, or invocation before
206+
* VM creation). Be sure to check the kvm parameter before using it.
207+
*/
208+
static bool vt_has_emulated_msr(struct kvm *kvm, u32 index)
209+
{
210+
if (kvm && is_td(kvm))
211+
return tdx_has_emulated_msr(index);
212+
213+
return vmx_has_emulated_msr(kvm, index);
214+
}
215+
216+
static int vt_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
217+
{
218+
if (unlikely(is_td_vcpu(vcpu)))
219+
return tdx_get_msr(vcpu, msr_info);
220+
221+
return vmx_get_msr(vcpu, msr_info);
222+
}
223+
224+
static void vt_msr_filter_changed(struct kvm_vcpu *vcpu)
225+
{
226+
/*
227+
* TDX doesn't allow VMM to configure interception of MSR accesses.
228+
* TDX guest requests MSR accesses by calling TDVMCALL. The MSR
229+
* filters will be applied when handling the TDVMCALL for RDMSR/WRMSR
230+
* if the userspace has set any.
231+
*/
232+
if (is_td_vcpu(vcpu))
233+
return;
234+
235+
vmx_msr_filter_changed(vcpu);
236+
}
237+
196238
#ifdef CONFIG_KVM_SMM
197239
static int vt_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
198240
{
@@ -516,7 +558,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
516558
.disable_virtualization_cpu = vt_disable_virtualization_cpu,
517559
.emergency_disable_virtualization_cpu = vmx_emergency_disable_virtualization_cpu,
518560

519-
.has_emulated_msr = vmx_has_emulated_msr,
561+
.has_emulated_msr = vt_has_emulated_msr,
520562

521563
.vm_size = sizeof(struct kvm_vmx),
522564

@@ -535,8 +577,8 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
535577

536578
.update_exception_bitmap = vmx_update_exception_bitmap,
537579
.get_feature_msr = vmx_get_feature_msr,
538-
.get_msr = vmx_get_msr,
539-
.set_msr = vmx_set_msr,
580+
.get_msr = vt_get_msr,
581+
.set_msr = vt_set_msr,
540582
.get_segment_base = vmx_get_segment_base,
541583
.get_segment = vmx_get_segment,
542584
.set_segment = vmx_set_segment,
@@ -643,7 +685,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
643685
.apic_init_signal_blocked = vt_apic_init_signal_blocked,
644686
.migrate_timers = vmx_migrate_timers,
645687

646-
.msr_filter_changed = vmx_msr_filter_changed,
688+
.msr_filter_changed = vt_msr_filter_changed,
647689
.complete_emulated_msr = kvm_complete_insn_gp,
648690

649691
.vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector,

arch/x86/kvm/vmx/tdx.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,6 +2028,73 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
20282028
*error_code = 0;
20292029
}
20302030

2031+
bool tdx_has_emulated_msr(u32 index)
2032+
{
2033+
switch (index) {
2034+
case MSR_IA32_UCODE_REV:
2035+
case MSR_IA32_ARCH_CAPABILITIES:
2036+
case MSR_IA32_POWER_CTL:
2037+
case MSR_IA32_CR_PAT:
2038+
case MSR_IA32_TSC_DEADLINE:
2039+
case MSR_IA32_MISC_ENABLE:
2040+
case MSR_PLATFORM_INFO:
2041+
case MSR_MISC_FEATURES_ENABLES:
2042+
case MSR_IA32_APICBASE:
2043+
case MSR_EFER:
2044+
case MSR_IA32_MCG_CAP:
2045+
case MSR_IA32_MCG_STATUS:
2046+
case MSR_IA32_MCG_CTL:
2047+
case MSR_IA32_MCG_EXT_CTL:
2048+
case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
2049+
case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1:
2050+
/* MSR_IA32_MCx_{CTL, STATUS, ADDR, MISC, CTL2} */
2051+
case MSR_KVM_POLL_CONTROL:
2052+
return true;
2053+
case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff:
2054+
/*
2055+
* x2APIC registers that are virtualized by the CPU can't be
2056+
* emulated, KVM doesn't have access to the virtual APIC page.
2057+
*/
2058+
switch (index) {
2059+
case X2APIC_MSR(APIC_TASKPRI):
2060+
case X2APIC_MSR(APIC_PROCPRI):
2061+
case X2APIC_MSR(APIC_EOI):
2062+
case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR + APIC_ISR_NR):
2063+
case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR + APIC_ISR_NR):
2064+
case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR + APIC_ISR_NR):
2065+
return false;
2066+
default:
2067+
return true;
2068+
}
2069+
default:
2070+
return false;
2071+
}
2072+
}
2073+
2074+
static bool tdx_is_read_only_msr(u32 index)
2075+
{
2076+
return index == MSR_IA32_APICBASE || index == MSR_EFER;
2077+
}
2078+
2079+
int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
2080+
{
2081+
if (!tdx_has_emulated_msr(msr->index))
2082+
return 1;
2083+
2084+
return kvm_get_msr_common(vcpu, msr);
2085+
}
2086+
2087+
int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
2088+
{
2089+
if (tdx_is_read_only_msr(msr->index))
2090+
return 1;
2091+
2092+
if (!tdx_has_emulated_msr(msr->index))
2093+
return 1;
2094+
2095+
return kvm_set_msr_common(vcpu, msr);
2096+
}
2097+
20312098
static int tdx_get_capabilities(struct kvm_tdx_cmd *cmd)
20322099
{
20332100
const struct tdx_sys_info_td_conf *td_conf = &tdx_sysinfo->td_conf;

arch/x86/kvm/vmx/x86_ops.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
144144
void tdx_inject_nmi(struct kvm_vcpu *vcpu);
145145
void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
146146
u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code);
147+
bool tdx_has_emulated_msr(u32 index);
148+
int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
149+
int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
147150

148151
int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp);
149152

@@ -187,6 +190,9 @@ static inline void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mo
187190
static inline void tdx_inject_nmi(struct kvm_vcpu *vcpu) {}
188191
static inline void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, u64 *info1,
189192
u64 *info2, u32 *intr_info, u32 *error_code) {}
193+
static inline bool tdx_has_emulated_msr(u32 index) { return false; }
194+
static inline int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; }
195+
static inline int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; }
190196

191197
static inline int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) { return -EOPNOTSUPP; }
192198

0 commit comments

Comments
 (0)