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);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to