Don't pass "-nics 0" to qemu, because this option name has changed
[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     31                  22 21                  12 11                   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:12). */
61 #define PGSHIFT 0                       /* Index of first offset bit. */
62 #define PGBITS  12                      /* Number of offset bits. */
63 #define PGMASK  MASK(PGSHIFT, PGBITS)   /* Page offset bits (0:12). */
64 #define PGSIZE  (1 << PGBITS)           /* Bytes in a page. */
65
66 /* Page table (bits 12:22). */
67 #define PTSHIFT PGBITS                  /* Index of first page table bit. */
68 #define PTBITS  10                      /* Number of page table bits. */
69 #define PTMASK  MASK(PTSHIFT, PTBITS)   /* Page table bits (12:22). */
70 #define PTSPAN  (1 << PTBITS << PGBITS) /* Bytes covered by a page table. */
71
72 /* Page directory (bits 22:32). */
73 #define PDSHIFT (PTSHIFT + PTBITS)      /* First page dir bit. */
74 #define PDBITS  10                      /* Number of page dir bits. */
75 #define PDMASK  MASK(PDSHIFT, PDBITS)   /* Page directory bits (22:32). */
76
77 /* Offset within a page. */
78 static inline unsigned pg_ofs (const void *va) {
79   return (uintptr_t) va & PGMASK;
80 }
81
82 /* Virtual page number. */
83 static inline uintptr_t pg_no (const void *va) {
84   return (uintptr_t) va >> PTSHIFT;
85 }
86
87 /* Round up to nearest page boundary. */
88 static inline void *pg_round_up (const void *va) {
89   return (void *) (((uintptr_t) va + PGSIZE - 1) & ~PGMASK);
90 }
91
92 /* Round down to nearest page boundary. */
93 static inline void *pg_round_down (const void *va) {
94   return (void *) ((uintptr_t) va & ~PGMASK);
95 }
96
97 /* Base address of the 1:1 physical-to-virtual mapping.  Physical
98    memory is mapped starting at this virtual address.  Thus,
99    physical address 0 is accessible at PHYS_BASE, physical
100    address address 0x1234 at (uint8_t *) PHYS_BASE + 0x1234, and
101    so on.
102
103    This address also marks the end of user programs' address
104    space.  Up to this point in memory, user programs are allowed
105    to map whatever they like.  At this point and above, the
106    virtual address space belongs to the kernel. */
107 #define PHYS_BASE ((void *) LOADER_PHYS_BASE)
108
109 /* Returns true if VADDR is a user virtual address. */
110 static inline bool
111 is_user_vaddr (const void *vaddr) 
112 {
113   return vaddr < PHYS_BASE;
114 }
115
116 /* Returns true if VADDR is a kernel virtual address. */
117 static inline bool
118 is_kernel_vaddr (const void *vaddr) 
119 {
120   return vaddr >= PHYS_BASE;
121 }
122
123 /* Returns kernel virtual address at which physical address PADDR
124    is mapped. */
125 static inline void *
126 ptov (uintptr_t paddr)
127 {
128   ASSERT ((void *) paddr < PHYS_BASE);
129
130   return (void *) (paddr + PHYS_BASE);
131 }
132
133 /* Returns physical address at which kernel virtual address VADDR
134    is mapped. */
135 static inline uintptr_t
136 vtop (const void *vaddr)
137 {
138   ASSERT (is_kernel_vaddr (vaddr));
139
140   return (uintptr_t) vaddr - (uintptr_t) PHYS_BASE;
141 }
142 \f
143 /* Page directories and page tables.
144
145    For more information see [IA32-v3a] 3.7.6 "Page-Directory and
146    Page-Table Entries".
147
148    PDEs and PTEs share a common format:
149
150    31                                 12 11                     0
151    +------------------------------------+------------------------+
152    |         Physical Address           |         Flags          |
153    +------------------------------------+------------------------+
154
155    In a PDE, the physical address points to a page table.
156    In a PTE, the physical address points to a data or code page.
157    The important flags are listed below.
158    When a PDE or PTE is not "present", the other flags are
159    ignored.
160    A PDE or PTE that is initialized to 0 will be interpreted as
161    "not present", which is just fine. */
162 #define PG_P 0x1               /* 1=present, 0=not present. */
163 #define PG_W 0x2               /* 1=read/write, 0=read-only. */
164 #define PG_U 0x4               /* 1=user/kernel, 0=kernel only. */
165 #define PG_A 0x20              /* 1=accessed, 0=not acccessed. */
166 #define PG_D 0x40              /* 1=dirty, 0=not dirty (PTEs only). */
167
168 /* Obtains page directory index from a virtual address. */
169 static inline uintptr_t pd_no (const void *va) {
170   return (uintptr_t) va >> PDSHIFT;
171 }
172
173 /* Returns a PDE that points to page table PT. */
174 static inline uint32_t pde_create (uint32_t *pt) {
175   ASSERT (pg_ofs (pt) == 0);
176   return vtop (pt) | PG_U | PG_P | PG_W;
177 }
178
179 /* Returns a pointer to the page table that page directory entry
180    PDE, which must "present", points to. */
181 static inline uint32_t *pde_get_pt (uint32_t pde) {
182   ASSERT (pde & PG_P);
183   return ptov (pde & ~PGMASK);
184 }
185
186 /* Obtains page table index from a virtual address. */
187 static inline unsigned pt_no (const void *va) {
188   return ((uintptr_t) va & PTMASK) >> PTSHIFT;
189 }
190
191 /* Returns a PTE that points to PAGE.
192    The PTE's page is readable.
193    If WRITABLE is true then it will be writable as well.
194    The page will be usable only by ring 0 code (the kernel). */
195 static inline uint32_t pte_create_kernel (uint32_t *page, bool writable) {
196   ASSERT (pg_ofs (page) == 0);
197   return vtop (page) | PG_P | (writable ? PG_W : 0);
198 }
199
200 /* Returns a PTE that points to PAGE.
201    The PTE's page is readable.
202    If WRITABLE is true then it will be writable as well.
203    The page will be usable by both user and kernel code. */
204 static inline uint32_t pte_create_user (uint32_t *page, bool writable) {
205   return pte_create_kernel (page, writable) | PG_U;
206 }
207
208 /* Returns a pointer to the page that page table entry PTE points
209    to. */
210 static inline void *pte_get_page (uint32_t pte) {
211   return ptov (pte & ~PGMASK);
212 }
213
214 #endif /* threads/mmu.h */