Add const to various functions.
[pintos-anon] / src / threads / mmu.h
1 #ifndef THREADS_MMU_H
2 #define THREADS_MMU_H
3
4 #include <debug.h>
5 #include <stdint.h>
6 #include <stdbool.h>
7
8 #include "threads/loader.h"
9
10 /* Virtual to physical translation works like this on an x86:
11
12    - The top 10 bits of the virtual address (bits 22:31) are used
13      to index into the page directory.  If the PDE is marked
14      "present," the physical address of a page table is read from
15      the PDE thus obtained.  If the PDE is marked "not present"
16      then a page fault occurs.
17
18    - The next 10 bits of the virtual address (bits 12:21) are
19      used to index into the page table.  If the PTE is marked
20      "present," the physical address of a data page is read from
21      the PTE thus obtained.  If the PTE is marked "not present"
22      then a page fault occurs.
23
24    - The bottom 12 bits of the virtual address (bits 0:11) are
25      added to the data page's physical base address, producing
26      the final physical address.
27
28
29    32                    22                     12                      0
30    +--------------------------------------------------------------------+
31    | Page Directory Index |   Page Table Index   |    Page Offset       |
32    +--------------------------------------------------------------------+
33                 |                    |                     |
34         _______/             _______/                _____/
35        /                    /                       /
36       /    Page Directory  /      Page Table       /    Data Page
37      /     .____________. /     .____________.    /   .____________.
38      |1,023|____________| |1,023|____________|    |   |____________|
39      |1,022|____________| |1,022|____________|    |   |____________|
40      |1,021|____________| |1,021|____________|    \__\|____________|
41      |1,020|____________| |1,020|____________|       /|____________|
42      |     |            | |     |            |        |            |
43      |     |            | \____\|            |_       |            |
44      |     |      .     |      /|      .     | \      |      .     |
45      \____\|      .     |_      |      .     |  |     |      .     |
46           /|      .     | \     |      .     |  |     |      .     |
47            |      .     |  |    |      .     |  |     |      .     |
48            |            |  |    |            |  |     |            |
49            |____________|  |    |____________|  |     |____________|
50           4|____________|  |   4|____________|  |     |____________|
51           3|____________|  |   3|____________|  |     |____________|
52           2|____________|  |   2|____________|  |     |____________|
53           1|____________|  |   1|____________|  |     |____________|
54           0|____________|  \__\0|____________|  \____\|____________|
55                               /                      /
56 */
57
58 #define MASK(SHIFT, CNT) (((1ul << (CNT)) - 1) << (SHIFT))
59
60 /* Page offset (bits 0:11). */
61 #define PGSHIFT         0                  /* First offset bit. */
62 #define PGBITS          12                 /* Number of offset bits. */
63 #define PGMASK          MASK(PGSHIFT, PGBITS)
64 #define PGSIZE          (1 << PGBITS)
65
66 /* Page table (bits 12:21). */
67 #define PTSHIFT         PGBITS             /* First page table bit. */
68 #define PTBITS          10                 /* Number of page table bits. */
69 #define PTMASK          MASK(PTSHIFT, PTBITS)
70
71 /* Page directory (bits 22:31). */
72 #define PDSHIFT         (PTSHIFT + PTBITS) /* First page dir bit. */
73 #define PDBITS          10                 /* Number of page dir bits. */
74 #define PDMASK          MASK(PDSHIFT, PDBITS)
75
76 /* Offset within a page. */
77 static inline unsigned pg_ofs (const void *va) {
78   return (uintptr_t) va & PGMASK;
79 }
80
81 /* Virtual page number. */
82 static inline uintptr_t pg_no (const void *va) {
83   return (uintptr_t) va >> PTSHIFT;
84 }
85
86 /* Round up to nearest page boundary. */
87 static inline void *pg_round_up (const void *va) {
88   return (void *) (((uintptr_t) va + PGSIZE - 1) & ~PGMASK);
89 }
90
91 /* Round down to nearest page boundary. */
92 static inline void *pg_round_down (const void *va) {
93   return (void *) ((uintptr_t) va & ~PGMASK);
94 }
95
96 #define PHYS_BASE ((void *) LOADER_PHYS_BASE)
97
98 /* Returns kernel virtual address at which physical address PADDR
99    is mapped. */
100 static inline void *
101 ptov (uintptr_t paddr)
102 {
103   ASSERT ((void *) paddr < PHYS_BASE);
104
105   return (void *) (paddr + PHYS_BASE);
106 }
107
108 /* Returns physical address at which kernel virtual address VADDR
109    is mapped. */
110 static inline uintptr_t
111 vtop (const void *vaddr)
112 {
113   ASSERT (vaddr >= PHYS_BASE);
114
115   return (uintptr_t) vaddr - (uintptr_t) PHYS_BASE;
116 }
117 \f
118 /* Page directories and page tables.
119
120    For more information see [IA32-v3] pages 3-23 to 3-28.
121
122    PDEs and PTEs share a common format:
123
124    32                                   12                       0
125    +------------------------------------+------------------------+
126    |         Physical Address           |         Flags          |
127    +------------------------------------+------------------------+
128
129    In a PDE, the physical address points to a page table.
130    In a PTE, the physical address points to a data or code page.
131    The important flags are listed below.
132    When a PDE or PTE is not "present", the other flags are
133    ignored.
134    A PDE or PTE that is initialized to 0 will be interpreted as
135    "not present", which is just fine. */
136 #define PG_P 0x1               /* 1=present, 0=not present. */
137 #define PG_W 0x2               /* 1=read/write, 0=read-only. */
138 #define PG_U 0x4               /* 1=user/kernel, 0=kernel only. */
139 #define PG_A 0x20              /* 1=accessed, 0=not acccessed. */
140 #define PG_D 0x40              /* 1=dirty, 0=not dirty (PTEs only). */
141
142 /* Obtains page directory index from a virtual address. */
143 static inline uintptr_t pd_no (const void *va) {
144   return (uintptr_t) va >> PDSHIFT;
145 }
146
147 /* Returns a PDE that points to page table PT. */
148 static inline uint32_t pde_create (uint32_t *pt) {
149   ASSERT (pg_ofs (pt) == 0);
150   return vtop (pt) | PG_U | PG_P | PG_W;
151 }
152
153 /* Returns a pointer to the page table that page directory entry
154    PDE, which must "present", points to. */
155 static inline uint32_t *pde_get_pt (uint32_t pde) {
156   ASSERT (pde & PG_P);
157   return ptov (pde & ~PGMASK);
158 }
159
160 /* Obtains page table index from a virtual address. */
161 static inline unsigned pt_no (void *va) {
162   return ((uintptr_t) va & PTMASK) >> PTSHIFT;
163 }
164
165 /* Returns a PTE that points to PAGE.
166    The PTE's page is readable.
167    If WRITABLE is true then it will be writable as well.
168    The page will be usable only by ring 0 code (the kernel). */
169 static inline uint32_t pte_create_kernel (uint32_t *page, bool writable) {
170   ASSERT (pg_ofs (page) == 0);
171   return vtop (page) | PG_P | (writable ? PG_W : 0);
172 }
173
174 /* Returns a PTE that points to PAGE.
175    The PTE's page is readable.
176    If WRITABLE is true then it will be writable as well.
177    The page will be usable by both user and kernel code. */
178 static inline uint32_t pte_create_user (uint32_t *page, bool writable) {
179   return pte_create_kernel (page, writable) | PG_U;
180 }
181
182 /* Returns a pointer to the page that page table entry PTE, which
183    must "present", points to. */
184 static inline void *pte_get_page (uint32_t pte) {
185   ASSERT (pte & PG_P);
186   return ptov (pte & ~PGMASK);
187 }
188
189 #endif /* threads/mmu.h */