VMM: Call EPT ops for every KPT op
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 2 Apr 2015 01:47:03 +0000 (21:47 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 7 Apr 2015 19:06:59 +0000 (15:06 -0400)
At this point, the EPT should equal the KPT, up to UVPT.

I disconnected the EPT fault handler for now.  tests/vmmcp still works,
since everything is pre-faulted in.  We'll need to change it to do the
initial faults from the VM.

kern/arch/x86/arch.h
kern/arch/x86/kpt.h [new file with mode: 0644]
kern/arch/x86/pmap.c
kern/arch/x86/pmap64.c
kern/arch/x86/pmap_ops.h
kern/arch/x86/vmm/ept.h [new file with mode: 0644]
kern/arch/x86/vmm/intel/Kbuild
kern/arch/x86/vmm/intel/ept.c [deleted file]
kern/arch/x86/vmm/intel/vmx.c
kern/arch/x86/vmm/intel/vmx.h

index bf6f85e..bee50ea 100644 (file)
@@ -14,8 +14,6 @@
 #define __always_inline inline __attribute__((always_inline))
 
 static inline void breakpoint(void) __attribute__((always_inline));
-static inline void invlpg(void *addr) __attribute__((always_inline));  
-static inline void tlbflush(void) __attribute__((always_inline));
 static inline void icache_flush_page(void *va, void *kva)
               __attribute__((always_inline));
 static inline uint64_t read_tsc(void) __attribute__((always_inline));
@@ -42,24 +40,16 @@ void send_ipi(uint32_t os_coreid, uint8_t vector);
 void print_cpuinfo(void);
 void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size);
 int vendor_id(char *);
+/* pmap.c */
+void invlpg(void *addr);
+void tlbflush(void);
+void tlb_flush_global(void);
 
 static inline void breakpoint(void)
 {
        asm volatile("int3");
 }
 
-static inline void invlpg(void *addr)
-{ 
-       asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
-}  
-
-static inline void tlbflush(void)
-{
-       unsigned long cr3;
-       asm volatile("mov %%cr3,%0" : "=r" (cr3));
-       asm volatile("mov %0,%%cr3" : : "r" (cr3));
-}
-
 static inline void icache_flush_page(void *va, void *kva)
 {
        // x86 handles self-modifying code (mostly) without SW support
diff --git a/kern/arch/x86/kpt.h b/kern/arch/x86/kpt.h
new file mode 100644 (file)
index 0000000..3415418
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * 64 bit KPT helpers */
+
+#ifndef ROS_ARCH_KPT_H
+#define ROS_ARCH_KPT_H
+
+#include <arch/ros/mmu64.h>
+
+static inline bool kpte_is_present(kpte_t *kpte)
+{
+       return *kpte & PTE_P ? TRUE : FALSE;
+}
+
+static inline bool kpte_is_unmapped(kpte_t *kpte)
+{
+       return *kpte == 0;
+}
+
+static inline bool kpte_is_mapped(kpte_t *kpte)
+{
+       return *kpte != 0;
+}
+
+static inline bool kpte_is_paged_out(kpte_t *kpte)
+{
+       return *kpte != 0;
+}
+
+static inline bool kpte_is_dirty(kpte_t *kpte)
+{
+       return *kpte & PTE_D ? TRUE : FALSE;
+}
+
+static inline bool kpte_is_accessed(kpte_t *kpte)
+{
+       return *kpte & PTE_A ? TRUE : FALSE;
+}
+
+static inline bool kpte_is_jumbo(kpte_t *kpte)
+{
+       return *kpte & PTE_PS ? TRUE : FALSE;
+}
+
+static inline physaddr_t kpte_get_paddr(kpte_t *kpte)
+{
+       return (physaddr_t)*kpte & ~(PGSIZE - 1);
+}
+
+/* Returns the PTE in an unsigned long, for debugging mostly. */
+static inline unsigned long kpte_print(kpte_t *kpte)
+{
+       return *kpte;
+}
+
+static inline void kpte_write(kpte_t *kpte, physaddr_t pa, int perm)
+{
+       assert(!PGOFF(pa));
+       *kpte = pa | perm;
+}
+
+static inline void kpte_clear_present(kpte_t *kpte)
+{
+       *kpte &= ~PTE_P;
+}
+
+static inline void kpte_clear(kpte_t *kpte)
+{
+       *kpte = 0;
+}
+
+static inline bool kpte_has_perm_ur(kpte_t *kpte)
+{
+       return (*kpte & PTE_USER_RO) == PTE_USER_RO;
+}
+
+static inline bool kpte_has_perm_urw(kpte_t *kpte)
+{
+       return (*kpte & PTE_USER_RW) == PTE_USER_RW;
+}
+
+static inline int kpte_get_perm(kpte_t *kpte)
+{
+       return *kpte & PTE_PERM;
+}
+
+static inline void kpte_replace_perm(kpte_t *kpte, int perm)
+{
+       *kpte = (*kpte & ~PTE_PERM) | perm;
+}
+
+#endif /* ROS_ARCH_KPT_H */
index 2fe9f56..903387c 100644 (file)
@@ -99,6 +99,22 @@ void setup_default_mtrrs(barrier_t* smp_barrier)
        enable_irqsave(&state);
 }
 
