00001 #include "userprog/pagedir.h"
00002
00003 #include <stdbool.h>
00004 #include <stddef.h>
00005 #include <string.h>
00006 #include "threads/init.h"
00007 #include "threads/pte.h"
00008 #include "threads/palloc.h"
00009
00010 static uint32_t *active_pd (void);
00011 static void invalidate_pagedir (uint32_t *);
00012
00013
00014
00015
00016
00017 uint32_t *
00018 pagedir_create (void)
00019 {
00020 uint32_t *pd = palloc_get_page (0);
00021 if (pd != NULL)
00022 memcpy (pd, base_page_dir, PGSIZE);
00023 return pd;
00024 }
00025
00026
00027
00028 void
00029 pagedir_destroy (uint32_t *pd)
00030 {
00031 uint32_t *pde;
00032
00033 if (pd == NULL)
00034 return;
00035
00036 ASSERT (pd != base_page_dir);
00037 for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
00038 if (*pde & PTE_P)
00039 {
00040 uint32_t *pt = pde_get_pt (*pde);
00041 uint32_t *pte;
00042
00043 for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
00044 if (*pte & PTE_P)
00045 palloc_free_page (pte_get_page (*pte));
00046 palloc_free_page (pt);
00047 }
00048 palloc_free_page (pd);
00049 }
00050
00051
00052
00053
00054
00055
00056
00057 static uint32_t *
00058 lookup_page (uint32_t *pd, const void *vaddr, bool create)
00059 {
00060 uint32_t *pt, *pde;
00061
00062 ASSERT (pd != NULL);
00063
00064
00065 ASSERT (!create || is_user_vaddr (vaddr));
00066
00067
00068
00069 pde = pd + pd_no (vaddr);
00070 if (*pde == 0)
00071 {
00072 if (create)
00073 {
00074 pt = palloc_get_page (PAL_ZERO);
00075 if (pt == NULL)
00076 return NULL;
00077
00078 *pde = pde_create_user (pt);
00079 }
00080 else
00081 return NULL;
00082 }
00083
00084
00085 pt = pde_get_pt (*pde);
00086 return &pt[pt_no (vaddr)];
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 bool
00100 pagedir_set_page (uint32_t *pd, void *upage, void *kpage, bool writable)
00101 {
00102 uint32_t *pte;
00103
00104 ASSERT (pg_ofs (upage) == 0);
00105 ASSERT (pg_ofs (kpage) == 0);
00106 ASSERT (is_user_vaddr (upage));
00107 ASSERT (vtop (kpage) >> PTSHIFT < ram_pages);
00108 ASSERT (pd != base_page_dir);
00109
00110 pte = lookup_page (pd, upage, true);
00111
00112 if (pte != NULL)
00113 {
00114 ASSERT ((*pte & PTE_P) == 0);
00115 *pte = pte_create_user (kpage, writable);
00116 return true;
00117 }
00118 else
00119 return false;
00120 }
00121
00122
00123
00124
00125
00126 void *
00127 pagedir_get_page (uint32_t *pd, const void *uaddr)
00128 {
00129 uint32_t *pte;
00130
00131 ASSERT (is_user_vaddr (uaddr));
00132
00133 pte = lookup_page (pd, uaddr, false);
00134 if (pte != NULL && (*pte & PTE_P) != 0)
00135 return pte_get_page (*pte) + pg_ofs (uaddr);
00136 else
00137 return NULL;
00138 }
00139
00140
00141
00142
00143
00144 void
00145 pagedir_clear_page (uint32_t *pd, void *upage)
00146 {
00147 uint32_t *pte;
00148
00149 ASSERT (pg_ofs (upage) == 0);
00150 ASSERT (is_user_vaddr (upage));
00151
00152 pte = lookup_page (pd, upage, false);
00153 if (pte != NULL && (*pte & PTE_P) != 0)
00154 {
00155 *pte &= ~PTE_P;
00156 invalidate_pagedir (pd);
00157 }
00158 }
00159
00160
00161
00162
00163
00164 bool
00165 pagedir_is_dirty (uint32_t *pd, const void *vpage)
00166 {
00167 uint32_t *pte = lookup_page (pd, vpage, false);
00168 return pte != NULL && (*pte & PTE_D) != 0;
00169 }
00170
00171
00172
00173 void
00174 pagedir_set_dirty (uint32_t *pd, const void *vpage, bool dirty)
00175 {
00176 uint32_t *pte = lookup_page (pd, vpage, false);
00177 if (pte != NULL)
00178 {
00179 if (dirty)
00180 *pte |= PTE_D;
00181 else
00182 {
00183 *pte &= ~(uint32_t) PTE_D;
00184 invalidate_pagedir (pd);
00185 }
00186 }
00187 }
00188
00189
00190
00191
00192
00193 bool
00194 pagedir_is_accessed (uint32_t *pd, const void *vpage)
00195 {
00196 uint32_t *pte = lookup_page (pd, vpage, false);
00197 return pte != NULL && (*pte & PTE_A) != 0;
00198 }
00199
00200
00201
00202 void
00203 pagedir_set_accessed (uint32_t *pd, const void *vpage, bool accessed)
00204 {
00205 uint32_t *pte = lookup_page (pd, vpage, false);
00206 if (pte != NULL)
00207 {
00208 if (accessed)
00209 *pte |= PTE_A;
00210 else
00211 {
00212 *pte &= ~(uint32_t) PTE_A;
00213 invalidate_pagedir (pd);
00214 }
00215 }
00216 }
00217
00218
00219
00220 void
00221 pagedir_activate (uint32_t *pd)
00222 {
00223 if (pd == NULL)
00224 pd = base_page_dir;
00225
00226
00227
00228
00229
00230
00231 asm volatile ("movl %0, %%cr3" : : "r" (vtop (pd)) : "memory");
00232 }
00233
00234
00235 static uint32_t *
00236 active_pd (void)
00237 {
00238
00239
00240
00241
00242 uintptr_t pd;
00243 asm volatile ("movl %%cr3, %0" : "=r" (pd));
00244 return ptov (pd);
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 static void
00256 invalidate_pagedir (uint32_t *pd)
00257 {
00258 if (active_pd () == pd)
00259 {
00260
00261
00262 pagedir_activate (pd);
00263 }
00264 }