[RFC PATCH part-5 22/22] pkvm: x86: Add vmx msr emulation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux