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