Host VM see VMX capability, but with reduced features. pKVM need to provide such vmx msrs emulation to tell supported VMX capabilities to the host VM. Signed-off-by: Chuanxiao Dong <chuanxiao.dong@xxxxxxxxx> Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx> --- arch/x86/kvm/vmx/pkvm/hyp/nested.c | 65 +++++++++++++++++++ arch/x86/kvm/vmx/pkvm/hyp/nested.h | 8 +++ .../vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h | 2 +- arch/x86/kvm/vmx/pkvm/hyp/vmsr.c | 25 +++++-- 4 files changed, 94 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/vmx/pkvm/hyp/nested.c b/arch/x86/kvm/vmx/pkvm/hyp/nested.c index 73fa66ba95bd..429bfe7bb309 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/nested.c +++ b/arch/x86/kvm/vmx/pkvm/hyp/nested.c @@ -6,9 +6,71 @@ #include <pkvm.h> #include "pkvm_hyp.h" +#include "nested.h" +#include "cpu.h" #include "vmx.h" #include "debug.h" +/* + * Not support shadow vmcs & vmfunc; + * Not support descriptor-table exiting + * as it requires guest memory access + * to decode and emulate instructions + * which is not supported for protected VM. + */ +#define NESTED_UNSUPPORTED_2NDEXEC \ + (SECONDARY_EXEC_SHADOW_VMCS | \ + SECONDARY_EXEC_ENABLE_VMFUNC | \ + SECONDARY_EXEC_DESC) + +static const unsigned int vmx_msrs[] = { + LIST_OF_VMX_MSRS +}; + +bool is_vmx_msr(unsigned long msr) +{ + bool found = false; + int i; + + for (i = 0; i < ARRAY_SIZE(vmx_msrs); i++) { + if (msr == vmx_msrs[i]) { + found = true; + break; + } + } + + return found; +} + +int read_vmx_msr(struct kvm_vcpu *vcpu, unsigned long msr, u64 *val) +{ + u32 low, high; + int err = 0; + + pkvm_rdmsr(msr, low, high); + + switch (msr) { + case MSR_IA32_VMX_PROCBASED_CTLS2: + high &= ~NESTED_UNSUPPORTED_2NDEXEC; + break; + case MSR_IA32_VMX_MISC: + /* not support PT, SMM */ + low &= ~(MSR_IA32_VMX_MISC_INTEL_PT | BIT(28)); + break; + case MSR_IA32_VMX_VMFUNC: + /* not support vmfunc */ + low = high = 0; + break; + default: + err = -EACCES; + break; + } + + *val = (u64)high << 32 | (u64)low; + + return err; +} + /** * According to SDM Appendix B Field Encoding in VMCS, some fields only * exist on processor that support the 1-setting of the corresponding @@ -492,6 +554,9 @@ static u64 emulate_field_for_vmcs02(struct vcpu_vmx *vmx, u16 field, u64 virt_va /* host always in 64bit mode */ val |= VM_EXIT_HOST_ADDR_SPACE_SIZE; break; + case SECONDARY_VM_EXEC_CONTROL: + val &= ~NESTED_UNSUPPORTED_2NDEXEC; + break; } return val; } diff --git a/arch/x86/kvm/vmx/pkvm/hyp/nested.h b/arch/x86/kvm/vmx/pkvm/hyp/nested.h index 3f785be165c2..24cf731e96dd 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/nested.h +++ b/arch/x86/kvm/vmx/pkvm/hyp/nested.h @@ -16,4 +16,12 @@ int handle_vmlaunch(struct kvm_vcpu *vcpu); int nested_vmexit(struct kvm_vcpu *vcpu); void pkvm_init_nest(void); +#define LIST_OF_VMX_MSRS \ + MSR_IA32_VMX_MISC, \ + MSR_IA32_VMX_PROCBASED_CTLS2, \ + MSR_IA32_VMX_VMFUNC + +bool is_vmx_msr(unsigned long msr); +int read_vmx_msr(struct kvm_vcpu *vcpu, unsigned long msr, u64 *val); + #endif diff --git a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h index 8666cda4ee6d..7b0f1d73d76c 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h +++ b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h @@ -28,6 +28,7 @@ EMULATED_FIELD_RW(VIRTUAL_PROCESSOR_ID, virtual_processor_id) /* 32-bits */ EMULATED_FIELD_RW(VM_EXIT_CONTROLS, vm_exit_controls) EMULATED_FIELD_RW(VM_ENTRY_CONTROLS, vm_entry_controls) +EMULATED_FIELD_RW(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control) /* 64-bits, what about their HIGH 32 fields? */ EMULATED_FIELD_RW(IO_BITMAP_A, io_bitmap_a) @@ -77,7 +78,6 @@ SHADOW_FIELD_RW(GUEST_PML_INDEX, guest_pml_index) /* 32-bits */ SHADOW_FIELD_RW(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control) SHADOW_FIELD_RW(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control) -SHADOW_FIELD_RW(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control) SHADOW_FIELD_RW(EXCEPTION_BITMAP, exception_bitmap) SHADOW_FIELD_RW(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask) SHADOW_FIELD_RW(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match) diff --git a/arch/x86/kvm/vmx/pkvm/hyp/vmsr.c b/arch/x86/kvm/vmx/pkvm/hyp/vmsr.c index 360b0333b84f..ec7476debf25 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/vmsr.c +++ b/arch/x86/kvm/vmx/pkvm/hyp/vmsr.c @@ -5,6 +5,7 @@ #include <pkvm.h> #include "cpu.h" +#include "nested.h" #include "debug.h" #define INTERCEPT_DISABLE (0U) @@ -13,7 +14,7 @@ #define INTERCEPT_READ_WRITE (INTERCEPT_READ | INTERCEPT_WRITE) static unsigned int emulated_ro_guest_msrs[] = { - /* DUMMY */ + LIST_OF_VMX_MSRS, }; static void enable_msr_interception(u8 *bitmap, unsigned int msr_arg, unsigned int mode) @@ -50,11 +51,25 @@ static void enable_msr_interception(u8 *bitmap, unsigned int msr_arg, unsigned i int handle_read_msr(struct kvm_vcpu *vcpu) { - /* simply return 0 for non-supported MSRs */ - vcpu->arch.regs[VCPU_REGS_RAX] = 0; - vcpu->arch.regs[VCPU_REGS_RDX] = 0; + unsigned long msr = vcpu->arch.regs[VCPU_REGS_RCX]; + int ret = 0; + u32 low = 0, high = 0; + u64 val; - return 0; + /* For non-supported MSRs, return low=high=0 by default */ + if (is_vmx_msr(msr)) { + ret = read_vmx_msr(vcpu, msr, &val); + if (!ret) { + low = (u32)val; + high = (u32)(val >> 32); + } + } + pkvm_dbg("%s: CPU%d Value of msr 0x%lx: low=0x%x, high=0x%x\n", __func__, vcpu->cpu, msr, low, high); + + vcpu->arch.regs[VCPU_REGS_RAX] = low; + vcpu->arch.regs[VCPU_REGS_RDX] = high; + + return ret; } int handle_write_msr(struct kvm_vcpu *vcpu) -- 2.25.1