[RFC PATCH part-5 03/22] pkvm: x86: Do guest address translation per page granularity

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

 



From: Haiwei Li <haiwei.li@xxxxxxxxx>

Guest memory operations like read_gva/write_gva/read_gpa/write_gpa only
support doing address translation for current page. It's not correct if
such operation access data over current page.

Fix above issue for these functions by doing address translation per page
granularity.

Signed-off-by: Haiwei Li <haiwei.li@xxxxxxxxx>
---
 arch/x86/kvm/vmx/pkvm/hyp/memory.c | 65 ++++++++++++++++++++----------
 1 file changed, 44 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kvm/vmx/pkvm/hyp/memory.c b/arch/x86/kvm/vmx/pkvm/hyp/memory.c
index e99fa72cedac..a42669ccf89c 100644
--- a/arch/x86/kvm/vmx/pkvm/hyp/memory.c
+++ b/arch/x86/kvm/vmx/pkvm/hyp/memory.c
@@ -110,27 +110,47 @@ int gva2gpa(struct kvm_vcpu *vcpu, gva_t gva, gpa_t *gpa,
 	return check_translation(vcpu, _gpa, prot, access, exception);
 }
 
-/* only support host VM now */
-static int copy_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr,
-		unsigned int bytes, struct x86_exception *exception, bool from_guest)
+static inline int __copy_gpa(struct kvm_vcpu *vcpu, void *addr, gpa_t gpa,
+			     unsigned int size, unsigned int pg_size,
+			     bool from_guest)
 {
-	u32 access = VMX_AR_DPL(vmcs_read32(GUEST_SS_AR_BYTES)) == 3 ? PFERR_USER_MASK : 0;
-	gpa_t gpa;
+	unsigned int len, offset_in_pg;
 	void *hva;
-	int ret;
 
-	/*FIXME: need check the gva per page granularity */
-	ret = gva2gpa(vcpu, gva, &gpa, access, exception);
-	if (ret)
-		return ret;
+	offset_in_pg = (unsigned int)gpa & (pg_size - 1);
+	len = (size > (pg_size - offset_in_pg)) ? (pg_size - offset_in_pg) : size;
 
 	hva = host_gpa2hva(gpa);
 	if (from_guest)
-		memcpy(addr, hva, bytes);
+		memcpy(addr, hva, len);
 	else
-		memcpy(hva, addr, bytes);
+		memcpy(hva, addr, len);
 
-	return bytes;
+	return len;
+}
+
+/* only support host VM now */
+static int copy_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr,
+		unsigned int bytes, struct x86_exception *exception, bool from_guest)
+{
+	u32 access = VMX_AR_DPL(vmcs_read32(GUEST_SS_AR_BYTES)) == 3 ? PFERR_USER_MASK : 0;
+	gpa_t gpa;
+	unsigned int len;
+	int ret = 0;
+
+	while ((bytes > 0) && (ret == 0)) {
+		ret = gva2gpa(vcpu, gva, &gpa, access, exception);
+		if (ret >= 0) {
+			len = __copy_gpa(vcpu, addr, gpa, bytes, PAGE_SIZE, from_guest);
+			if (len == 0)
+				return -EINVAL;
+			gva += len;
+			addr += len;
+			bytes -= len;
+		}
+	}
+
+	return ret;
 }
 
 int read_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr,
@@ -149,15 +169,18 @@ int write_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr,
 static int copy_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, void *addr,
 		unsigned int bytes, bool from_guest)
 {
-	void *hva;
-
-	hva = host_gpa2hva(gpa);
-	if (from_guest)
-		memcpy(addr, hva, bytes);
-	else
-		memcpy(hva, addr, bytes);
+	unsigned int len;
+
+	while (bytes > 0) {
+		len = __copy_gpa(vcpu, addr, gpa, bytes, PAGE_SIZE, from_guest);
+		if (len == 0)
+			return -EINVAL;
+		gpa += len;
+		addr += len;
+		bytes -= len;
+	}
 
-	return bytes;
+	return 0;
 }
 
 int read_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, void *addr, unsigned int bytes)
-- 
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