1 #include "threads/paging.h"
5 #include "threads/init.h"
6 #include "threads/mmu.h"
7 #include "threads/palloc.h"
9 static uint32_t *base_page_dir;
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;
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);
21 static uint32_t make_user_pte (uint32_t *page, bool writable) {
22 return make_kernel_pte (page, writable) | PG_U;
26 pde_get_pt (uint32_t pde)
30 return ptov (pde & ~PGMASK);
34 pte_get_page (uint32_t pte)
38 return ptov (pte & ~PGMASK);
41 /* Populates the base page directory and page table with the
42 kernel virtual mapping, and then sets up the CPU to use the
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. */
55 pd = base_page_dir = palloc_get (PAL_ASSERT | PAL_ZERO);
57 for (page = 0; page < ram_pages; page++)
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);
66 pt = palloc_get (PAL_ASSERT | PAL_ZERO);
67 pd[pde_idx] = make_pde (pt);
70 pt[pte_idx] = make_kernel_pte (vaddr, true);
73 pagedir_activate (pd);
79 uint32_t *pd = palloc_get (0);
80 memcpy (pd, base_page_dir, PGSIZE);
85 pagedir_destroy (uint32_t *pd)
90 /* Destroy user pages. */
91 for (kpage = pagedir_first (pd, &upage); kpage != NULL;
92 kpage = pagedir_next (pd, &upage))
95 /* Destroy page table pages. */
96 for (pde_idx = 0; pde_idx < pd_no (PHYS_BASE); pde_idx++)
98 uint32_t pde = pd[pde_idx];
102 uint32_t *pt = pde_get_pt (pde);
107 /* Destroy page directory. */
112 lookup_page (uint32_t *pd, void *upage, bool create)
118 ASSERT (pg_ofs (upage) == 0);
119 ASSERT (upage < PHYS_BASE);
121 /* Check for a page table for UPAGE.
122 If one is missing, create one if requested. */
123 pde = pd + pd_no (upage);
128 pt = palloc_get (PAL_ZERO);
132 *pde = make_pde (pt);
138 /* Return the page table entry. */
139 pt = pde_get_pt (*pde);
140 return &pt[pt_no (upage)];
144 pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
149 ASSERT (pg_ofs (kpage) == 0);
151 pte = lookup_page (pd, upage, true);
154 *pte = make_user_pte (kpage, writable);
162 pagedir_get_page (uint32_t *pd, void *upage)
164 uint32_t *pte = lookup_page (pd, upage, false);
165 return pte != NULL && *pte != 0 ? pte_get_page (*pte) : NULL;
169 pagedir_clear_page (uint32_t *pd, void *upage)
171 uint32_t *pte = lookup_page (pd, upage, false);
177 scan_pt (uint32_t *pt, unsigned pde_idx, unsigned pte_idx, void **upage)
179 for (; pte_idx < PGSIZE / sizeof *pt; pte_idx++)
181 uint32_t pte = pt[pte_idx];
185 void *kpage = pte_get_page (pte);
188 *upage = (void *) ((pde_idx << PDSHIFT) | (pte_idx << PTSHIFT));
198 scan_pd (uint32_t *pd, unsigned pde_idx, void **upage)
200 for (; pde_idx < pd_no (PHYS_BASE); pde_idx++)
202 uint32_t pde = pd[pde_idx];
206 void *kpage = scan_pt (pde_get_pt (pde), pde_idx, 0, upage);
216 pagedir_first (uint32_t *pd, void **upage)
218 return scan_pd (pd, 0, upage);
222 pagedir_next (uint32_t *pd, void **upage)
224 unsigned pde_idx, pte_idx;
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);
232 kpage = scan_pd (pd, pde_idx + 1, upage);
237 pagedir_activate (uint32_t *pd)
241 asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));