Message ID | c98edbcdf5f7163ae04456f7e40be436f6d95744.1646422845.git.isaku.yamahata@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM TDX basic feature support | expand |
On 3/4/22 20:49, isaku.yamahata@intel.com wrote: > From: Isaku Yamahata <isaku.yamahata@intel.com> > > Implements set_msr/get_msr/has_emulated_msr methods for TDX to handle > hypercall from guest TD for paravirtualized rdmsr and wrmsr. The TDX > module virtualizes MSRs. For some MSRs, it injects #VE to the guest TD > upon RDMSR or WRMSR. The exact list of such MSRs are defined in the spec. > > Upon #VE, the guest TD may execute hypercalls, > TDG.VP.VMCALL<INSTRUCTION.RDMSR> and TDG.VP.VMCALL<INSTRUCTION.WRMSR>, > which are defined in GHCI (Guest-Host Communication Interface) so that the > host VMM (e.g. KVM) can virtualizes the MSRs. > > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> > --- > arch/x86/kvm/vmx/main.c | 34 +++++++++++++++++-- > arch/x86/kvm/vmx/tdx.c | 68 ++++++++++++++++++++++++++++++++++++++ > arch/x86/kvm/vmx/x86_ops.h | 6 ++++ > 3 files changed, 105 insertions(+), 3 deletions(-) > > diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c > index 1e65406e3882..a528cfdbce54 100644 > --- a/arch/x86/kvm/vmx/main.c > +++ b/arch/x86/kvm/vmx/main.c > @@ -165,6 +165,34 @@ static void vt_handle_exit_irqoff(struct kvm_vcpu *vcpu) > vmx_handle_exit_irqoff(vcpu); > } > > +static int vt_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > +{ > + if (unlikely(is_td_vcpu(vcpu))) > + return tdx_set_msr(vcpu, msr_info); > + > + return vmx_set_msr(vcpu, msr_info); > +} > + > +/* > + * The kvm parameter can be NULL (module initialization, or invocation before > + * VM creation). Be sure to check the kvm parameter before using it. > + */ > +static bool vt_has_emulated_msr(struct kvm *kvm, u32 index) > +{ > + if (kvm && is_td(kvm)) > + return tdx_is_emulated_msr(index, true); > + > + return vmx_has_emulated_msr(kvm, index); > +} > + > +static int vt_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > +{ > + if (unlikely(is_td_vcpu(vcpu))) > + return tdx_get_msr(vcpu, msr_info); > + > + return vmx_get_msr(vcpu, msr_info); > +} > + > static void vt_apicv_post_state_restore(struct kvm_vcpu *vcpu) > { > if (is_td_vcpu(vcpu)) > @@ -393,7 +421,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { > .hardware_enable = vt_hardware_enable, > .hardware_disable = vt_hardware_disable, > .cpu_has_accelerated_tpr = report_flexpriority, > - .has_emulated_msr = vmx_has_emulated_msr, > + .has_emulated_msr = vt_has_emulated_msr, > > .is_vm_type_supported = vt_is_vm_type_supported, > .vm_size = sizeof(struct kvm_vmx), > @@ -411,8 +439,8 @@ struct kvm_x86_ops vt_x86_ops __initdata = { > > .update_exception_bitmap = vmx_update_exception_bitmap, > .get_msr_feature = vmx_get_msr_feature, > - .get_msr = vmx_get_msr, > - .set_msr = vmx_set_msr, > + .get_msr = vt_get_msr, > + .set_msr = vt_set_msr, > .get_segment_base = vmx_get_segment_base, > .get_segment = vmx_get_segment, > .set_segment = vmx_set_segment, > diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c > index 914af5da4805..cec2660206bd 100644 > --- a/arch/x86/kvm/vmx/tdx.c > +++ b/arch/x86/kvm/vmx/tdx.c > @@ -1517,6 +1517,74 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, > *error_code = 0; > } > > +bool tdx_is_emulated_msr(u32 index, bool write) > +{ > + switch (index) { > + case MSR_IA32_UCODE_REV: > + case MSR_IA32_ARCH_CAPABILITIES: > + case MSR_IA32_POWER_CTL: > + case MSR_MTRRcap: > + case 0x200 ... 0x26f: > + /* IA32_MTRR_PHYS{BASE, MASK}, IA32_MTRR_FIX*_* */ > + case MSR_IA32_CR_PAT: > + case MSR_MTRRdefType: > + case MSR_IA32_TSC_DEADLINE: > + case MSR_IA32_MISC_ENABLE: > + case MSR_KVM_STEAL_TIME: > + case MSR_KVM_POLL_CONTROL: > + case MSR_PLATFORM_INFO: > + case MSR_MISC_FEATURES_ENABLES: > + case MSR_IA32_MCG_CAP: > + case MSR_IA32_MCG_STATUS: > + case MSR_IA32_MCG_CTL: > + case MSR_IA32_MCG_EXT_CTL: > + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(28) - 1: > + /* MSR_IA32_MCx_{CTL, STATUS, ADDR, MISC} */ > + return true; > + case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: > + /* > + * x2APIC registers that are virtualized by the CPU can't be > + * emulated, KVM doesn't have access to the virtual APIC page. > + */ > + switch (index) { > + case X2APIC_MSR(APIC_TASKPRI): > + case X2APIC_MSR(APIC_PROCPRI): > + case X2APIC_MSR(APIC_EOI): > + case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR + APIC_ISR_NR): > + case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR + APIC_ISR_NR): > + case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR + APIC_ISR_NR): > + return false; > + default: > + return true; > + } > + case MSR_IA32_APICBASE: > + case MSR_EFER: > + return !write; > + case MSR_IA32_MCx_CTL2(0) ... MSR_IA32_MCx_CTL2(31): > + /* > + * 0x280 - 0x29f: The x86 common code doesn't emulate MCx_CTL2. > + * Refer to kvm_{get,set}_msr_common(), > + * kvm_mtrr_{get, set}_msr(), and msr_mtrr_valid(). > + */ > + default: > + return false; > + } > +} > + > +int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) > +{ > + if (tdx_is_emulated_msr(msr->index, false)) > + return kvm_get_msr_common(vcpu, msr); > + return 1; > +} > + > +int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) > +{ > + if (tdx_is_emulated_msr(msr->index, true)) > + return kvm_set_msr_common(vcpu, msr); > + return 1; > +} > + > static int tdx_capabilities(struct kvm *kvm, struct kvm_tdx_cmd *cmd) > { > struct kvm_tdx_capabilities __user *user_caps; > diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h > index c0a34186bc37..dcaa5806802e 100644 > --- a/arch/x86/kvm/vmx/x86_ops.h > +++ b/arch/x86/kvm/vmx/x86_ops.h > @@ -156,6 +156,9 @@ void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode, > void tdx_inject_nmi(struct kvm_vcpu *vcpu); > void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, > u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code); > +bool tdx_is_emulated_msr(u32 index, bool write); > +int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); > +int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); > > int tdx_vm_ioctl(struct kvm *kvm, void __user *argp); > int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp); > @@ -193,6 +196,9 @@ static inline void tdx_inject_nmi(struct kvm_vcpu *vcpu) {} > static inline void tdx_get_exit_info( > struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u64 *info2, > u32 *intr_info, u32 *error_code) {} > +static inline bool tdx_is_emulated_msr(u32 index, bool write) { return false; } > +static inline int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; } > +static inline int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; } > > static inline int tdx_vm_ioctl(struct kvm *kvm, void __user *argp) { return -EOPNOTSUPP; } > static inline int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) { return -EOPNOTSUPP; } Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index 1e65406e3882..a528cfdbce54 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -165,6 +165,34 @@ static void vt_handle_exit_irqoff(struct kvm_vcpu *vcpu) vmx_handle_exit_irqoff(vcpu); } +static int vt_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + if (unlikely(is_td_vcpu(vcpu))) + return tdx_set_msr(vcpu, msr_info); + + return vmx_set_msr(vcpu, msr_info); +} + +/* + * The kvm parameter can be NULL (module initialization, or invocation before + * VM creation). Be sure to check the kvm parameter before using it. + */ +static bool vt_has_emulated_msr(struct kvm *kvm, u32 index) +{ + if (kvm && is_td(kvm)) + return tdx_is_emulated_msr(index, true); + + return vmx_has_emulated_msr(kvm, index); +} + +static int vt_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + if (unlikely(is_td_vcpu(vcpu))) + return tdx_get_msr(vcpu, msr_info); + + return vmx_get_msr(vcpu, msr_info); +} + static void vt_apicv_post_state_restore(struct kvm_vcpu *vcpu) { if (is_td_vcpu(vcpu)) @@ -393,7 +421,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .hardware_enable = vt_hardware_enable, .hardware_disable = vt_hardware_disable, .cpu_has_accelerated_tpr = report_flexpriority, - .has_emulated_msr = vmx_has_emulated_msr, + .has_emulated_msr = vt_has_emulated_msr, .is_vm_type_supported = vt_is_vm_type_supported, .vm_size = sizeof(struct kvm_vmx), @@ -411,8 +439,8 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .update_exception_bitmap = vmx_update_exception_bitmap, .get_msr_feature = vmx_get_msr_feature, - .get_msr = vmx_get_msr, - .set_msr = vmx_set_msr, + .get_msr = vt_get_msr, + .set_msr = vt_set_msr, .get_segment_base = vmx_get_segment_base, .get_segment = vmx_get_segment, .set_segment = vmx_set_segment, diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 914af5da4805..cec2660206bd 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -1517,6 +1517,74 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, *error_code = 0; } +bool tdx_is_emulated_msr(u32 index, bool write) +{ + switch (index) { + case MSR_IA32_UCODE_REV: + case MSR_IA32_ARCH_CAPABILITIES: + case MSR_IA32_POWER_CTL: + case MSR_MTRRcap: + case 0x200 ... 0x26f: + /* IA32_MTRR_PHYS{BASE, MASK}, IA32_MTRR_FIX*_* */ + case MSR_IA32_CR_PAT: + case MSR_MTRRdefType: + case MSR_IA32_TSC_DEADLINE: + case MSR_IA32_MISC_ENABLE: + case MSR_KVM_STEAL_TIME: + case MSR_KVM_POLL_CONTROL: + case MSR_PLATFORM_INFO: + case MSR_MISC_FEATURES_ENABLES: + case MSR_IA32_MCG_CAP: + case MSR_IA32_MCG_STATUS: + case MSR_IA32_MCG_CTL: + case MSR_IA32_MCG_EXT_CTL: + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_MISC(28) - 1: + /* MSR_IA32_MCx_{CTL, STATUS, ADDR, MISC} */ + return true; + case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: + /* + * x2APIC registers that are virtualized by the CPU can't be + * emulated, KVM doesn't have access to the virtual APIC page. + */ + switch (index) { + case X2APIC_MSR(APIC_TASKPRI): + case X2APIC_MSR(APIC_PROCPRI): + case X2APIC_MSR(APIC_EOI): + case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR + APIC_ISR_NR): + case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR + APIC_ISR_NR): + case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR + APIC_ISR_NR): + return false; + default: + return true; + } + case MSR_IA32_APICBASE: + case MSR_EFER: + return !write; + case MSR_IA32_MCx_CTL2(0) ... MSR_IA32_MCx_CTL2(31): + /* + * 0x280 - 0x29f: The x86 common code doesn't emulate MCx_CTL2. + * Refer to kvm_{get,set}_msr_common(), + * kvm_mtrr_{get, set}_msr(), and msr_mtrr_valid(). + */ + default: + return false; + } +} + +int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) +{ + if (tdx_is_emulated_msr(msr->index, false)) + return kvm_get_msr_common(vcpu, msr); + return 1; +} + +int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) +{ + if (tdx_is_emulated_msr(msr->index, true)) + return kvm_set_msr_common(vcpu, msr); + return 1; +} + static int tdx_capabilities(struct kvm *kvm, struct kvm_tdx_cmd *cmd) { struct kvm_tdx_capabilities __user *user_caps; diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index c0a34186bc37..dcaa5806802e 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -156,6 +156,9 @@ void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode, void tdx_inject_nmi(struct kvm_vcpu *vcpu); void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code); +bool tdx_is_emulated_msr(u32 index, bool write); +int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); +int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); int tdx_vm_ioctl(struct kvm *kvm, void __user *argp); int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp); @@ -193,6 +196,9 @@ static inline void tdx_inject_nmi(struct kvm_vcpu *vcpu) {} static inline void tdx_get_exit_info( struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code) {} +static inline bool tdx_is_emulated_msr(u32 index, bool write) { return false; } +static inline int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; } +static inline int tdx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { return 1; } static inline int tdx_vm_ioctl(struct kvm *kvm, void __user *argp) { return -EOPNOTSUPP; } static inline int tdx_vcpu_ioctl(struct kvm_vcpu *vcpu, void __user *argp) { return -EOPNOTSUPP; }