Pmap ops: perm->settings
[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 static inline int epte_get_settings(epte_t *epte)
138 {
139         int settings = 0;
140         if (*epte & EPTE_P) {
141                 /* We want to know User and Writable, in the 'PTE' sense.  All present
142                  * epte entries are User PTEs. */
143                 settings |= PTE_P | PTE_U;
144                 settings |= *epte & EPTE_W ? PTE_W : 0;
145         }
146         settings |= *epte & EPTE_PS ? PTE_PS : 0;
147         settings |= *epte & EPTE_A ? PTE_A : 0;
148         settings |= *epte & EPTE_D ? PTE_D : 0;
149         return settings;
150 }
151
152 /* Again, we're replacing the old perms with U and/or W.  Any non-U are ignored,
153  * as with epte_write.  */
154 static inline void epte_replace_perm(epte_t *epte, int perm)
155 {
156         *epte = (*epte & ~EPTE_P) | __pte_to_epte_perm(perm & PTE_PERM);
157 }
158
159 /* These ops might be the same for AMD as Intel; in which case we can move the
160  * body of these ept_sync_* funcs into here */
161 static inline void ept_inval_addr(unsigned long addr)
162 {
163         if (current && current->vmm.vmmcp)
164                 ept_sync_individual_addr(current->env_pgdir.eptp, addr);
165 }
166
167 static inline void ept_inval_context(void)
168 {
169         if (current && current->vmm.vmmcp)
170                 ept_sync_context(current->env_pgdir.eptp);
171 }
172
173 static inline void ept_inval_global(void)
174 {
175         ept_sync_global();
176 }
177
178 #endif /* ROS_ARCH_VMM_EPT_H */