1 #include "userprog/pagedir.h"
5 #include "threads/init.h"
6 #include "threads/mmu.h"
7 #include "threads/palloc.h"
9 static uint32_t *active_pd (void);
11 /* Creates a new page directory that has mappings for kernel
12 virtual addresses, but none for user virtual addresses.
13 Returns the new page directory, or a null pointer if memory
18 uint32_t *pd = palloc_get_page (0);
19 memcpy (pd, base_page_dir, PGSIZE);
23 /* Destroys page directory PD, freeing all the pages it
26 pagedir_destroy (uint32_t *pd)
33 ASSERT (pd != base_page_dir);
34 for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
37 uint32_t *pt = pde_get_pt (*pde);
40 for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
42 palloc_free_page (pte_get_page (*pte));
43 palloc_free_page (pt);
45 palloc_free_page (pd);
48 /* Returns the address of the page table entry for user virtual
49 address UADDR in page directory PD.
50 If PD does not have a page table for UADDR, behavior varies
52 if CREATE is true, then a new page table is created and a
53 pointer into it is returned,
54 otherwise a null pointer is returned.
55 Also returns a null pointer if UADDR is a kernel address. */
57 lookup_page (uint32_t *pd, void *uaddr, bool create)
63 /* Make sure it's a user address. */
64 if (uaddr >= PHYS_BASE)
67 /* Check for a page table for UADDR.
68 If one is missing, create one if requested. */
69 pde = pd + pd_no (uaddr);
74 pt = palloc_get_page (PAL_ZERO);
78 *pde = pde_create (pt);
84 /* Return the page table entry. */
85 pt = pde_get_pt (*pde);
86 return &pt[pt_no (uaddr)];
89 /* Adds a mapping from user virtual address UPAGE to kernel
90 virtual address KPAGE in page directory PD.
91 UPAGE must not already be mapped.
92 If WRITABLE is true, the new page is read/write;
93 otherwise it is read-only.
94 Returns true if successful, false if memory allocation
97 pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
102 ASSERT (pg_ofs (upage) == 0);
103 ASSERT (pg_ofs (kpage) == 0);
104 ASSERT (upage < PHYS_BASE);
105 ASSERT (pagedir_get_page (pd, upage) == NULL);
107 pte = lookup_page (pd, upage, true);
110 *pte = pte_create_user (kpage, writable);
117 /* Returns the kernel virtual address that user virtual address
118 UADDR is mapped to in PD, or a null pointer if there is no
121 pagedir_get_page (uint32_t *pd, const void *uaddr)
123 uint32_t *pte = lookup_page (pd, (void *) uaddr, false);
124 return (pte != NULL && *pte != 0
125 ? (uint8_t *) pte_get_page (*pte) + pg_ofs (uaddr)
129 /* Clears any mapping for user virtual address UPAGE in page
131 UPAGE need not already be mapped. */
133 pagedir_clear_page (uint32_t *pd, void *upage)
135 uint32_t *pte = lookup_page (pd, upage, false);
136 if (pte != NULL && *pte != 0)
140 if (active_pd () == pd)
142 /* We cleared a page-table entry in the active page
143 table, so we have to invalidate the TLB. See
144 [IA32-v3], section 3.11. */
145 pagedir_activate (pd);
151 /* Returns true if the PTE for user virtual page UPAGE in PD is
152 dirty, that is, if the page has been modified since the PTE
154 Returns false if PD contains no PDE for UPAGE. */
156 pagedir_test_dirty (uint32_t *pd, const void *upage)
158 uint32_t *pte = lookup_page (pd, (void *) upage, false);
159 return pte != NULL && (*pte & PG_D) != 0;
162 /* Returns true if the PTE for user virtual page UPAGE in PD has
163 been accessed recently, that is, between the time the PTE was
164 installed and the last time it was cleared.
165 Returns false if PD contains no PDE for UPAGE. */
167 pagedir_test_accessed (uint32_t *pd, const void *upage)
169 uint32_t *pte = lookup_page (pd, (void *) upage, false);
170 return pte != NULL && (*pte & PG_A) != 0;
173 /* Resets the accessed bit in the PTE for user virtual page UPAGE
176 pagedir_clear_accessed (uint32_t *pd, const void *upage)
178 uint32_t *pte = lookup_page (pd, (void *) upage, false);
180 *pte &= ~(uint32_t) PG_A;
183 /* Loads page directory PD into the CPU's page directory base
186 pagedir_activate (uint32_t *pd)
191 /* Store the physical address of the page directory into CR3
192 aka PDBR (page directory base register). This activates our
193 new page tables immediately. See [IA32-v2a] "MOV--Move
194 to/from Control Registers" and [IA32-v3] 3.7.5. */
195 asm volatile ("mov %%cr3, %0" :: "r" (vtop (pd)));
198 /* Returns the currently active page directory. */
202 /* Copy CR3, the page directory base register (PDBR), into
204 See [IA32-v2a] "MOV--Move to/from Control Registers" and
207 asm ("mov %0, %%cr3" : "=r" (pd));