+void invlpg(void *addr)
+{
+       asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
+       if (per_cpu_info[core_id()].vmx_enabled)
+               ept_inval_addr((uintptr_t)addr);
+}
+
+void tlbflush(void)
+{
+       unsigned long cr3;
+       asm volatile("mov %%cr3,%0" : "=r" (cr3));
+       asm volatile("mov %0,%%cr3" : : "r" (cr3));
+       if (per_cpu_info[core_id()].vmx_enabled)
+               ept_inval_context();
+}
+
 /* Flushes a TLB, including global pages.  We should always have the CR4_PGE
  * flag set, but just in case, we'll check.  Toggling this bit flushes the TLB.
  */
@@ -108,6 +124,9 @@ void tlb_flush_global(void)
        if (cr4 & CR4_PGE) {
                lcr4(cr4 & ~CR4_PGE);
                lcr4(cr4);
-       } else 
+       } else {
                lcr3(rcr3());
+       }
+       if (per_cpu_info[core_id()].vmx_enabled)
+               ept_inval_global();
 }
index 901a9af..d9a2dd8 100644 (file)
@@ -80,9 +80,11 @@ static kpte_t *kpte2pml(kpte_t kpte)
 static kpte_t *__pml_walk(kpte_t *pml, uintptr_t va, int flags, int pml_shift)
 {
        kpte_t *kpte;
+       epte_t *epte;
        void *new_pml_kva;
 
        kpte = &pml[PMLx(va, pml_shift)];
+       epte = kpte_to_epte(kpte);
        if (walk_is_complete(kpte, pml_shift, flags))
                return kpte;
        if (!(*kpte & PTE_P)) {
@@ -98,6 +100,14 @@ static kpte_t *__pml_walk(kpte_t *pml, uintptr_t va, int flags, int pml_shift)
                 * translation is !User).  We put the perms on the last entry, not the
                 * intermediates. */
                *kpte = PADDR(new_pml_kva) | PTE_P | PTE_U | PTE_W;
+               /* The physaddr of the new_pml is one page higher than the KPT page.  A
+                * few other things:
+                * - for the same reason that we have U and X set on all intermediate
+                * PTEs, we now set R, X, and W for the EPTE.
+                * - All EPTEs have U perms
+                * - We can't use epte_write since we're workin on intermediate PTEs,
+                * and they don't have the memory type set. */
+               *epte = (PADDR(new_pml_kva) + PGSIZE) | EPTE_R | EPTE_X | EPTE_W;
        }
        return __pml_walk(kpte2pml(*kpte), va, flags, pml_shift - BITS_PER_PML);
 }
index 78c05fb..8e7e574 100644 (file)
 #ifndef ROS_ARCH_PMAPS_OPS_H
 #define ROS_ARCH_PMAPS_OPS_H
 
+#include <arch/vmm/ept.h>
+#include <arch/kpt.h>
+
 /* TODO: (EPT)  build a CONFIG mode where we assert the EPT agrees with the KPT
  * for all of the read ops */
 
 static inline bool pte_walk_okay(pte_t pte)
 {
-       /* walk_okay should only be called after a walk, when we have both a KPTE
-        * and an EPTE */
-       dassert(pte.kpte ? TRUE : !pte.epte);
        return pte.kpte ? TRUE : FALSE;
 }
 
