Merge large page support code.
[barrelfish] / kernel / include / target / x86_64 / paging_kernel_target.h
1 /**
2  * \file
3  * \brief x86-64 kernel page-table structures.
4  */
5
6 /*
7  * Copyright (c) 2007-2013 ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #ifndef KERNEL_TARGET_X86_64_PAGING_H
16 #define KERNEL_TARGET_X86_64_PAGING_H
17
18 #include <capabilities.h>
19 #include <barrelfish_kpi/paging_arch.h>
20
21 // Functions defined elsewhere. Move the declerations to appropriate includes
22 int paging_x86_64_map_memory(lpaddr_t base, size_t size);
23 lvaddr_t paging_x86_64_map_device(lpaddr_t base, size_t size);
24 void paging_x86_64_reset(void);
25 void paging_x86_64_make_good_pml4(lpaddr_t base);
26
27 /// All flags valid for page access protection from user-space
28 #define X86_64_PTABLE_ACCESS_MASK \
29     (X86_64_PTABLE_EXECUTE_DISABLE | X86_64_PTABLE_USER_SUPERVISOR | \
30      X86_64_PTABLE_READ_WRITE)
31
32 /// All arch-specific flags valid to be set from user-space
33 #ifdef __k1om__
34 #define X86_64_PTABLE_FLAGS_MASK                                        \
35     (X86_64_PTABLE_ATTR_INDEX | X86_64_PTABLE_DIRTY |                   \
36      X86_64_PTABLE_ACCESSED | X86_64_PTABLE_CACHE_DISABLED |            \
37      X86_64_PTABLE_WRITE_THROUGH)
38 #else
39 #define X86_64_PTABLE_FLAGS_MASK                                        \
40     (X86_64_PTABLE_GLOBAL_PAGE | X86_64_PTABLE_ATTR_INDEX |             \
41      X86_64_PTABLE_DIRTY | X86_64_PTABLE_ACCESSED |                     \
42      X86_64_PTABLE_CACHE_DISABLED | X86_64_PTABLE_WRITE_THROUGH)
43 #endif
44
45 /// Mask out all arch-specific flags except those valid from user-space
46 #define X86_64_PTABLE_FLAGS(flags)     (flags & X86_64_PTABLE_FLAGS_MASK)
47
48 /// Mask out all flags except those for access protection
49 #define X86_64_PTABLE_ACCESS(flags)    (flags & X86_64_PTABLE_ACCESS_MASK)
50
51 /** True if page entry is present in memory */
52 #define X86_64_IS_PRESENT(entry)                        \
53     ((*(uint64_t *)(entry)) & X86_64_PTABLE_PRESENT)
54
55 /**
56  * A page directory entry.
57  */
58 union x86_64_pdir_entry {
59     uint64_t raw;
60     struct {
61         uint64_t        present         :1;
62         uint64_t        read_write      :1;
63         uint64_t        user_supervisor :1;
64         uint64_t        write_through   :1;
65         uint64_t        cache_disabled  :1;
66         uint64_t        accessed        :1;
67         uint64_t        reserved        :3;
68         uint64_t        available       :3;
69         uint64_t        base_addr       :28;
70         uint64_t        reserved2       :12;
71         uint64_t        available2      :11;
72         uint64_t        execute_disable :1;
73     } d;
74 };
75
76 #ifdef __k1om__
77 #define X86_64_PHYSADDR_BITS X1OM_PADDR_SPACE_BITS // TODO: Take that from offsets target
78 #else
79 #define X86_64_PHYSADDR_BITS X86_64_PADDR_SPACE_BITS
80 #endif
81 #define X86_64_PAGING_ENTRY_SIZE 64
82 #define X86_64_PAGING_AVAIL2_BITS 11
83 #define X86_64_PAGING_FLAG_BITS 12
84 #define X86_64_PAGING_LARGE_FLAGE_BITS 21
85 #define X86_64_PAGING_RESERVED_BITS \
86                 (X86_64_PAGING_ENTRY_SIZE - X86_64_PHYSADDR_BITS - \
87                  X86_64_PAGING_AVAIL2_BITS - 1)
88 #define X86_64_PAGING_LARGE_BASE_BITS \
89                 (X86_64_PHYSADDR_BITS - X86_64_PAGING_LARGE_FLAGE_BITS)
90 #define X86_64_PAGING_BASE_BASE_BITS \
91                 (X86_64_PHYSADDR_BITS - X86_64_PAGING_FLAG_BITS)
92
93
94 /**
95  * A page table entry.
96  */
97 union x86_64_ptable_entry {
98     uint64_t raw;
99     struct {
100         uint64_t        present         :1;
101         uint64_t        read_write      :1;
102         uint64_t        user_supervisor :1;
103         uint64_t        write_through   :1;
104         uint64_t        cache_disabled  :1;
105         uint64_t        accessed        :1;
106         uint64_t        dirty           :1;
107         uint64_t        always1         :1;
108         uint64_t        global          :1;
109         uint64_t        available       :3;
110         uint64_t        attr_index      :1;
111         uint64_t        reserved        :17;
112         uint64_t        base_addr       :10;
113         uint64_t        reserved2       :12;
114         uint64_t        available2      :11;
115         uint64_t        execute_disable :1;
116     } huge;
117     struct {
118         uint64_t        present         :1;
119         uint64_t        read_write      :1;
120         uint64_t        user_supervisor :1;
121         uint64_t        write_through   :1;
122         uint64_t        cache_disabled  :1;
123         uint64_t        accessed        :1;
124         uint64_t        dirty           :1;
125         uint64_t        always1         :1;
126         uint64_t        global          :1;
127         uint64_t        available       :3;
128         uint64_t        attr_index      :1;
129         uint64_t        reserved        :8;
130         uint64_t        base_addr       :X86_64_PAGING_LARGE_BASE_BITS;
131         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
132         uint64_t        available2      :11;
133         uint64_t        execute_disable :1;
134     } large;
135     struct {
136         uint64_t        present         :1;
137         uint64_t        read_write      :1;
138         uint64_t        user_supervisor :1;
139         uint64_t        write_through   :1;
140         uint64_t        cache_disabled  :1;
141         uint64_t        accessed        :1;
142         uint64_t        dirty           :1;
143         uint64_t        attr_index      :1;
144         uint64_t        global          :1;
145         uint64_t        available       :3;
146         uint64_t        base_addr       :X86_64_PAGING_BASE_BASE_BITS;
147         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
148         uint64_t        available2      :11;
149         uint64_t        execute_disable :1;
150     } base;
151 };
152
153 STATIC_ASSERT_SIZEOF(union x86_64_ptable_entry, (X86_64_PAGING_ENTRY_SIZE / 8));
154
155 /**
156  * \brief Clear page directory.
157  *
158  * Clears page directory pointed to by 'p'.
159  *
160  * \param p     Pointer to page directory to clear.
161  */
162 static inline void paging_x86_64_clear_pdir(union x86_64_pdir_entry * COUNT(X86_64_PTABLE_SIZE)
163                                             NONNULL p)
164 {
165     for (int i = 0; i < X86_64_PTABLE_SIZE; i++) {
166         p[i].raw = X86_64_PTABLE_CLEAR;
167     }
168 }
169
170 /**
171  * \brief Clear page table.
172  *
173  * Clears page table pointed to by 'p'.
174  *
175  * \param p     Pointer to page table to clear.
176  */
177 static inline void paging_x86_64_clear_ptable(union x86_64_ptable_entry * COUNT(X86_64_PTABLE_SIZE)
178                                               NONNULL p)
179 {
180     for (int i = 0; i < X86_64_PTABLE_SIZE; i++) {
181         p[i].raw = X86_64_PTABLE_CLEAR;
182     }
183 }
184
185 /**
186  * \brief Maps from page directory entry to page directory/table.
187  *
188  * Maps page directory or table, based at 'base', from page directory entry
189  * pointed to by 'entry'.
190  *
191  * \param entry Pointer to page directory entry to point from.
192  * \param base  Base virtual address of page directory/table to point to.
193  */
194 static inline void paging_x86_64_map_table(union x86_64_pdir_entry *entry,
195                                            lpaddr_t base)
196 {
197     union x86_64_pdir_entry tmp;
198     tmp.raw = X86_64_PTABLE_CLEAR;
199
200     tmp.d.present = 1;
201     tmp.d.read_write = 1;
202     tmp.d.user_supervisor = 1;
203     tmp.d.base_addr = base >> 12;
204
205     *entry = tmp;
206 }
207
208 /**
209  * \brief Maps a huge page.
210  *
211  * From huge page table entry, pointed to by 'entry', maps physical address
212  * 'base' with page attribute bitmap 'bitmap'.
213  *
214  * \param entry         Pointer to page table entry to map from.
215  * \param base          Physical address to map to (will be page-aligned).
216  * \param bitmap        Bitmap to apply to page attributes.
217  */
218 static inline void paging_x86_64_map_huge(union x86_64_ptable_entry *entry,
219                                            lpaddr_t base, uint64_t bitmap)
220 {
221     union x86_64_ptable_entry tmp;
222     tmp.raw = X86_64_PTABLE_CLEAR;
223
224     tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
225     tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
226     tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
227     tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
228     tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
229     tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
230     tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
231     tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
232     tmp.huge.always1 = 1;
233     tmp.huge.base_addr = base >> X86_64_HUGE_PAGE_BITS;
234     
235     *entry = tmp;
236 }
237
238 /**
239  * \brief Maps a large page.
240  *
241  * From large page table entry, pointed to by 'entry', maps physical address
242  * 'base' with page attribute bitmap 'bitmap'.
243  *
244  * \param entry         Pointer to page table entry to map from.
245  * \param base          Physical address to map to (will be page-aligned).
246  * \param bitmap        Bitmap to apply to page attributes.
247  */
248 static inline void paging_x86_64_map_large(union x86_64_ptable_entry *entry,
249                                            lpaddr_t base, uint64_t bitmap)
250 {
251     union x86_64_ptable_entry tmp;
252     tmp.raw = X86_64_PTABLE_CLEAR;
253
254     tmp.large.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
255     tmp.large.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
256     tmp.large.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
257     tmp.large.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
258     tmp.large.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
259 #ifdef __k1om__
260         /* The Xeon Phi has no support for global pages */
261         tmp.large.global = 0;
262 #else
263     tmp.large.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
264 #endif
265     tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
266     tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
267     tmp.large.always1 = 1;
268     tmp.large.base_addr = base >> 21;
269     
270     *entry = tmp;
271 }
272
273 /**
274  * \brief Maps a normal (small) page.
275  *
276  * From small page table entry, pointed to by 'entry', maps physical address
277  * 'base' with page attribute bitmap 'bitmap'.
278  *
279  * \param entry         Pointer to page table entry to map from.
280  * \param base          Physical address to map to (will be page-aligned).
281  * \param bitmap        Bitmap to apply to page attributes.
282  */
283 static inline void paging_x86_64_map(union x86_64_ptable_entry * NONNULL entry,
284                                      lpaddr_t base, uint64_t bitmap)
285 {
286     union x86_64_ptable_entry tmp;
287     tmp.raw = X86_64_PTABLE_CLEAR;
288
289     tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
290     tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
291     tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
292     tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
293     tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
294     tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
295 #ifdef __k1om__
296         /* The Xeon Phi has no support for global pages */
297         tmp.base.global = 0;
298 #else
299     tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
300 #endif
301     tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
302     tmp.base.base_addr = base >> 12;
303
304     *entry = tmp;
305 }
306
307 /**
308  * \brief Modify flags of a normal (small) page.
309  *
310  * From small page table entry, pointed to by 'entry', maps physical address
311  * 'base' with page attribute bitmap 'bitmap'.
312  *
313  * \param entry         Pointer to page table entry to map from.
314  * \param bitmap        Bitmap to apply to page attributes.
315  */
316 static inline void paging_x86_64_modify_flags(union x86_64_ptable_entry * NONNULL entry,
317                                               uint64_t bitmap)
318 {
319     union x86_64_ptable_entry tmp = *entry;
320
321     tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
322     tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
323     tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
324     tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
325     tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
326     tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
327 #ifdef __k1om__
328         /* XXX: The Xeon Phi does no support global pages */
329         tmp.base.global =  0;
330 #else
331     tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
332 #endif
333     tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
334
335     *entry = tmp;
336 }
337
338 static inline void paging_unmap(union x86_64_ptable_entry * NONNULL entry)
339 {
340     entry->raw = X86_64_PTABLE_CLEAR;
341 }
342
343 /**
344  * \brief Convert Capability access rights to X86-64 page flags.
345  *
346  * Returns corresponding X86-64 page flags to given capability access rights
347  * mask 'rights'.
348  *
349  * \param rights        Capability rightsmask.
350  *
351  * \return X86-64 page flags.
352  */
353 static inline uint64_t paging_x86_64_cap_to_page_flags(CapRights rights)
354 {
355     uint64_t pageflags = 0;
356
357     // Sanity-check given flags
358     if(!(rights & CAPRIGHTS_READ) &&
359        (rights & CAPRIGHTS_WRITE || rights & CAPRIGHTS_EXECUTE)) {
360         printk(LOG_ERR, "Page mapped writable and/or executable, but not "
361                "readable. Impossible on X86! Will map non-everything "
362                "instead.\n");
363     }
364
365     // Convert flags
366     pageflags |= rights & CAPRIGHTS_READ ? X86_64_PTABLE_USER_SUPERVISOR : 0;
367     pageflags |= rights & CAPRIGHTS_WRITE ? X86_64_PTABLE_READ_WRITE : 0;
368     pageflags |= rights & CAPRIGHTS_EXECUTE ? 0 : X86_64_PTABLE_EXECUTE_DISABLE;
369
370     return pageflags;
371 }
372
373 /**
374  * \brief Switch context.
375  *
376  * Assigns given physical base address of PML4 'pml4' to the CR3
377  * register, effectively switching context to new address space. Be
378  * cautious that you only switch to "good" (as explained in
379  * paging_make_good_pml4()) PML4s!
380  *
381  * \param pml4  Physical base address of PML4 table.
382  */
383 static void inline paging_x86_64_context_switch(lpaddr_t pml4)
384 {
385     __asm volatile("mov %[pml4], %%cr3"
386                    : /* No output */
387                    :
388                    [pml4] "r" (pml4)
389                    );
390 }
391
392 /**
393  * \brief Mask out page attributes.
394  *
395  * Masks out all attributes and access rights from 'attr' according to
396  * 'mask'. This is architecture-specific. On x86-64, except for the
397  * execute disable attribute, rights are given by setting a
398  * corresponding bit. Thus, setting that bit within 'mask' to zero,
399  * masks out the right. For the execute disable bit, the right is
400  * masked out when the bit is set, so the mask works the other way
401  * around in this case: When the bit is set in 'mask', but not set in
402  * 'attr', it will be set in the return value, so mask-out behavior is
403  * preserved.
404  *
405  * \param attr  The page attributes to mask.
406  * \param mask  Mask for the page attributes.
407  *
408  * \return Masked version of 'attr'.
409  */
410 static inline uint64_t paging_x86_64_mask_attrs(uint64_t attr, uint64_t mask)
411 {
412     // First, mask out all "bit-sets-enabled" attributes
413     attr &= mask | X86_64_PTABLE_EXECUTE_DISABLE;
414
415     // Now, mask out all "bit-sets-disabled" attributes
416     attr |= mask & X86_64_PTABLE_EXECUTE_DISABLE;
417
418     return attr;
419 }
420
421 #endif // KERNEL_TARGET_X86_64_PAGING_H