1/**
2 * \file
3 * \brief x86-32 kernel page-table structures.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#ifndef KERNEL_TARGET_X86_32_PAGING_H
16#define KERNEL_TARGET_X86_32_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
22int paging_x86_32_map_memory(lpaddr_t base, size_t size);
23lvaddr_t paging_x86_32_map_special(lpaddr_t base, size_t size, uint64_t bitmap);
24lvaddr_t paging_x86_32_map_device(lpaddr_t base, size_t size);
25
26#ifdef CONFIG_PAE
27void paging_x86_32_make_good_pdpte(lpaddr_t base);
28#else
29void paging_x86_32_make_good_pdir(lpaddr_t base);
30#endif
31
32void paging_x86_32_reset(void);
33
34/// All arch-specific flags valid to be set from user-space
35#define X86_32_PTABLE_FLAGS_MASK \
36    (X86_32_PTABLE_GLOBAL_PAGE | X86_32_PTABLE_ATTR_INDEX | \
37     X86_32_PTABLE_DIRTY | PTABLE_ACCESSED |                \
38     PTABLE_CACHE_DISABLED | PTABLE_WRITE_THROUGH)
39
40/// All flags valid for page access protection from user-space
41#define X86_32_PTABLE_ACCESS_MASK \
42    (X86_32_PTABLE_EXECUTE_DISABLE | X86_32_PTABLE_USER_SUPERVISOR | \
43     X86_32_PTABLE_READ_WRITE)
44
45/// Mask out all arch-specific flags except those valid from user-space
46#define X86_32_PTABLE_FLAGS(flags)     (flags & X86_32_PTABLE_FLAGS_MASK)
47
48/// Mask out all flags except those for access protection
49#define X86_32_PTABLE_ACCESS(flags)    (flags & X86_32_PTABLE_ACCESS_MASK)
50
51#ifdef CONFIG_PAE
52
53/** True if page entry is present in memory */
54#define X86_32_IS_PRESENT(entry)                        \
55    ((*(uint64_t *)(entry)) & X86_32_PTABLE_PRESENT)
56
57#else
58
59/** True if page entry is present in memory */
60#define X86_32_IS_PRESENT(entry)                        \
61    ((*(uint32_t *)(entry)) & X86_32_PTABLE_PRESENT)
62
63#endif
64
65#ifdef CONFIG_PAE
66
67union x86_32_pdpte_entry {
68    uint64_t raw;
69    struct {
70        uint64_t        present         :1;
71        uint64_t        reserved0       :2;
72        uint64_t        write_through   :1;
73        uint64_t        cache_disabled  :1;
74        uint64_t        reserved        :4;
75        uint64_t        ignored         :3;
76        uint64_t        base_addr       :52;
77    } d;
78};
79
80/**
81 * A page directory entry.
82 */
83union x86_32_pdir_entry {
84    uint64_t raw;
85    struct {
86        uint64_t        present         :1;
87        uint64_t        read_write      :1;
88        uint64_t        user_supervisor :1;
89        uint64_t        write_through   :1;
90        uint64_t        cache_disabled  :1;
91        uint64_t        accessed        :1;
92        uint64_t        reserved        :3;
93        uint64_t        available       :3;
94        uint64_t        base_addr       :28;
95        uint64_t        reserved2       :12;    // XXX: Part of base_addr
96        uint64_t        reserved3       :11;
97        uint64_t        execute_disable :1;
98    } d;
99};
100
101/**
102 * A page table entry.
103 */
104union x86_32_ptable_entry {
105    uint64_t raw;
106    struct {
107        uint64_t        present         :1;
108        uint64_t        read_write      :1;
109        uint64_t        user_supervisor :1;
110        uint64_t        write_through   :1;
111        uint64_t        cache_disabled  :1;
112        uint64_t        accessed        :1;
113        uint64_t        dirty           :1;
114        uint64_t        always1         :1;
115        uint64_t        global          :1;
116        uint64_t        available       :3;
117        uint64_t        attr_index      :1;
118        uint64_t        reserved        :8;
119        uint64_t        base_addr       :42;
120        uint64_t        execute_disable :1;
121    } large;
122    struct {
123        uint64_t        present         :1;
124        uint64_t        read_write      :1;
125        uint64_t        user_supervisor :1;
126        uint64_t        write_through   :1;
127        uint64_t        cache_disabled  :1;
128        uint64_t        accessed        :1;
129        uint64_t        dirty           :1;
130        uint64_t        attr_index      :1;
131        uint64_t        global          :1;
132        uint64_t        reserved        :3;
133        uint64_t        base_addr       :51;
134        uint64_t        execute_disable :1;
135    } base;
136};
137
138#else
139
140/**
141 * A page directory entry.
142 */
143union x86_32_pdir_entry {
144    uint32_t raw;
145    struct {
146        uint32_t        present         :1;
147        uint32_t        read_write      :1;
148        uint32_t        user_supervisor :1;
149        uint32_t        write_through   :1;
150        uint32_t        cache_disabled  :1;
151        uint32_t        accessed        :1;
152        uint32_t        available       :1;
153        uint32_t        always0         :1;
154        uint32_t        reserved        :4;
155        uint32_t        base_addr       :20;
156    } d;
157};
158
159/**
160 * A page table entry.
161 */
162union x86_32_ptable_entry {
163    uint32_t raw;
164    struct {
165        uint32_t        present         :1;
166        uint32_t        read_write      :1;
167        uint32_t        user_supervisor :1;
168        uint32_t        write_through   :1;
169        uint32_t        cache_disabled  :1;
170        uint32_t        accessed        :1;
171        uint32_t        dirty           :1;
172        uint32_t        always1         :1;
173        uint32_t        global          :1;
174        uint32_t        available       :3;
175        uint32_t        attr_index      :1;
176        uint32_t        reserved        :9;
177        uint32_t        base_addr       :10;
178    } large;
179    struct {
180        uint32_t        present         :1;
181        uint32_t        read_write      :1;
182        uint32_t        user_supervisor :1;
183        uint32_t        write_through   :1;
184        uint32_t        cache_disabled  :1;
185        uint32_t        accessed        :1;
186        uint32_t        dirty           :1;
187        uint32_t        attr_index      :1;
188        uint32_t        global          :1;
189        uint32_t        available       :3;
190        uint32_t        base_addr       :20;
191    } base;
192};
193
194#endif
195
196/**
197 * \brief Clear page directory.
198 *
199 * Clears page directory pointed to by 'p'.
200 *
201 * \param p     Pointer to page directory to clear.
202 */
203static inline void paging_x86_32_clear_pdir(union x86_32_pdir_entry * COUNT(X86_32_PTABLE_SIZE)
204                                            NONNULL p)
205{
206    for (int i = 0; i < X86_32_PTABLE_SIZE; i++) {
207        p[i].raw = X86_32_PTABLE_CLEAR;
208    }
209}
210
211/**
212 * \brief Clear page table.
213 *
214 * Clears page table pointed to by 'p'.
215 *
216 * \param p     Pointer to page table to clear.
217 */
218static inline void paging_x86_32_clear_ptable(union x86_32_ptable_entry * COUNT(X86_32_PTABLE_SIZE)
219                                              NONNULL p)
220{
221    for (int i = 0; i < X86_32_PTABLE_SIZE; i++) {
222        p[i].raw = X86_32_PTABLE_CLEAR;
223    }
224}
225
226/**
227 * \brief Maps from page directory entry to page directory/table.
228 *
229 * Maps page directory or table, based at 'base', from page directory entry
230 * pointed to by 'entry'.
231 *
232 * \param entry Pointer to page directory entry to point from.
233 * \param base  Base virtual address of page directory/table to point to.
234 */
235static inline void paging_x86_32_map_table(union x86_32_pdir_entry * NONNULL entry,
236                                           lpaddr_t base)
237{
238    union x86_32_pdir_entry tmp;
239    tmp.raw = PTABLE_CLEAR;
240
241    tmp.d.present = 1;
242    tmp.d.read_write = 1;
243    tmp.d.user_supervisor = 1;
244    tmp.d.base_addr = base >> 12;
245
246    *entry = tmp;
247}
248
249#ifdef CONFIG_PAE
250static inline void paging_x86_32_map_pdpte(union x86_32_pdpte_entry *entry,
251                                           lpaddr_t base)
252{
253    union x86_32_pdpte_entry tmp;
254    tmp.raw = X86_32_PTABLE_CLEAR;
255
256    tmp.d.present = 1;
257    tmp.d.base_addr = base >> 12;
258
259    *entry = tmp;
260}
261#endif
262
263/**
264 * \brief Maps a large page.
265 *
266 * From large page table entry, pointed to by 'entry', maps physical address
267 * 'base' with page attribute bitmap 'bitmap'.
268 *
269 * \param entry         Pointer to page table entry to map from.
270 * \param base          Physical address to map to (will be page-aligned).
271 * \param bitmap        Bitmap to apply to page attributes.
272 */
273static inline void paging_x86_32_map_large(union x86_32_ptable_entry * NONNULL entry,
274                                           lpaddr_t base,
275                                           paging_x86_32_flags_t bitmap)
276{
277    union x86_32_ptable_entry tmp;
278    tmp.raw = X86_32_PTABLE_CLEAR;
279
280    tmp.large.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0;
281    tmp.large.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0;
282    tmp.large.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0;
283    tmp.large.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0;
284    tmp.large.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0;
285    tmp.large.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0;
286    tmp.large.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0;
287#ifdef CONFIG_NXE
288    tmp.large.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0;
289#endif
290    tmp.large.always1 = 1;
291#ifdef CONFIG_PAE
292    tmp.large.base_addr = base >> 21;
293#else
294    tmp.large.base_addr = base >> 22;
295#endif
296
297    *entry = tmp;
298}
299
300/**
301 * \brief Maps a normal (small) page.
302 *
303 * From small page table entry, pointed to by 'entry', maps physical address
304 * 'base' with page attribute bitmap 'bitmap'.
305 *
306 * \param entry         Pointer to page table entry to map from.
307 * \param base          Physical address to map to (will be page-aligned).
308 * \param bitmap        Bitmap to apply to page attributes.
309 */
310static inline void paging_x86_32_map(union x86_32_ptable_entry * NONNULL entry,
311                                     lpaddr_t base,
312                                     paging_x86_32_flags_t bitmap)
313{
314    union x86_32_ptable_entry tmp;
315    tmp.raw = X86_32_PTABLE_CLEAR;
316
317    tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0;
318    tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0;
319    tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0;
320    tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0;
321    tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0;
322    tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0;
323    tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0;
324#ifdef CONFIG_NXE
325    tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0;
326#endif
327    tmp.base.base_addr = base >> 12;
328
329    *entry = tmp;
330}
331
332/**
333 * \brief Modify flags of a large page.
334 *
335 * Update small page table entry, pointed to by 'entry', with page attribute
336 * bitmap 'bitmap'.
337 *
338 * \param entry         Pointer to page table entry to map from.
339 * \param bitmap        Bitmap to apply to page attributes.
340 */
341static inline void paging_x86_32_modify_flags_large(union x86_32_ptable_entry * NONNULL entry,
342                                              paging_x86_32_flags_t bitmap)
343{
344    union x86_32_ptable_entry tmp = *entry;
345
346    tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0;
347    tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0;
348    tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0;
349    tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0;
350    tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0;
351    tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0;
352    tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0;
353#ifdef CONFIG_NXE
354    tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0;
355#endif
356
357    *entry = tmp;
358}
359
360/**
361 * \brief Modify flags of a normal (small) page.
362 *
363 * Update small page table entry, pointed to by 'entry', with page attribute
364 * bitmap 'bitmap'.
365 *
366 * \param entry         Pointer to page table entry to map from.
367 * \param bitmap        Bitmap to apply to page attributes.
368 */
369static inline void paging_x86_32_modify_flags(union x86_32_ptable_entry * NONNULL entry,
370                                              paging_x86_32_flags_t bitmap)
371{
372    union x86_32_ptable_entry tmp = *entry;
373
374    tmp.base.present = bitmap & X86_32_PTABLE_PRESENT ? 1 : 0;
375    tmp.base.read_write = bitmap & X86_32_PTABLE_READ_WRITE ? 1 : 0;
376    tmp.base.user_supervisor = bitmap & X86_32_PTABLE_USER_SUPERVISOR ? 1 : 0;
377    tmp.base.write_through = bitmap & X86_32_PTABLE_WRITE_THROUGH ? 1 : 0;
378    tmp.base.cache_disabled = bitmap & X86_32_PTABLE_CACHE_DISABLED ? 1 : 0;
379    tmp.base.attr_index = bitmap & X86_32_PTABLE_ATTR_INDEX ? 1 : 0;
380    tmp.base.global = bitmap & X86_32_PTABLE_GLOBAL_PAGE ? 1 : 0;
381#ifdef CONFIG_NXE
382    tmp.base.execute_disable = bitmap & X86_32_PTABLE_EXECUTE_DISABLE ? 1 : 0;
383#endif
384
385    *entry = tmp;
386}
387
388static inline void paging_x86_32_unmap(union x86_32_ptable_entry * NONNULL entry)
389{
390    entry->raw = X86_32_PTABLE_CLEAR;
391}
392
393/**
394 * \brief Convert Capability access rights to X86-64 page flags.
395 *
396 * Returns corresponding X86-64 page flags to given capability access rights
397 * mask 'rights'.
398 *
399 * \param rights        Capability rightsmask.
400 *
401 * \return X86-64 page flags.
402 */
403static inline uint64_t paging_x86_32_cap_to_page_flags(CapRights rights)
404{
405    uint64_t pageflags = 0;
406
407    // Sanity-check given flags
408    if(!(rights & CAPRIGHTS_READ) &&
409       (rights & CAPRIGHTS_WRITE || rights & CAPRIGHTS_EXECUTE)) {
410        printk(LOG_ERR, "Page mapped writable and/or executable, but not "
411               "readable. Impossible on X86! Will map non-everything "
412               "instead.\n");
413    }
414
415    // Convert flags
416    pageflags |= rights & CAPRIGHTS_READ ? X86_32_PTABLE_USER_SUPERVISOR : 0;
417    pageflags |= rights & CAPRIGHTS_WRITE ? X86_32_PTABLE_READ_WRITE : 0;
418    pageflags |= rights & CAPRIGHTS_EXECUTE ? 0 : X86_32_PTABLE_EXECUTE_DISABLE;
419
420    return pageflags;
421}
422
423/**
424 * \brief Switch context.
425 *
426 * Assigns given physical base address of PDPTE/PDE 'cr3' to the CR3
427 * register, effectively switching context to new address space. Be
428 * cautious that you only switch to "good" (as explained in
429 * paging_make_good_pdpte()/paging_make_good_pdir()) PDPTEs/PDEs!
430 *
431 * \param pdpte  Physical base address of PDPTE/PDE table.
432 */
433static void inline paging_x86_32_context_switch(lpaddr_t cr3)
434{
435    __asm volatile("mov %[cr3], %%cr3"
436                   : /* No output */
437                   :
438                   [cr3] "r" (cr3)
439                   );
440}
441
442/**
443 * \brief Mask out page attributes.
444 *
445 * Masks out all attributes and access rights from 'attr' according to
446 * 'mask'. This is architecture-specific. On x86-64, except for the
447 * execute disable attribute, rights are given by setting a
448 * corresponding bit. Thus, setting that bit within 'mask' to zero,
449 * masks out the right. For the execute disable bit, the right is
450 * masked out when the bit is set, so the mask works the other way
451 * around in this case: When the bit is set in 'mask', but not set in
452 * 'attr', it will be set in the return value, so mask-out behavior is
453 * preserved.
454 *
455 * \param attr  The page attributes to mask.
456 * \param mask  Mask for the page attributes.
457 *
458 * \return Masked version of 'attr'.
459 */
460static inline uint64_t paging_x86_32_mask_attrs(uint64_t attr, uint64_t mask)
461{
462    // First, mask out all "bit-sets-enabled" attributes
463    attr &= mask | X86_32_PTABLE_EXECUTE_DISABLE;
464
465    // Now, mask out all "bit-sets-disabled" attributes
466    attr |= mask & X86_32_PTABLE_EXECUTE_DISABLE;
467
468    return attr;
469}
470
471#endif // KERNEL_TARGET_X86_32_PAGING_H
472