@@ -43,92 +43,69 @@ static inline bool pte_walk_okay(pte_t pte)
  *     - unmapped: completely unused. (0 value) */
 static inline bool pte_is_present(pte_t pte)
 {
-#if 0  /* could do some debuggin like this.  painful. */
-       bool ret_kpte, ret_epte;
-       assert(pte.kpte || pte.epte);
-       ret_kpte = pte.kpte ? (*pte.kpte & PTE_P ? TRUE : FALSE) : 0;
-       /* TODO: EPT check */
-       ret_epte = pte.epte ? (*pte.epte & PTE_P ? TRUE : FALSE) : 0;
-       if (pte.kpte && pte.epte)
-               assert(ret_kpte == ret_epte);
-       return pte.kpte ? ret_kpte : ret_epte;
-#endif
-       return pte.kpte ? (*pte.kpte & PTE_P ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_present(pte.kpte);
 }
 
 static inline bool pte_is_unmapped(pte_t pte)
 {
-       return pte.kpte ? PAGE_UNMAPPED(*pte.kpte)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_unmapped(pte.kpte);
 }
 
 static inline bool pte_is_mapped(pte_t pte)
 {
-       return pte.kpte ? !PAGE_UNMAPPED(*pte.kpte)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_mapped(pte.kpte);
 }
 
 static inline bool pte_is_paged_out(pte_t pte)
 {
-       return pte.kpte ? PAGE_PAGED_OUT(*pte.kpte)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_paged_out(pte.kpte);
 }
 
 static inline bool pte_is_dirty(pte_t pte)
 {
-       return pte.kpte ? (*pte.kpte & PTE_D ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_dirty(pte.kpte) ||
+              epte_is_dirty(kpte_to_epte(pte.kpte));
 }
 
 static inline bool pte_is_accessed(pte_t pte)
 {
-       return pte.kpte ? (*pte.kpte & PTE_A ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_accessed(pte.kpte) ||
+              epte_is_accessed(kpte_to_epte(pte.kpte));
 }
 
 /* Used in debugging code - want something better involving the walk */
 static inline bool pte_is_jumbo(pte_t pte)
 {
-       return pte.kpte ? (*pte.kpte & PTE_PS ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_is_jumbo(pte.kpte);
 }
 
 static inline physaddr_t pte_get_paddr(pte_t pte)
 {
-       return pte.kpte ? PTE_ADDR(*pte.kpte)
-                       : 0; /* TODO: EPT check */
+       return kpte_get_paddr(pte.kpte);
 }
 
 /* Returns the PTE in an unsigned long, for debugging mostly. */
 static inline unsigned long pte_print(pte_t pte)
 {
-       return pte.kpte ? *pte.kpte
-                       : 0; /* TODO: EPT check */
+       return kpte_print(pte.kpte);
 }
 
 static inline void pte_write(pte_t pte, physaddr_t pa, int perm)
 {
-       if (pte.kpte)
-               *pte.kpte = PTE(pa2ppn(pa), perm);
-       if (pte.epte)
-               /* TODO: EPT write (if EPT) */;
+       kpte_write(pte.kpte, pa, perm);
+       epte_write(kpte_to_epte(pte.kpte), pa, perm);
 }
 
 static inline void pte_clear_present(pte_t pte)
 {
-       if (pte.kpte)
-               *pte.kpte &= ~PTE_P;
-       if (pte.epte)
-               /* TODO: EPT write (if EPT) */;
+       kpte_clear_present(pte.kpte);
+       epte_clear_present(kpte_to_epte(pte.kpte));
 }
 
 static inline void pte_clear(pte_t pte)
 {
-       if (pte.kpte)
-               *pte.kpte = 0;
-       if (pte.epte)
-               /* TODO: EPT write (if EPT) */;
+       kpte_clear(pte.kpte);
+       epte_clear(kpte_to_epte(pte.kpte));
 }
 
 /* These are used by memcpy_*_user, but are very dangerous (and possibly used
@@ -139,30 +116,25 @@ static inline void pte_clear(pte_t pte)
  * to an intermediate PTE, we'd miss that. */
 static inline bool pte_has_perm_ur(pte_t pte)
 {
-       return pte.kpte ? (*pte.kpte & PTE_USER_RO ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_has_perm_ur(pte.kpte);
 }
 
 static inline bool pte_has_perm_urw(pte_t pte)
 {
-       return pte.kpte ? (*pte.kpte & PTE_USER_RW ? TRUE : FALSE)
-                       : 0; /* TODO: EPT check */
+       return kpte_has_perm_urw(pte.kpte);
 }
 
 /* return the arch-independent format for prots - whatever you'd expect to
  * receive for pte_write.  Careful with the ret, since a valid type is 0. */
 static inline int pte_get_perm(pte_t pte)
 {
-       return pte.kpte ? *pte.kpte & PTE_PERM
-                       : 0; /* TODO: EPT check */
+       return kpte_get_perm(pte.kpte);
 }
 
 static inline void pte_replace_perm(pte_t pte, int perm)
 {
-       if (pte.kpte)
-               *pte.kpte = (*pte.kpte & ~PTE_PERM) | perm;
-       if (pte.epte)
-               /* TODO: EPT write (if EPT) */;
+       kpte_replace_perm(pte.kpte, perm);
+       epte_replace_perm(kpte_to_epte(pte.kpte), perm);
 }
 
 #endif /* ROS_ARCH_PMAPS_OPS_H */
diff --git a/kern/arch/x86/vmm/ept.h b/kern/arch/x86/vmm/ept.h
new file mode 100644 (file)
index 0000000..b2d3da9
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (c) 2015 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * 64 bit EPT helpers */
+
+#ifndef ROS_ARCH_VMM_EPT_H
+#define ROS_ARCH_VMM_EPT_H
+
+#include <arch/vmm/intel/vmx.h>        /* for sync/flush helpers */
+#include <smp.h>                               /* for current */
+
+/* Some EPTE PTE flags are only valid for the last PTEs in a walk */
+#define EPTE_R                                 (1ULL << 0)             /* Readable */
+#define EPTE_W                                 (1ULL << 1)             /* Writeable */
+#define EPTE_X                                 (1ULL << 2)             /* Executable */
+#define EPTE_MEM_BITS                  (7ULL << 3)             /* Memory type specifier */
+#define EPTE_IGN_PAT                   (1ULL << 6)             /* Ignore PAT */
+#define EPTE_PS                                        (1ULL << 7)             /* Jumbo Page Size */
+#define EPTE_A                                 (1ULL << 8)             /* Accessed */
+#define EPTE_D                                 (1ULL << 9)             /* Dirty */
+#define EPTE_SUP_VE                            (1ULL << 63)    /* Suppress virt exceptions */
+#define EPTE_P (EPTE_R | EPTE_W | EPTE_X)
+
+/* Types available for the EPTE_MEM_TYPE */
+#define EPT_MEM_TYPE_UC                        0
+#define EPT_MEM_TYPE_WC                        1
+#define EPT_MEM_TYPE_WT                        4
+#define EPT_MEM_TYPE_WP                        5
+#define EPT_MEM_TYPE_WB                        6
+/* Helper to align the type to its location in the PTE */
+#define EPT_MEM_TYPE(type) ((type) << 3)
+
+/* Some machines don't support A and D EPTE bits.  We'll |= 1 in those cases. */
+extern int x86_ept_pte_fix_ups;
+
+static inline epte_t *kpte_to_epte(kpte_t *kpte)
+{
+       return (epte_t*)(((uintptr_t)kpte) + PGSIZE);
+}
+
+static inline bool epte_is_present(epte_t *epte)
+{
+       /* Actually, certain combos, like W but not R could be misconfigurations */
+       return *epte & EPTE_P ? TRUE : FALSE;
+}
+
+static inline bool epte_is_unmapped(epte_t *epte)
+{
+       return *epte == 0;
+}
+
+static inline bool epte_is_mapped(epte_t *epte)
+{
+       return *epte != 0;
+}
+
+static inline bool epte_is_paged_out(epte_t *epte)
+{
+       return *epte != 0;
+}
+
+/* Some Intel machines don't support A or D.  In these cases, we must assume
+ * the pages have been accessed or dirtied... */
+static inline bool epte_is_dirty(epte_t *epte)
+{
+       return (*epte | x86_ept_pte_fix_ups) & EPTE_D ? TRUE : FALSE;
+}
+
+static inline bool epte_is_accessed(epte_t *epte)
+{
+       return (*epte | x86_ept_pte_fix_ups) & EPTE_A ? TRUE : FALSE;
+}
+
+static inline bool epte_is_jumbo(epte_t *epte)
+{
+       return *epte & EPTE_PS ? TRUE : FALSE;
+}
+
+static inline physaddr_t epte_get_paddr(epte_t *epte)
+{
+       /* 63:52 are ignored/flags.  51:12 are the addr.  Technically 51:N must be
+        * 0, where N is the physical addr width */
+       return *epte & 0x000ffffffffff000;
+}
+
+static inline int __pte_to_epte_perm(int perm)
+{
+       switch (perm) {
+               /* Since we keep the EPT in lockstep with the KPT, we might get some
+                * mapping requests for the kernel (e.g. vmap_pmem).  */
+               case PTE_KERN_RW:
+               case PTE_KERN_RO:
+               case PTE_NONE:
+                       return 0;
+               case PTE_USER_RW:
+                       return EPTE_W | EPTE_R | EPTE_X;
+               case PTE_USER_RO:
+                       return EPTE_R | EPTE_X;
+               default:
+                       panic("Bad PTE type 0x%x\n", perm);
+       }
+}
+
+static inline void epte_write(epte_t *epte, physaddr_t pa, int settings)
+{
+       /* Could put in a check against the max physaddr len */
+       epte_t temp = pa;
+       temp |= __pte_to_epte_perm(settings & PTE_PERM);
+       temp |= settings & PTE_PS ? EPTE_PS : 0;
+       /* All memory is WB by default, but the guest can override that with their
+        * PAT on the first page walk (guest KPT/cr3) */
+       temp |= EPT_MEM_TYPE(EPT_MEM_TYPE_WB);
+       *epte = temp;
+}
+
+static inline void epte_clear_present(epte_t *epte)
+{
+       *epte &= ~EPTE_P;
+}
+
+static inline void epte_clear(epte_t *epte)
+{
+       *epte = 0;
+}
+
+static inline bool epte_has_perm_ur(epte_t *epte)
+{
+       return (*epte & (EPTE_R | EPTE_X)) == (EPTE_R | EPTE_X);
+}
+
+static inline bool epte_has_perm_urw(epte_t *epte)
+{
+       return (*epte & (EPTE_R | EPTE_W | EPTE_X)) == (EPTE_R | EPTE_W | EPTE_X);
+}
+
+/* We want to know User and Writable, in the 'PTE' sense.  All present epte
+ * entries are User PTEs. */
+static inline int epte_get_perm(epte_t *epte)
+{
+       int settings = 0;
+       if (*epte & EPTE_P) {
+               settings |= PTE_P | PTE_U;
+               settings |= *epte & EPTE_W ? PTE_W : 0;
+       }
+       //settings |= *epte & EPTE_PS ? PTE_PS : 0; /* TODO */
+       return settings;
+}
+
+/* Again, we're replacing the old perms with U and/or W.  Any non-U are ignored,
+ * as with epte_write.  R (and X) are implied. */
+static inline void epte_replace_perm(epte_t *epte, int settings)
+{
+       *epte = (*epte & ~EPTE_P) | __pte_to_epte_perm(settings & PTE_PERM);
+}
+
+/* These ops might be the same for AMD as Intel; in which case we can move the
+ * body of these ept_sync_* funcs into here */
+static inline void ept_inval_addr(unsigned long addr)
+{
+       if (current && current->vmm.vmmcp)
+               ept_sync_individual_addr(current->env_pgdir.eptp, addr);
+}
+
+static inline void ept_inval_context(void)
+{
+       if (current && current->vmm.vmmcp)
+               ept_sync_context(current->env_pgdir.eptp);
+}
+
+static inline void ept_inval_global(void)
+{
+       ept_sync_global();
+}
+
+#endif /* ROS_ARCH_VMM_EPT_H */
index a0f377a..152480f 100644 (file)
@@ -1,2 +1 @@
 obj-y                                          += vmx.o
-obj-y                                          += ept.o
diff --git a/kern/arch/x86/vmm/intel/ept.c b/kern/arch/x86/vmm/intel/ept.c
deleted file mode 100644 (file)
index 08ff585..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * ept.c - Support for Intel's Extended Page Tables
- *
- * Authors:
- *   Adam Belay <abelay@stanford.edu>
- *
- * Right now we support EPT by making a sort of 'shadow' copy of the Linux
- * process page table. In the future, a more invasive architecture port
- * to VMX x86 could provide better performance by eliminating the need for
- * two copies of each page table entry, relying instead on only the EPT
- * format.
- * 
- * This code is only a prototype and could benefit from a more comprehensive
- * review in terms of performance and correctness. Also, the implications
- * of threaded processes haven't been fully considered.
- *
- * Some of the low-level EPT functions are based on KVM.
- * Original Authors:
- *   Avi Kivity   <avi@qumranet.com>
- *   Yaniv Kamay  <yaniv@qumranet.com>
- */
-
-#include <kmalloc.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <error.h>
-#include <pmap.h>
-#include <sys/queue.h>
-#include <smp.h>
-#include <kref.h>
-#include <atomic.h>
-#include <alarm.h>
-#include <event.h>
-#include <umem.h>
-#include <bitops.h>
-#include <arch/types.h>
-#include <syscall.h>
-#include <monitor.h>
-
-#include "vmx.h"
-#include "../vmm.h"
-
-#include "cpufeature.h"
-
-#define EPT_LEVELS     4       /* 0 through 3 */
-#define HUGE_PAGE_SIZE 2097152
-#define PageHuge(x) (0)
-
-#define VMX_EPT_FAULT_READ     0x01
-#define VMX_EPT_FAULT_WRITE    0x02
-#define VMX_EPT_FAULT_INS      0x04
-
-typedef unsigned long epte_t;
-
-#define __EPTE_READ    0x01
-#define __EPTE_WRITE   0x02
-#define __EPTE_EXEC    0x04
-#define __EPTE_IPAT    0x40
-#define __EPTE_SZ      0x80
-#define __EPTE_TYPE(n) (((n) & 0x7) << 3)
-
-enum {
-       EPTE_TYPE_UC = 0, /* uncachable */
-       EPTE_TYPE_WC = 1, /* write combining */
-       EPTE_TYPE_WT = 4, /* write through */
-       EPTE_TYPE_WP = 5, /* write protected */
-       EPTE_TYPE_WB = 6, /* write back */
-};
-
-#define __EPTE_NONE    0
-#define __EPTE_FULL    (__EPTE_READ | __EPTE_WRITE | __EPTE_EXEC)
-
-#define EPTE_ADDR      (~(PAGE_SIZE - 1))
-#define EPTE_FLAGS     (PAGE_SIZE - 1)
-
-static inline uintptr_t epte_addr(epte_t epte)
-{
-       return (epte & EPTE_ADDR);
-}
-
-static inline uintptr_t epte_page_vaddr(epte_t epte)
-{
-       return (uintptr_t) KADDR(epte_addr(epte));
-}
-
-static inline epte_t epte_flags(epte_t epte)
-{
-       return (epte & EPTE_FLAGS);
-}
-
-static inline int epte_present(epte_t epte)
-{
-       return (epte & __EPTE_FULL) > 0;
-}
-
-static inline int epte_big(epte_t epte)
-{
-       return (epte & __EPTE_SZ) > 0;
-}
-
-#define ADDR_TO_IDX(la, n) \
-       ((((unsigned long) (la)) >> (12 + 9 * (n))) & ((1 << 9) - 1))
-
-/* for now we assume in 'current' */
-static int
-ept_lookup_gpa(epte_t *dir, void *gpa, int level, int create, epte_t **epte_out)
-{
-       int i;
-
-       for (i = EPT_LEVELS - 1; i > level; i--) {
-               int idx = ADDR_TO_IDX(gpa, i);
-               printk("%d: gpa %p, idx %p\n", i, gpa, idx);
-               if (!epte_present(dir[idx])) {
-                       printk("not present\n");
-                       void *page;
-
-                       if (!create)
-                               return -ENOENT;
-
-                       page = (void *) kpage_zalloc_addr();
-                       if (!page)
-                               return -ENOMEM;
-                       printk("page %p\n", page);
-                       dir[idx] = epte_addr(PADDR(page)) |
-                                  __EPTE_FULL;
-                       printk("Set %p[%p] to %p\n", dir, idx, dir[idx]);
-               }
-
-               if (epte_big(dir[idx])) {
-                       if (i != 1)
-                               return -EINVAL;
-                       level = i;
-                       break;
-               }
-
-               dir = (epte_t *) epte_page_vaddr(dir[idx]);
-               printk("Dir for next pass: %p\n", dir);
-       }
-
-       *epte_out = &dir[ADDR_TO_IDX(gpa, level)];
-       printk("Final ept is %p\n", *epte_out);
-       return 0;
-}
-
-static void free_ept_page(epte_t epte)
-{
-       // TODO: clean this up. 
-       void *page = KADDR(epte & ~0xfff);
-       //struct page *page = pfn_to_page(epte_addr(epte) >> PAGE_SHIFT);
-
-       kfree(page);
-}
-
-static void vmx_free_ept(unsigned long ept_root)
-{
-       epte_t *pgd = (epte_t *) KADDR(ept_root);
-       int i, j, k, l;
-
-       // TODO: change all instances of 512 to something.
-       for (i = 0; i < 512; i++) {
-               epte_t *pud = (epte_t *) epte_page_vaddr(pgd[i]);
-               if (!epte_present(pgd[i]))
-                       continue;
-
-               for (j = 0; j < 512; j++) {
-                       epte_t *pmd = (epte_t *) epte_page_vaddr(pud[j]);
-                       if (!epte_present(pud[j]))
-                               continue;
-                       if (epte_flags(pud[j]) & __EPTE_SZ)
-                               continue;
-
-                       for (k = 0; k < 512; k++) {
-                               epte_t *pte = (epte_t *) epte_page_vaddr(pmd[k]);
-                               if (!epte_present(pmd[k]))
-                                       continue;
-                               if (epte_flags(pmd[k]) & __EPTE_SZ) {
-                                       free_ept_page(pmd[k]);
-                                       continue;
-                               }
-
-                               for (l = 0; l < 512; l++) {
-                                       if (!epte_present(pte[l]))
-                                               continue;
-
-                                       free_ept_page(pte[l]);
-                               }
-
-                               kfree(pte);
-                       }
-
-                       kfree(pmd);
-               }
-
-               kfree(pud);
-       }
-
-       kfree(pgd);
-}
-
-static int ept_clear_epte(epte_t *epte)
-{
-       if (*epte == __EPTE_NONE)
-               return 0;
-
-       free_ept_page(*epte);
-       *epte = __EPTE_NONE;
-
-       return 1;
-}
-
-/* We're given a guest physical and a host physical. */
-static int ept_set_epte(epte_t *dir, int make_write, unsigned long gpa, unsigned long hpa)
-{
-       int ret = -1;
-       epte_t *epte, flags;
-       struct page *page = NULL;
-
-       // We're going to assume locking is done by this point.
-       // TODO: PageHuge
-
-       ret = ept_lookup_gpa(dir, (void *) gpa, PageHuge(page) ? 1 : 0, 1, &epte);
-       if (ret) {
-               printk("ept: failed to lookup EPT entry\n");
-               return ret;
-       }
-
-       printk("=====================> epte %p is %p\n", epte, *epte);
-       if (epte_present(*epte) && (epte_big(*epte) || !PageHuge(page))) {
-               printk("PRESENT? WTF? OK ...\n");
-               monitor(NULL);
-               //ept_clear_epte(epte);
-       } else {
-               flags = __EPTE_READ | __EPTE_EXEC | __EPTE_WRITE |
-                       __EPTE_TYPE(EPTE_TYPE_WB) | __EPTE_IPAT;
-               if (make_write)
-                       flags |= __EPTE_WRITE;
-               
-               /* TODO: fix thishuge page shit.*/
-               if (PageHuge(page)) {
-                       flags |= __EPTE_SZ;
-                       if (epte_present(*epte) && !epte_big(*epte)){
-                               panic("free huge page?");
-                               //free_page(epte_page_vaddr(*epte));
-                       }
-                       /* FIXME: free L0 entries too */
-                       *epte = epte_addr(PADDR(page) & ~((1 << 21) - 1)) |
-                               flags;
-               } else {
-                       *epte = epte_addr(hpa) | flags;
-                       printk("Set epte to %p\n", *epte);
-               }
-       }
-       return 0;
-}
-
-// TODO: kill this? 
-// NOTE: guest physical is 1:1 mapped to host virtual. This is NOT 
-// like dune at all.
-int vmx_do_ept_fault(void *dir, unsigned long gpa, unsigned long hpa, int fault_flags)
-{
-       int ret;
-       int make_write = (fault_flags & VMX_EPT_FAULT_WRITE) ? 1 : 0;
-
-       printk("ept: GPA: 0x%lx, GVA: 0x%lx, flags: %x\n",
-                gpa, hpa, fault_flags);
-
-       ret = ept_set_epte((epte_t *)dir, make_write, gpa, hpa);
-
-       return ret;
-}
-
-/*
- * ept_fault_pages pre-faults pages in the range start..end
- */
-int ept_fault_pages(void *dir, uint32_t start, uint32_t end)
-{
-       uint64_t i;
-       int ret;
-       for(i = start; i < end; i++) {
-               uint64_t addr = i << 12;
-               ret = vmx_do_ept_fault((epte_t*)dir, i, i, VMX_EPT_FAULT_WRITE);
-               if (ret) {
-                       return ret;
-               }
-       }
-       return 0;
-}
-/**
- * ept_invalidate_page - removes a page from the EPT
- * @vcpu: the vcpu
- * @mm: the process's mm_struct
- * @addr: the address of the page
- * 
- * Returns 1 if the page was removed, 0 otherwise
- */
-static int ept_invalidate_page(epte_t *dir, unsigned long addr)
-{
-       int ret;
-       epte_t *epte;
-       void *gpa = (void *) addr;
-
-       ret = ept_lookup_gpa(dir, (void *) gpa, 0, 0, &epte);
-       if (ret) {
-               return 0;
-       }
-
-       ret = ept_clear_epte(epte);
-
-       /* TODO: sync individual?
-       if (ret)
-               vmx_ept_sync_individual_addr(vcpu, (gpa_t) gpa);
-       */
-
-       return ret;
-}
-
-/**
- * ept_check_page - determines if a page is mapped in the ept
- * @vcpu: the vcpu
- * @mm: the process's mm_struct
- * @addr: the address of the page
- * 
- * Returns 1 if the page is mapped, 0 otherwise
- */
-int ept_check_page(void *dir, unsigned long addr)
-{
-       int ret;
-       epte_t *epte;
-       void *gpa = (void *) addr;
-
-       ret = ept_lookup_gpa((epte_t *)dir, gpa, 0, 0, &epte);
-
-       return ret;
-}
index 25bd9be..ef0bb45 100644 (file)
@@ -173,6 +173,8 @@ static const uint32_t vmx_msr_index[] = {
 
 static unsigned long *msr_bitmap;
 
+int x86_ept_pte_fix_ups = 0;
+
 struct vmx_capability vmx_capability;
 struct vmcs_config vmcs_config;
 
@@ -654,67 +656,6 @@ static void vmx_put_cpu(struct vmx_vcpu *vcpu)
        //put_cpu();
 }
 
-static void __vmx_sync_helper(struct hw_trapframe *hw_tf, void *ptr)
-{
-       struct vmx_vcpu *vcpu = ptr;
-
-       ept_sync_context(vcpu_get_eptp(vcpu));
-}
-
-struct sync_addr_args {
-       struct vmx_vcpu *vcpu;
-       gpa_t gpa;
-};
-
-static void __vmx_sync_individual_addr_helper(struct hw_trapframe *hw_tf, void *ptr)
-{
-       struct sync_addr_args *args = ptr;
-
-//     ept_sync_individual_addr(
-
-}
-
-/**
- * vmx_ept_sync_global - used to evict everything in the EPT
- * @vcpu: the vcpu
- */
-void vmx_ept_sync_vcpu(struct vmx_vcpu *vcpu)
-{
-       handler_wrapper_t *w;
-
-       smp_call_function_single(vcpu->cpu,
-               __vmx_sync_helper, (void *) vcpu, &w);
-
-       if (smp_call_wait(w)) {
-               printk("litevm_init. smp_call_wait failed. Expect a panic.\n");
-       }
-
-
-}
-
-/**
- * vmx_ept_sync_individual_addr - used to evict an individual address
- * @vcpu: the vcpu
- * @gpa: the guest-physical address
- */
-void vmx_ept_sync_individual_addr(struct vmx_vcpu *vcpu, gpa_t gpa)
-{
-       struct sync_addr_args args;
-       args.vcpu = vcpu;
-       args.gpa = gpa;
-
-       handler_wrapper_t *w;
-
-
-       smp_call_function_single(vcpu->cpu,
-                                __vmx_sync_individual_addr_helper, (void *) &args, &w);
-
-       if (smp_call_wait(w)) {
-               printk("litevm_init. smp_call_wait failed. Expect a panic.\n");
-       }
-
-}
-
 /**
  * vmx_dump_cpu - prints the CPU state
  * @vcpu: VCPU to print
@@ -1212,7 +1153,7 @@ static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu)
        if (page) {
                uint64_t hpa = page2pa(page);
                printk("hpa for %p is %p\n", gpa, hpa);
-               ret = vmx_do_ept_fault(vcpu->proc->env_pgdir.epte, gpa, hpa, exit_qual);
+               ret = -1;
                printk("vmx_do_ept_fault returns %d\n", ret);
        }
 
@@ -1531,7 +1472,7 @@ static int ept_init(void)
        }
        if (!cpu_has_vmx_ept_ad_bits()) {
                printk("VMX EPT doesn't support accessed/dirty!\n");
-               /* TODO: set the pmap_ops accordingly */
+               x86_ept_pte_fix_ups |= EPTE_A | EPTE_D;
        }
        if (!cpu_has_vmx_invept() || !cpu_has_vmx_invept_global()) {
                printk("VMX EPT can't invalidate PTEs/TLBs!\n");
index d329d19..c69168d 100644 (file)
@@ -502,6 +502,9 @@ enum shutdown_reason {
 
 #define VMX_EPT_IDENTITY_PAGETABLE_ADDR                0xfffbc000ul
 
+#define VMX_EPT_FAULT_READ     0x01
+#define VMX_EPT_FAULT_WRITE    0x02
+#define VMX_EPT_FAULT_INS      0x04
 
 #define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
 #define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"