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 ? pte_get_page (*pte) : NULL;
127 /* Clears any mapping for user virtual address UPAGE in page
129 UPAGE need not already be mapped. */
131 pagedir_clear_page (uint32_t *pd, void *upage)
133 uint32_t *pte = lookup_page (pd, upage, false);
134 if (pte != NULL && *pte != 0)
138 if (active_pd () == pd)
140 /* We cleared a page-table entry in the active page
141 table, so we have to invalidate the TLB. See
142 [IA32-v3], section 3.11. */
143 pagedir_activate (pd);
149 /* Returns true if the PTE for user virtual page UPAGE in PD is
150 dirty, that is, if the page has been modified since the PTE
152 Returns false if PD contains no PDE for UPAGE. */
154 pagedir_test_dirty (uint32_t *pd, const void *upage)
156 uint32_t *pte = lookup_page (pd, (void *) upage, false);
157 return pte != NULL && (*pte & PG_D) != 0;
160 /* Returns true if the PTE for user virtual page UPAGE in PD has
161 been accessed recently, that is, between the time the PTE was
162 installed and the last time it was cleared.
163 Returns false if PD contains no PDE for UPAGE. */
165 pagedir_test_accessed (uint32_t *pd, const void *upage)
167 uint32_t *pte = lookup_page (pd, (void *) upage, false);
168 return pte != NULL && (*pte & PG_A) != 0;
171 /* Resets the accessed bit in the PTE for user virtual page UPAGE
174 pagedir_clear_accessed (uint32_t *pd, const void *upage)
176 uint32_t *pte = lookup_page (pd, (void *) upage, false);
178 *pte &= ~(uint32_t) PG_A;
181 /* Loads page directory PD into the CPU's page directory base
184 pagedir_activate (uint32_t *pd)
188 asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
191 /* Returns the currently active page directory. */
197 asm ("movl %%cr3,%0" : "=r" (pd));