Merge branch 'arrakis'
[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       :2;
110         uint64_t        vtd_snoop       :1;
111         uint64_t        attr_index      :1;
112         uint64_t        reserved        :17;
113         uint64_t        base_addr       :10;
114         uint64_t        reserved2       :12;
115         uint64_t        available2      :11;
116         uint64_t        execute_disable :1;
117     } huge;
118     struct {
119         uint64_t        present         :1;
120         uint64_t        read_write      :1;
121         uint64_t        user_supervisor :1;
122         uint64_t        write_through   :1;
123         uint64_t        cache_disabled  :1;
124         uint64_t        accessed        :1;
125         uint64_t        dirty           :1;
126         uint64_t        always1         :1;
127         uint64_t        global          :1;
128         uint64_t        available       :2;
129         uint64_t        vtd_snoop       :1;
130         uint64_t        attr_index      :1;
131         uint64_t        reserved        :8;
132         uint64_t        base_addr       :X86_64_PAGING_LARGE_BASE_BITS;
133         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
134         uint64_t        available2      :11;
135         uint64_t        execute_disable :1;
136     } large;
137     struct {
138         uint64_t        present         :1;
139         uint64_t        read_write      :1;
140         uint64_t        user_supervisor :1;
141         uint64_t        write_through   :1;
142         uint64_t        cache_disabled  :1;
143         uint64_t        accessed        :1;
144         uint64_t        dirty           :1;
145         uint64_t        attr_index      :1;
146         uint64_t        global          :1;
147         uint64_t        available       :2;
148         uint64_t        vtd_snoop       :1;
149         uint64_t        base_addr       :X86_64_PAGING_BASE_BASE_BITS;
150         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
151         uint64_t        available2      :11;
152         uint64_t        execute_disable :1;
153     } base;
154 };
155
156 STATIC_ASSERT_SIZEOF(union x86_64_ptable_entry, (X86_64_PAGING_ENTRY_SIZE / 8));
157
158 /**
159  * \brief Clear page directory.
160  *
161  * Clears page directory pointed to by 'p'.
162  *
163  * \param p     Pointer to page directory to clear.
164  */
165 static inline void paging_x86_64_clear_pdir(union x86_64_pdir_entry * COUNT(X86_64_PTABLE_SIZE)
166                                             NONNULL p)
167 {
168     for (int i = 0; i < X86_64_PTABLE_SIZE; i++) {
169         p[i].raw = X86_64_PTABLE_CLEAR;
170     }
171 }
172
173 /**
174  * \brief Clear page table.
175  *
176  * Clears page table pointed to by 'p'.
177  *
178  * \param p     Pointer to page table to clear.
179  */
180 static inline void paging_x86_64_clear_ptable(union x86_64_ptable_entry * COUNT(X86_64_PTABLE_SIZE)
181                                               NONNULL p)
182 {
183     for (int i = 0; i < X86_64_PTABLE_SIZE; i++) {
184         p[i].raw = X86_64_PTABLE_CLEAR;
185     }
186 }
187
188 /**
189  * \brief Maps from page directory entry to page directory/table.
190  *
191  * Maps page directory or table, based at 'base', from page directory entry
192  * pointed to by 'entry'.
193  *
194  * \param entry Pointer to page directory entry to point from.
195  * \param base  Base virtual address of page directory/table to point to.
196  */
197 static inline void paging_x86_64_map_table(union x86_64_pdir_entry *entry,
198                                            lpaddr_t base)
199 {
200     union x86_64_pdir_entry tmp;
201     tmp.raw = X86_64_PTABLE_CLEAR;
202
203     tmp.d.present = 1;
204     tmp.d.read_write = 1;
205     tmp.d.user_supervisor = 1;
206     tmp.d.base_addr = base >> 12;
207
208     *entry = tmp;
209 }
210
211 /**
212  * \brief Maps a huge page.
213  *
214  * From huge page table entry, pointed to by 'entry', maps physical address
215  * 'base' with page attribute bitmap 'bitmap'.
216  *
217  * \param entry         Pointer to page table entry to map from.
218  * \param base          Physical address to map to (will be page-aligned).
219  * \param bitmap        Bitmap to apply to page attributes.
220  */
221 static inline void paging_x86_64_map_huge(union x86_64_ptable_entry *entry,
222                                            lpaddr_t base, uint64_t bitmap)
223 {
224     union x86_64_ptable_entry tmp;
225     tmp.raw = X86_64_PTABLE_CLEAR;
226
227     tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
228     tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
229     tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
230     tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
231     tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
232     tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
233     tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
234     tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
235     tmp.huge.always1 = 1;
236     tmp.huge.base_addr = base >> X86_64_HUGE_PAGE_BITS;
237
238     *entry = tmp;
239 }
240
241 /**
242  * \brief Maps a large page.
243  *
244  * From large page table entry, pointed to by 'entry', maps physical address
245  * 'base' with page attribute bitmap 'bitmap'.
246  *
247  * \param entry         Pointer to page table entry to map from.
248  * \param base          Physical address to map to (will be page-aligned).
249  * \param bitmap        Bitmap to apply to page attributes.
250  */
251 static inline void paging_x86_64_map_large(union x86_64_ptable_entry *entry,
252                                            lpaddr_t base, uint64_t bitmap)
253 {
254     union x86_64_ptable_entry tmp;
255     tmp.raw = X86_64_PTABLE_CLEAR;
256
257     tmp.large.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
258     tmp.large.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
259     tmp.large.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
260     tmp.large.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
261     tmp.large.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
262 #ifdef __k1om__
263         /* The Xeon Phi has no support for global pages */
264         tmp.large.global = 0;
265 #else
266     tmp.large.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
267 #endif
268     tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
269     tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
270     tmp.large.always1 = 1;
271     tmp.large.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0;
272     tmp.large.base_addr = base >> 21;
273
274     *entry = tmp;
275 }
276
277 /**
278  * \brief Maps a normal (small) page.
279  *
280  * From small page table entry, pointed to by 'entry', maps physical address
281  * 'base' with page attribute bitmap 'bitmap'.
282  *
283  * \param entry         Pointer to page table entry to map from.
284  * \param base          Physical address to map to (will be page-aligned).
285  * \param bitmap        Bitmap to apply to page attributes.
286  */
287 static inline void paging_x86_64_map(union x86_64_ptable_entry * NONNULL entry,
288                                      lpaddr_t base, uint64_t bitmap)
289 {
290     union x86_64_ptable_entry tmp;
291     tmp.raw = X86_64_PTABLE_CLEAR;
292
293     tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
294     tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
295     tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
296     tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
297     tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
298     tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
299 #ifdef __k1om__
300         /* The Xeon Phi has no support for global pages */
301         tmp.base.global = 0;
302 #else
303     tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
304 #endif
305     tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
306     tmp.base.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0;
307     tmp.base.base_addr = base >> 12;
308
309     *entry = tmp;
310 }
311
312
313 /**
314  * \brief Modify flags of a huge page.
315  *
316  * From small page table entry, pointed to by 'entry', maps physical address
317  * 'base' with page attribute bitmap 'bitmap'.
318  *
319  * \param entry         Pointer to page table entry to map from.
320  * \param bitmap        Bitmap to apply to page attributes.
321  */
322 static inline void paging_x86_64_modify_flags_huge(union x86_64_ptable_entry * entry,
323                                                    uint64_t bitmap)
324 {
325     union x86_64_ptable_entry tmp = *entry;
326
327     tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
328     tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
329     tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
330     tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
331     tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
332 #ifdef __k1om__
333     tmp.huge.global = 0;
334 #else
335     tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
336 #endif
337     tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
338     tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
339     tmp.huge.always1 = 1;
340
341     *entry = tmp;
342 }
343
344
345 /**
346  * \brief Modify flags of a large page.
347  *
348  * From small page table entry, pointed to by 'entry', maps physical address
349  * 'base' with page attribute bitmap 'bitmap'.
350  *
351  * \param entry         Pointer to page table entry to map from.
352  * \param bitmap        Bitmap to apply to page attributes.
353  */
354 static inline void paging_x86_64_modify_flags_large(union x86_64_ptable_entry *entry,
355                                               uint64_t bitmap)
356 {
357     union x86_64_ptable_entry tmp = *entry;
358
359     tmp.large.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
360     tmp.large.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
361     tmp.large.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
362     tmp.large.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
363     tmp.large.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
364 #ifdef __k1om__
365     /* The Xeon Phi has no support for global pages */
366     tmp.large.global = 0;
367 #else
368     tmp.large.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
369 #endif
370     tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
371     tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
372     tmp.large.always1 = 1;
373
374     *entry = tmp;
375 }
376
377 /**
378  * \brief Modify flags of a normal (small) page.
379  *
380  * From small page table entry, pointed to by 'entry', maps physical address
381  * 'base' with page attribute bitmap 'bitmap'.
382  *
383  * \param entry         Pointer to page table entry to map from.
384  * \param bitmap        Bitmap to apply to page attributes.
385  */
386 static inline void paging_x86_64_modify_flags(union x86_64_ptable_entry * NONNULL entry,
387                                               uint64_t bitmap)
388 {
389     union x86_64_ptable_entry tmp = *entry;
390
391     tmp.base.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
392     tmp.base.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
393     tmp.base.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
394     tmp.base.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
395     tmp.base.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
396     tmp.base.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
397 #ifdef __k1om__
398         /* XXX: The Xeon Phi does no support global pages */
399         tmp.base.global =  0;
400 #else
401     tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
402 #endif
403     tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
404
405     *entry = tmp;
406 }
407
408 static inline void paging_unmap(union x86_64_ptable_entry * NONNULL entry)
409 {
410     entry->raw = X86_64_PTABLE_CLEAR;
411 }
412
413 /**
414  * \brief Convert Capability access rights to X86-64 page flags.
415  *
416  * Returns corresponding X86-64 page flags to given capability access rights
417  * mask 'rights'.
418  *
419  * \param rights        Capability rightsmask.
420  *
421  * \return X86-64 page flags.
422  */
423 static inline uint64_t paging_x86_64_cap_to_page_flags(CapRights rights)
424 {
425     uint64_t pageflags = 0;
426
427     // Sanity-check given flags
428     if(!(rights & CAPRIGHTS_READ) &&
429        (rights & CAPRIGHTS_WRITE || rights & CAPRIGHTS_EXECUTE)) {
430         printk(LOG_ERR, "Page mapped writable and/or executable, but not "
431                "readable. Impossible on X86! Will map non-everything "
432                "instead.\n");
433     }
434
435     // Convert flags
436     pageflags |= rights & CAPRIGHTS_READ ? X86_64_PTABLE_USER_SUPERVISOR : 0;
437     pageflags |= rights & CAPRIGHTS_WRITE ? X86_64_PTABLE_READ_WRITE : 0;
438     pageflags |= rights & CAPRIGHTS_EXECUTE ? 0 : X86_64_PTABLE_EXECUTE_DISABLE;
439
440     return pageflags;
441 }
442
443 /**
444  * \brief Switch context.
445  *
446  * Assigns given physical base address of PML4 'pml4' to the CR3
447  * register, effectively switching context to new address space. Be
448  * cautious that you only switch to "good" (as explained in
449  * paging_make_good_pml4()) PML4s!
450  *
451  * \param pml4  Physical base address of PML4 table.
452  */
453 static void inline paging_x86_64_context_switch(lpaddr_t pml4)
454 {
455     __asm volatile("mov %[pml4], %%cr3"
456                    : /* No output */
457                    :
458                    [pml4] "r" (pml4)
459                    );
460 }
461
462 /**
463  * \brief Mask out page attributes.
464  *
465  * Masks out all attributes and access rights from 'attr' according to
466  * 'mask'. This is architecture-specific. On x86-64, except for the
467  * execute disable attribute, rights are given by setting a
468  * corresponding bit. Thus, setting that bit within 'mask' to zero,
469  * masks out the right. For the execute disable bit, the right is
470  * masked out when the bit is set, so the mask works the other way
471  * around in this case: When the bit is set in 'mask', but not set in
472  * 'attr', it will be set in the return value, so mask-out behavior is
473  * preserved.
474  *
475  * \param attr  The page attributes to mask.
476  * \param mask  Mask for the page attributes.
477  *
478  * \return Masked version of 'attr'.
479  */
480 static inline uint64_t paging_x86_64_mask_attrs(uint64_t attr, uint64_t mask)
481 {
482     // First, mask out all "bit-sets-enabled" attributes
483     attr &= mask | X86_64_PTABLE_EXECUTE_DISABLE;
484
485     // Now, mask out all "bit-sets-disabled" attributes
486     attr |= mask & X86_64_PTABLE_EXECUTE_DISABLE;
487
488     return attr;
489 }
490
491 #endif // KERNEL_TARGET_X86_64_PAGING_H