VMM: Call EPT ops for every KPT op
[akaros.git] / kern / arch / x86 / vmm / ept.h
1 /* Copyright (c) 2015 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * 64 bit EPT helpers */
6
7 #ifndef ROS_ARCH_VMM_EPT_H
8 #define ROS_ARCH_VMM_EPT_H
9
10 #include <arch/vmm/intel/vmx.h> /* for sync/flush helpers */
11 #include <smp.h>                                /* for current */
12
13 /* Some EPTE PTE flags are only valid for the last PTEs in a walk */
14 #define EPTE_R                                  (1ULL << 0)             /* Readable */
15 #define EPTE_W                                  (1ULL << 1)             /* Writeable */
16 #define EPTE_X                                  (1ULL << 2)             /* Executable */
17 #define EPTE_MEM_BITS                   (7ULL << 3)             /* Memory type specifier */
18 #define EPTE_IGN_PAT                    (1ULL << 6)             /* Ignore PAT */
19 #define EPTE_PS                                 (1ULL << 7)             /* Jumbo Page Size */
20 #define EPTE_A                                  (1ULL << 8)             /* Accessed */
21 #define EPTE_D                                  (1ULL << 9)             /* Dirty */
22 #define EPTE_SUP_VE                             (1ULL << 63)    /* Suppress virt exceptions */
23 #define EPTE_P (EPTE_R | EPTE_W | EPTE_X)
24
25 /* Types available for the EPTE_MEM_TYPE */
26 #define EPT_MEM_TYPE_UC                 0
27 #define EPT_MEM_TYPE_WC                 1
28 #define EPT_MEM_TYPE_WT                 4
29 #define EPT_MEM_TYPE_WP                 5
30 #define EPT_MEM_TYPE_WB                 6
31 /* Helper to align the type to its location in the PTE */
32 #define EPT_MEM_TYPE(type) ((type) << 3)
33
34 /* Some machines don't support A and D EPTE bits.  We'll |= 1 in those cases. */
35 extern int x86_ept_pte_fix_ups;
36
37 static inline epte_t *kpte_to_epte(kpte_t *kpte)
38 {
39         return (epte_t*)(((uintptr_t)kpte) + PGSIZE);
40 }
41
42 static inline bool epte_is_present(epte_t *epte)
43 {
44         /* Actually, certain combos, like W but not R could be misconfigurations */
45         return *epte & EPTE_P ? TRUE : FALSE;
46 }
47
48 static inline bool epte_is_unmapped(epte_t *epte)
49 {
50         return *epte == 0;
51 }
52
53 static inline bool epte_is_mapped(epte_t *epte)
54 {
55         return *epte != 0;
56 }
57
58 static inline bool epte_is_paged_out(epte_t *epte)
59 {
60         return *epte != 0;
61 }
62
63 /* Some Intel machines don't support A or D.  In these cases, we must assume
64  * the pages have been accessed or dirtied... */
65 static inline bool epte_is_dirty(epte_t *epte)
66 {
67         return (*epte | x86_ept_pte_fix_ups) & EPTE_D ? TRUE : FALSE;
68 }
69
70 static inline bool epte_is_accessed(epte_t *epte)
71 {
72         return (*epte | x86_ept_pte_fix_ups) & EPTE_A ? TRUE : FALSE;
73 }
74
75 static inline bool epte_is_jumbo(epte_t *epte)
76 {
77         return *epte & EPTE_PS ? TRUE : FALSE;
78 }
79
80 static inline physaddr_t epte_get_paddr(epte_t *epte)
81 {
82         /* 63:52 are ignored/flags.  51:12 are the addr.  Technically 51:N must be
83          * 0, where N is the physical addr width */
84         return *epte & 0x000ffffffffff000;
85 }
86
87 static inline int __pte_to_epte_perm(int perm)
88 {
89         switch (perm) {
90                 /* Since we keep the EPT in lockstep with the KPT, we might get some
91                  * mapping requests for the kernel (e.g. vmap_pmem).  */
92                 case PTE_KERN_RW:
93                 case PTE_KERN_RO:
94                 case PTE_NONE:
95                         return 0;
96                 case PTE_USER_RW:
97                         return EPTE_W | EPTE_R | EPTE_X;
98                 case PTE_USER_RO:
99                         return EPTE_R | EPTE_X;
100                 default:
101                         panic("Bad PTE type 0x%x\n", perm);
102         }
103 }
104
105 static inline void epte_write(epte_t *epte, physaddr_t pa, int settings)
106 {
107         /* Could put in a check against the max physaddr len */
108         epte_t temp = pa;
109         temp |= __pte_to_epte_perm(settings & PTE_PERM);
110         temp |= settings & PTE_PS ? EPTE_PS : 0;
111         /* All memory is WB by default, but the guest can override that with their
112          * PAT on the first page walk (guest KPT/cr3) */
113         temp |= EPT_MEM_TYPE(EPT_MEM_TYPE_WB);
114         *epte = temp;
115 }
116
117 static inline void epte_clear_present(epte_t *epte)
118 {
119         *epte &= ~EPTE_P;
120 }
121
122 static inline void epte_clear(epte_t *epte)
123 {
124         *epte = 0;
125 }
126
127 static inline bool epte_has_perm_ur(epte_t *epte)
128 {
129         return (*epte & (EPTE_R | EPTE_X)) == (EPTE_R | EPTE_X);
130 }
131
132 static inline bool epte_has_perm_urw(epte_t *epte)
133 {
134         return (*epte & (EPTE_R | EPTE_W | EPTE_X)) == (EPTE_R | EPTE_W | EPTE_X);
135 }
136
137 /* We want to know User and Writable, in the 'PTE' sense.  All present epte
138  * entries are User PTEs. */
139 static inline int epte_get_perm(epte_t *epte)
140 {
141         int settings = 0;
142         if (*epte & EPTE_P) {
143                 settings |= PTE_P | PTE_U;
144                 settings |= *epte & EPTE_W ? PTE_W : 0;
145         }
146         //settings |= *epte & EPTE_PS ? PTE_PS : 0; /* TODO */
147         return settings;
148 }
149
150 /* Again, we're replacing the old perms with U and/or W.  Any non-U are ignored,
151  * as with epte_write.  R (and X) are implied. */
152 static inline void epte_replace_perm(epte_t *epte, int settings)
153 {
154         *epte = (*epte & ~EPTE_P) | __pte_to_epte_perm(settings & PTE_PERM);
155 }
156
157 /* These ops might be the same for AMD as Intel; in which case we can move the
158  * body of these ept_sync_* funcs into here */
159 static inline void ept_inval_addr(unsigned long addr)
160 {
161         if (current && current->vmm.vmmcp)
162                 ept_sync_individual_addr(current->env_pgdir.eptp, addr);
163 }
164
165 static inline void ept_inval_context(void)
166 {
167         if (current && current->vmm.vmmcp)
168                 ept_sync_context(current->env_pgdir.eptp);
169 }
170
171 static inline void ept_inval_global(void)
172 {
173         ept_sync_global();
174 }
175
176 #endif /* ROS_ARCH_VMM_EPT_H */