[RFC PATCH part-6 05/13] pkvm: x86: Introduce vEPT to record guest EPT information

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

 



From: Chuanxiao Dong <chuanxiao.dong@xxxxxxxxx>

KVM-high manages a guest EPT for its nested VM, which shall be shadowed
to shadow EPT in pKVM hypervisor.

Introduce a per vcpu pgtable(vEPT) to save the guest EPT related
information from KVM-high when vmwrite(EPTP).

Each time when a vcpu vmwrites to EPTP, pKVM will setup the vEPT
according to the new value or just do nothing if it is the same
with the last one.

Signed-off-by: Chuanxiao Dong <chuanxiao.dong@xxxxxxxxx>
Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx>
---
 arch/x86/kvm/vmx/pkvm/hyp/ept.c      | 33 ++++++++++++++++++++++++++++
 arch/x86/kvm/vmx/pkvm/hyp/ept.h      | 10 +++++++++
 arch/x86/kvm/vmx/pkvm/hyp/memory.c   |  6 +++++
 arch/x86/kvm/vmx/pkvm/hyp/memory.h   |  1 +
 arch/x86/kvm/vmx/pkvm/hyp/nested.c   | 16 ++++++++++++++
 arch/x86/kvm/vmx/pkvm/hyp/pkvm_hyp.h |  3 +++
 6 files changed, 69 insertions(+)

diff --git a/arch/x86/kvm/vmx/pkvm/hyp/ept.c b/arch/x86/kvm/vmx/pkvm/hyp/ept.c
index 0edea266b8bc..641b8252071e 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/ept.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/ept.c
@@ -297,3 +297,36 @@ int pkvm_shadow_ept_init(struct shadow_ept_desc *desc)
 
 	return 0;
 }
+
+/*
+ * virtual_ept_mm_ops is used as the ops for the ept constructed by
+ * KVM high in host.
+ * The physical address in this ept is the host VM GPA, which is
+ * the same with HPA.
+ */
+struct pkvm_mm_ops virtual_ept_mm_ops = {
+	.phys_to_virt = host_gpa2hva,
+};
+
+void pkvm_guest_ept_deinit(struct shadow_vcpu_state *shadow_vcpu)
+{
+	struct pkvm_pgtable *vept = &shadow_vcpu->vept;
+
+	memset(vept, 0, sizeof(struct pkvm_pgtable));
+}
+
+void pkvm_guest_ept_init(struct shadow_vcpu_state *shadow_vcpu, u64 guest_eptp)
+{
+	/*
+	 * TODO: we just assume guest will use page level the HW supported,
+	 * it actually need align with KVM high
+	 */
+	struct pkvm_pgtable_cap cap = {
+		.level = pkvm_hyp->ept_cap.level,
+		.allowed_pgsz = pkvm_hyp->ept_cap.allowed_pgsz,
+		.table_prot = pkvm_hyp->ept_cap.table_prot,
+	};
+
+	pkvm_pgtable_init(&shadow_vcpu->vept, &virtual_ept_mm_ops, &ept_ops, &cap, false);
+	shadow_vcpu->vept.root_pa = host_gpa2hpa(guest_eptp & SPTE_BASE_ADDR_MASK);
+}
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/ept.h b/arch/x86/kvm/vmx/pkvm/hyp/ept.h
index 7badcb3dd621..420c9c5816e9 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/ept.h
+++ b/arch/x86/kvm/vmx/pkvm/hyp/ept.h
@@ -22,5 +22,15 @@ int handle_host_ept_violation(unsigned long gpa);
 int pkvm_shadow_ept_pool_init(void *ept_pool_base, unsigned long ept_pool_pages);
 int pkvm_shadow_ept_init(struct shadow_ept_desc *desc);
 void pkvm_shadow_ept_deinit(struct shadow_ept_desc *desc);
