Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 May 2014 03:14:54 +0000 (UTC)
From:      Neel Natu <neel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r266524 - in head/sys/amd64: include vmm
Message-ID:  <201405220314.s4M3Esdn073934@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: neel
Date: Thu May 22 03:14:54 2014
New Revision: 266524
URL: http://svnweb.freebsd.org/changeset/base/266524

Log:
  Inject page fault into the guest if the page table walker detects an invalid
  translation for the guest linear address.

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/include/vmm_instruction_emul.h
  head/sys/amd64/vmm/vmm.c
  head/sys/amd64/vmm/vmm_instruction_emul.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Thu May 22 00:46:03 2014	(r266523)
+++ head/sys/amd64/include/vmm.h	Thu May 22 03:14:54 2014	(r266524)
@@ -236,6 +236,7 @@ int vm_exception_pending(struct vm *vm, 
 
 void vm_inject_gp(struct vm *vm, int vcpuid); /* general protection fault */
 void vm_inject_ud(struct vm *vm, int vcpuid); /* undefined instruction fault */
+void vm_inject_pf(struct vm *vm, int vcpuid, int error_code); /* page fault */
 
 #endif	/* KERNEL */
 

Modified: head/sys/amd64/include/vmm_instruction_emul.h
==============================================================================
--- head/sys/amd64/include/vmm_instruction_emul.h	Thu May 22 00:46:03 2014	(r266523)
+++ head/sys/amd64/include/vmm_instruction_emul.h	Thu May 22 03:14:54 2014	(r266524)
@@ -122,6 +122,16 @@ int vmm_fetch_instruction(struct vm *vm,
 			  enum vie_paging_mode paging_mode, int cpl,
 			  struct vie *vie);
 
+/*
+ * Translate the guest linear address 'gla' to a guest physical address.
+ *
+ * Returns 0 on success and '*gpa' contains the result of the translation.
+ * Returns 1 if a page fault exception was injected into the guest.
+ * Returns -1 otherwise.
+ */
+int vmm_gla2gpa(struct vm *vm, int vcpuid, uint64_t gla, uint64_t cr3,
+    uint64_t *gpa, enum vie_paging_mode paging_mode, int cpl, int prot);
+
 void vie_init(struct vie *vie);
 
 /*

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Thu May 22 00:46:03 2014	(r266523)
+++ head/sys/amd64/vmm/vmm.c	Thu May 22 03:14:54 2014	(r266524)
@@ -1155,9 +1155,14 @@ vm_handle_inst_emul(struct vm *vm, int v
 	vie_init(vie);
 
 	/* Fetch, decode and emulate the faulting instruction */
-	if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3,
-	    paging_mode, cpl, vie) != 0)
+	error = vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3,
+	    paging_mode, cpl, vie);
+	if (error == 1)
+		return (0);		/* Resume guest to handle page fault */
+	else if (error == -1)
 		return (EFAULT);
+	else if (error != 0)
+		panic("%s: vmm_fetch_instruction error %d", __func__, error);
 
 	if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, vie) != 0)
 		return (EFAULT);
@@ -1431,6 +1436,18 @@ vm_inject_fault(struct vm *vm, int vcpui
 }
 
 void
