Comments.
[pintos-anon] / src / userprog / pagedir.c
1 #include "userprog/pagedir.h"
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include "threads/init.h"
6 #include "threads/mmu.h"
7 #include "threads/palloc.h"
8
9 /* Creates a new page directory that has mappings for kernel
10    virtual addresses, but none for user virtual addresses.
11    Returns the new page directory, or a null pointer if memory
12    allocation fails. */
13 uint32_t *
14 pagedir_create (void) 
15 {
16   uint32_t *pd = palloc_get (0);
17   memcpy (pd, base_page_dir, PGSIZE);
18   return pd;
19 }
20
21 /* Destroys page directory PD, freeing all the pages it
22    references. */
23 void
24 pagedir_destroy (uint32_t *pd) 
25 {
26   uint32_t *pde;
27
28   if (pd == NULL)
29     return;
30
31   for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
32     if (*pde & PG_P) 
33       {
34         uint32_t *pt = pde_get_pt (*pde);
35         uint32_t *pte;
36         
37         for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
38           if (*pte & PG_P) 
39             palloc_free (pte_get_page (*pte));
40         palloc_free (pt);
41       }
42   palloc_free (pd);
43 }
44
45 /* Returns the mapping of user virtual address UADDR in page
46    directory PD into a kernel virtual address.
47    If UADDR is unmapped, behavior varies based on CREATE:
48    if CREATE is true, then a new, zeroed page is created and a
49    pointer into it is returned,
50    otherwise a null pointer is returned. */
51 static uint32_t *
52 lookup_page (uint32_t *pd, void *uaddr, bool create)
53 {
54   uint32_t *pt, *pde;
55
56   ASSERT (pd != NULL);
57   ASSERT (uaddr < PHYS_BASE);
58
59   /* Check for a page table for UADDR.
60      If one is missing, create one if requested. */
61   pde = pd + pd_no (uaddr);
62   if (*pde == 0) 
63     {
64       if (create)
65         {
66           pt = palloc_get (PAL_ZERO);
67           if (pt == NULL) 
68             return NULL; 
69       
70           *pde = pde_create (pt);
71         }
72       else
73         return NULL;
74     }
75
76   /* Return the page table entry. */
77   pt = pde_get_pt (*pde);
78   return &pt[pt_no (uaddr)];
79 }
80
81 /* Adds a mapping from user virtual address UPAGE to kernel
82    virtual address KPAGE in page directory PD.
83    UPAGE must not already be mapped.
84    If WRITABLE is true, the new page is read/write;
85    otherwise it is read-only.
86    Returns true if successful, false if memory allocation
87    failed. */
88 bool
89 pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
90                   bool writable) 
91 {
92   uint32_t *pte;
93
94   ASSERT (pg_ofs (upage) == 0);
95   ASSERT (pg_ofs (kpage) == 0);
96   ASSERT (lookup_page (pd, upage, false) == NULL);
97
98   pte = lookup_page (pd, upage, true);
99   if (pte != NULL) 
100     {
101       *pte = pte_create_user (kpage, writable);
102       return true;
103     }
104   else
105     return false;
106 }
107
108 /* Returns the kernel virtual address that user virtual address
109    UADDR is mapped to in PD, or a null pointer if there is no
110    mapping. */
111 void *
112 pagedir_get_page (uint32_t *pd, const void *uaddr) 
113 {
114   uint32_t *pte = lookup_page (pd, (void *) uaddr, false);
115   return pte != NULL && *pte != 0 ? pte_get_page (*pte) : NULL;
116 }
117
118 /* Loads page directory PD into the CPU's page directory base
119    register. */
120 void
121 pagedir_activate (uint32_t *pd) 
122 {
123   if (pd == NULL)
124     pd = base_page_dir;
125   asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
126 }