+void pkvm_guest_ept_init(struct shadow_vcpu_state *shadow_vcpu, u64 guest_eptp);
+void pkvm_guest_ept_deinit(struct shadow_vcpu_state *shadow_vcpu);
 
+static inline bool is_valid_eptp(u64 eptp)
+{
+	if (!eptp || (eptp == INVALID_GPA))
+		return false;
+
+	/* TODO: other bits check */
+	return true;
+}
 #endif
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/memory.c b/arch/x86/kvm/vmx/pkvm/hyp/memory.c
index 6a400aef1bd8..43fc39d44c3d 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/memory.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/memory.c
@@ -73,6 +73,12 @@ void *host_gpa2hva(unsigned long gpa)
 	return pkvm_phys_to_virt(gpa);
 }
 
+unsigned long host_gpa2hpa(unsigned long gpa)
+{
+	/* Host VM is using identity mapping so GPA == HPA */
+	return gpa;
+}
+
 extern struct pkvm_pgtable_ops mmu_ops;
 static struct pkvm_mm_ops mm_ops = {
 	.phys_to_virt = host_gpa2hva,
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/memory.h b/arch/x86/kvm/vmx/pkvm/hyp/memory.h
index 4a75d8dff1b3..a95ae5f71841 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/memory.h
+++ b/arch/x86/kvm/vmx/pkvm/hyp/memory.h
@@ -22,6 +22,7 @@ bool mem_range_included(struct mem_range *child, struct mem_range *parent);
 
 #include <linux/kvm_host.h>
 void *host_gpa2hva(unsigned long gpa);
+unsigned long host_gpa2hpa(unsigned long gpa);
 int gva2gpa(struct kvm_vcpu *vcpu, gva_t gva, gpa_t *gpa,
 		u32 access, struct x86_exception *exception);
 int read_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr,
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/nested.c b/arch/x86/kvm/vmx/pkvm/hyp/nested.c
index 429bfe7bb309..68eddb459cfa 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/nested.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/nested.c
@@ -9,6 +9,7 @@
 #include "nested.h"
 #include "cpu.h"
 #include "vmx.h"
+#include "ept.h"
 #include "debug.h"
 
 /*
@@ -704,6 +705,18 @@ static void nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
 	}
 }
 
+static void setup_guest_ept(struct shadow_vcpu_state *shadow_vcpu, u64 guest_eptp)
+{
+	struct vmcs12 *vmcs12 = (struct vmcs12 *)shadow_vcpu->cached_vmcs12;
+
+	if (!is_valid_eptp(guest_eptp))
+		pkvm_guest_ept_deinit(shadow_vcpu);
+	else if (vmcs12->ept_pointer != guest_eptp) {
+		pkvm_guest_ept_deinit(shadow_vcpu);
+		pkvm_guest_ept_init(shadow_vcpu, guest_eptp);
+	}
+}
+
 int handle_vmxon(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -908,6 +921,9 @@ int handle_vmwrite(struct kvm_vcpu *vcpu)
 			if (field >= GUEST_ES_AR_BYTES && field <= GUEST_TR_AR_BYTES)
 				value &= 0x1f0ff;
 
+			if (field == EPT_POINTER)
+				setup_guest_ept(cur_shadow_vcpu, value);
+
 			vmcs12_write_any(vmcs12, field, offset, value);
 
 			if (is_emulated_fields(field)) {
diff --git a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_hyp.h b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_hyp.h
index a1f3644a4a34..f891660d9085 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_hyp.h
+++ b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_hyp.h
@@ -41,6 +41,9 @@ struct shadow_vcpu_state {
 
 	struct vcpu_vmx vmx;
 
+	/* represents for the virtual EPT configured by kvm-high */
+	struct pkvm_pgtable vept;
+
 	/* assume vmcs02 is one page */
 	u8 vmcs02[PAGE_SIZE] __aligned(PAGE_SIZE);
 	u8 cached_vmcs12[VMCS12_SIZE] __aligned(PAGE_SIZE);
-- 
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