+vm_inject_pf(struct vm *vm, int vcpuid, int error_code)
+{
+	struct vm_exception pf = {
+		.vector = IDT_PF,
+		.error_code_valid = 1,
+		.error_code = error_code
+	};
+
+	vm_inject_fault(vm, vcpuid, &pf);
+}
+
+void
 vm_inject_gp(struct vm *vm, int vcpuid)
 {
 	struct vm_exception gpf = {

Modified: head/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- head/sys/amd64/vmm/vmm_instruction_emul.c	Thu May 22 00:46:03 2014	(r266523)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c	Thu May 22 03:14:54 2014	(r266524)
@@ -572,6 +572,23 @@ vie_init(struct vie *vie)
 	vie->index_register = VM_REG_LAST;
 }
 
+static int
+pf_error_code(int usermode, int prot, uint64_t pte)
+{
+	int error_code = 0;
+
+	if (pte & PG_V)
+		error_code |= PGEX_P;
+	if (prot & VM_PROT_WRITE)
+		error_code |= PGEX_W;
+	if (usermode)
+		error_code |= PGEX_U;
+	if (prot & VM_PROT_EXECUTE)
+		error_code |= PGEX_I;
+
+	return (error_code);
+}
+
 static void
 ptp_release(void **cookie)
 {
@@ -591,11 +608,11 @@ ptp_hold(struct vm *vm, vm_paddr_t ptpph
 	return (ptr);
 }
 
-static int
-gla2gpa(struct vm *vm, uint64_t gla, uint64_t ptpphys, uint64_t *gpa,
-    enum vie_paging_mode paging_mode, int cpl, int prot)
+int
+vmm_gla2gpa(struct vm *vm, int vcpuid, uint64_t gla, uint64_t ptpphys,
+    uint64_t *gpa, enum vie_paging_mode paging_mode, int cpl, int prot)
 {
-	int nlevels, ptpshift, ptpindex, retval, usermode, writable;
+	int nlevels, pfcode, ptpshift, ptpindex, retval, usermode, writable;
 	u_int retries;
 	uint64_t *ptpbase, pte, pgsize;
 	uint32_t *ptpbase32, pte32;
@@ -604,7 +621,7 @@ gla2gpa(struct vm *vm, uint64_t gla, uin
 	usermode = (cpl == 3 ? 1 : 0);
 	writable = prot & VM_PROT_WRITE;
 	cookie = NULL;
-	retval = -1;
+	retval = 0;
 	retries = 0;
 restart:
 	ptp_release(&cookie);
@@ -633,11 +650,13 @@ restart:
 
 			pte32 = ptpbase32[ptpindex];
 
-			if ((pte32 & PG_V) == 0)
-				goto error;
-
-			if (usermode && (pte32 & PG_U) == 0)
-				goto error;
+			if ((pte32 & PG_V) == 0 ||
+			    (usermode && (pte32 & PG_U) == 0) ||
+			    (writable && (pte32 & PG_RW) == 0)) {
+				pfcode = pf_error_code(usermode, prot, pte32);
+				vm_inject_pf(vm, vcpuid, pfcode);
+				goto pagefault;
+			}
 
 			if (writable && (pte32 & PG_RW) == 0)
 				goto error;
@@ -689,8 +708,11 @@ restart:
 
 		pte = ptpbase[ptpindex];
 
-		if ((pte & PG_V) == 0)
-			goto error;
+		if ((pte & PG_V) == 0) {
+			pfcode = pf_error_code(usermode, prot, pte);
+			vm_inject_pf(vm, vcpuid, pfcode);
+			goto pagefault;
+		}
 
 		ptpphys = pte;
 
@@ -711,11 +733,13 @@ restart:
 
 		pte = ptpbase[ptpindex];
 
-		if ((pte & PG_V) == 0)
-			goto error;
-
-		if (usermode && (pte & PG_U) == 0)
-			goto error;
+		if ((pte & PG_V) == 0 ||
+		    (usermode && (pte & PG_U) == 0) ||
+		    (writable && (pte & PG_RW) == 0)) {
+			pfcode = pf_error_code(usermode, prot, pte);
+			vm_inject_pf(vm, vcpuid, pfcode);
+			goto pagefault;
+		}
 
 		if (writable && (pte & PG_RW) == 0)
 			goto error;
@@ -748,10 +772,14 @@ restart:
 	pte >>= ptpshift; pte <<= (ptpshift + 12); pte >>= 12;
 	*gpa = pte | (gla & (pgsize - 1));
 done:
-	retval = 0;
-error:
 	ptp_release(&cookie);
 	return (retval);
+error:
+	retval = -1;
+	goto done;
+pagefault:
+	retval = 1;
+	goto done;
 }
 
 int
@@ -759,7 +787,7 @@ vmm_fetch_instruction(struct vm *vm, int
 		      uint64_t cr3, enum vie_paging_mode paging_mode, int cpl,
 		      struct vie *vie)
 {
-	int n, err, prot;
+	int n, error, prot;
 	uint64_t gpa, off;
 	void *hpa, *cookie;
 
@@ -773,9 +801,10 @@ vmm_fetch_instruction(struct vm *vm, int
 
 	/* Copy the instruction into 'vie' */
 	while (vie->num_valid < inst_length) {
-		err = gla2gpa(vm, rip, cr3, &gpa, paging_mode, cpl, prot);
-		if (err)
-			break;
+		error = vmm_gla2gpa(vm, cpuid, rip, cr3, &gpa, paging_mode,
+		    cpl, prot);
+		if (error)
+			return (error);
 
 		off = gpa & PAGE_MASK;
 		n = min(inst_length - vie->num_valid, PAGE_SIZE - off);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405220314.s4M3Esdn073934>