Redo makefiles.
[pintos-anon] / src / threads / paging.c
1 #include "paging.h"
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include "init.h"
5 #include "mmu.h"
6 #include "palloc.h"
7 #include "lib/lib.h"
8
9 static uint32_t *base_page_dir;
10
11 static uint32_t make_pde (uint32_t *pt) {
12   ASSERT (pg_ofs (pt) == 0);
13   return vtop (pt) | PG_U | PG_P | PG_W;
14 }
15
16 static uint32_t make_kernel_pte (uint32_t *page, bool writable) {
17   ASSERT (pg_ofs (page) == 0);
18   return vtop (page) | PG_P | (writable ? PG_W : 0);
19 }
20
21 static uint32_t make_user_pte (uint32_t *page, bool writable) {
22   return make_kernel_pte (page, writable) | PG_U;
23 }
24
25 static uint32_t *
26 pde_get_pt (uint32_t pde) 
27 {
28   ASSERT (pde & PG_P);
29
30   return ptov (pde & ~PGMASK);
31 }
32
33 static void *
34 pte_get_page (uint32_t pte) 
35 {
36   ASSERT (pte & PG_P);
37   
38   return ptov (pte & ~PGMASK);
39 }
40
41 /* Populates the base page directory and page table with the
42    kernel virtual mapping, and then sets up the CPU to use the
43    new page directory.
44
45    At the time this function is called, the active page table
46    (set up by loader.S) only maps the first 4 MB of RAM, so we
47    should not try to use extravagant amounts of memory.
48    Fortunately, there is no need to do so. */
49 void
50 paging_init (void)
51 {
52   uint32_t *pd, *pt;
53   size_t page;
54
55   pd = base_page_dir = palloc_get (PAL_ASSERT | PAL_ZERO);
56   pt = NULL;
57   for (page = 0; page < ram_pages; page++) 
58     {
59       uintptr_t paddr = page * PGSIZE;
60       void *vaddr = ptov (paddr);
61       size_t pde_idx = pd_no (vaddr);
62       size_t pte_idx = pt_no (vaddr);
63
64       if (pd[pde_idx] == 0)
65         {
66           pt = palloc_get (PAL_ASSERT | PAL_ZERO);
67           pd[pde_idx] = make_pde (pt);
68         }
69
70       pt[pte_idx] = make_kernel_pte (vaddr, true);
71     }
72
73   pagedir_activate (pd);
74 }
75
76 uint32_t *
77 pagedir_create (void) 
78 {
79   uint32_t *pd = palloc_get (0);
80   memcpy (pd, base_page_dir, PGSIZE);
81   return pd;
82 }
83
84 void
85 pagedir_destroy (uint32_t *pd) 
86 {
87   void *kpage, *upage;
88   unsigned pde_idx;
89
90   /* Destroy user pages. */
91   for (kpage = pagedir_first (pd, &upage); kpage != NULL;
92        kpage = pagedir_next (pd, &upage)) 
93     palloc_free (kpage);
94
95   /* Destroy page table pages. */
96   for (pde_idx = 0; pde_idx < pd_no (PHYS_BASE); pde_idx++) 
97     {
98       uint32_t pde = pd[pde_idx];
99
100       if (pde != 0) 
101         {
102           uint32_t *pt = pde_get_pt (pde);
103           palloc_free (pt);
104         }
105     }
106
107   /* Destroy page directory. */
108   palloc_free (pd);
109 }
110
111 static uint32_t *
112 lookup_page (uint32_t *pd, void *upage, bool create)
113 {
114   uint32_t *pt;
115   uint32_t *pde;
116
117   ASSERT (pd != NULL);
118   ASSERT (pg_ofs (upage) == 0);
119   ASSERT (upage < PHYS_BASE);
120
121   /* Check for a page table for UPAGE.
122      If one is missing, create one if requested. */
123   pde = pd + pd_no (upage);
124   if (*pde == 0) 
125     {
126       if (create)
127         {
128           pt = palloc_get (PAL_ZERO);
129           if (pt == NULL) 
130             return NULL; 
131       
132           *pde = make_pde (pt);
133         }
134       else
135         return NULL;
136     }
137
138   /* Return the page table entry. */
139   pt = pde_get_pt (*pde);
140   return &pt[pt_no (upage)];
141 }
142
143 bool
144 pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
145                   bool writable) 
146 {
147   uint32_t *pte;
148
149   ASSERT (pg_ofs (kpage) == 0);
150
151   pte = lookup_page (pd, upage, true);
152   if (pte != NULL) 
153     {
154       *pte = make_user_pte (kpage, writable);
155       return true;
156     }
157   else
158     return false;
159 }
160
161 void *
162 pagedir_get_page (uint32_t *pd, void *upage) 
163 {
164   uint32_t *pte = lookup_page (pd, upage, false);
165   return pte != NULL && *pte != 0 ? pte_get_page (*pte) : NULL;
166 }
167
168 void
169 pagedir_clear_page (uint32_t *pd, void *upage)
170 {
171   uint32_t *pte = lookup_page (pd, upage, false);
172   if (pte != NULL)
173     *pte = 0;
174 }
175
176 static uint32_t *
177 scan_pt (uint32_t *pt, unsigned pde_idx, unsigned pte_idx, void **upage) 
178 {
179   for (; pte_idx < PGSIZE / sizeof *pt; pte_idx++) 
180     {
181       uint32_t pte = pt[pte_idx];
182
183       if (pte != 0) 
184         {
185           void *kpage = pte_get_page (pte);
186           if (kpage != NULL) 
187             {
188               *upage = (void *) ((pde_idx << PDSHIFT) | (pte_idx << PTSHIFT));
189               return kpage;
190             }
191         }
192     }
193   
194   return NULL;
195 }
196
197 static void *
198 scan_pd (uint32_t *pd, unsigned pde_idx, void **upage) 
199 {
200   for (; pde_idx < pd_no (PHYS_BASE); pde_idx++) 
201     {
202       uint32_t pde = pd[pde_idx];
203
204       if (pde != 0) 
205         {
206           void *kpage = scan_pt (pde_get_pt (pde), pde_idx, 0, upage);
207           if (kpage != NULL)
208             return kpage;
209         }
210     }
211   
212   return NULL;
213 }
214
215 void *
216 pagedir_first (uint32_t *pd, void **upage) 
217 {
218   return scan_pd (pd, 0, upage);
219 }
220
221 void *
222 pagedir_next (uint32_t *pd, void **upage) 
223 {
224   unsigned pde_idx, pte_idx;
225   void *kpage;
226
227   pde_idx = pd_no (*upage);
228   pte_idx = pt_no (*upage);
229   kpage = scan_pt (pde_get_pt (pd[pde_idx]),
230                    pde_idx, pte_idx + 1, upage);
231   if (kpage == NULL)
232     kpage = scan_pd (pd, pde_idx + 1, upage);
233   return kpage;
234 }
235
236 void
237 pagedir_activate (uint32_t *pd) 
238 {
239   if (pd == NULL)
240     pd = base_page_dir;
241   asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
242 }