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)
89 for (kpage = pagedir_first (pd, &upage); kpage != NULL;
90 kpage = pagedir_next (pd, &upage))
96 lookup_page (uint32_t *pd, void *upage, bool create)
102 ASSERT (pg_ofs (upage) == 0);
103 ASSERT (upage < PHYS_BASE);
105 /* Check for a page table for UPAGE.
106 If one is missing, create one if requested. */
107 pde = pd + pd_no (upage);
112 pt = palloc_get (PAL_ZERO);
116 *pde = make_pde (pt);
122 /* Return the page table entry. */
123 pt = pde_get_pt (*pde);
124 return &pt[pt_no (upage)];
128 pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
133 ASSERT (pg_ofs (kpage) == 0);
135 pte = lookup_page (pd, upage, true);
138 *pte = make_user_pte (kpage, writable);
146 pagedir_get_page (uint32_t *pd, void *upage)
148 uint32_t *pte = lookup_page (pd, upage, false);
149 return pte != NULL && *pte != 0 ? pte_get_page (*pte) : NULL;
153 pagedir_clear_page (uint32_t *pd, void *upage)
155 uint32_t *pte = lookup_page (pd, upage, false);
161 scan_pt (uint32_t *pt, unsigned pde_idx, unsigned pte_idx, void **upage)
163 for (; pte_idx < PGSIZE / sizeof *pt; pte_idx++)
165 uint32_t pte = pt[pte_idx];
169 void *kpage = pte_get_page (pte);
172 *upage = (void *) ((pde_idx << PDSHIFT) | (pte_idx << PTSHIFT));
182 scan_pd (uint32_t *pd, unsigned pde_idx, void **upage)
184 for (; pde_idx < pd_no (PHYS_BASE); pde_idx++)
186 uint32_t pde = pd[pde_idx];
190 void *kpage = scan_pt (pde_get_pt (pde), pde_idx, 0, upage);
200 pagedir_first (uint32_t *pd, void **upage)
202 return scan_pd (pd, 0, upage);
206 pagedir_next (uint32_t *pd, void **upage)
208 unsigned pde_idx, pte_idx;
211 pde_idx = pd_no (*upage);
212 pte_idx = pt_no (*upage);
213 kpage = scan_pt (pde_get_pt (pd[pde_idx]),
214 pde_idx, pte_idx + 1, upage);
216 kpage = scan_pd (pd, pde_idx + 1, upage);
221 pagedir_activate (uint32_t *pd)
223 asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));