Splits x86 into 32 and 64 bit (XCC)
[akaros.git] / kern / arch / x86 / pmap64.c
1 #ifdef __SHARC__
2 #pragma nosharc
3 #define SINIT(x) x
4 #endif
5
6 /* See COPYRIGHT for copyright information. */
7 #include <arch/x86.h>
8 #include <arch/arch.h>
9 #include <arch/mmu.h>
10 #include <arch/apic.h>
11
12 #include <error.h>
13 #include <sys/queue.h>
14
15 #include <atomic.h>
16 #include <string.h>
17 #include <assert.h>
18 #include <pmap.h>
19 #include <kclock.h>
20 #include <env.h>
21 #include <stdio.h>
22 #include <kmalloc.h>
23 #include <page_alloc.h>
24
25 // These variables are set in i386_vm_init()
26 pde_t* boot_pgdir;              // Virtual address of boot time page directory
27 physaddr_t RO boot_cr3;         // Physical address of boot time page directory
28
29 // Global variables
30 page_t *RO pages = NULL;          // Virtual address of physical page array
31
32 // Global descriptor table.
33 //
34 // The kernel and user segments are identical (except for the DPL).
35 // To load the SS register, the CPL must equal the DPL.  Thus,
36 // we must duplicate the segments for the user and the kernel.
37 //
38 segdesc_t gdt[] =
39 {
40         // 0x0 - unused (always faults -- for trapping NULL far pointers)
41         SEG_NULL,
42
43         // 0x8 - kernel code segment
44         [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
45
46         // 0x10 - kernel data segment
47         [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
48
49         // 0x18 - user code segment
50         [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
51
52         // 0x20 - user data segment
53         [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
54
55         // 0x28 - tss, initialized in idt_init()
56         [GD_TSS >> 3] = SEG_NULL,
57
58         // 0x30 - LDT, set per-process
59         [GD_LDT >> 3] = SEG_NULL
60 };
61
62 pseudodesc_t gdt_pd = {
63         /* 64 bit compiler complains about this.  going to redo it anyways. */
64         //sizeof(gdt) - 1, (unsigned long) gdt
65         sizeof(gdt) - 1, 0xdeadbeef
66 };
67
68 // --------------------------------------------------------------
69 // Set up initial memory mappings and turn on MMU.
70 // --------------------------------------------------------------
71
72 static void check_boot_pgdir(bool pse);
73
74 //
75 // Given pgdir, a pointer to a page directory,
76 // walk the 2-level page table structure to find
77 // the page table entry (PTE) for linear address la.
78 // Return a pointer to this PTE.
79 //
80 // If the relevant page table doesn't exist in the page directory:
81 //      - If create == 0, return 0.
82 //      - Otherwise allocate a new page table, install it into pgdir,
83 //        and return a pointer into it.
84 //        (Questions: What data should the new page table contain?
85 //        And what permissions should the new pgdir entry have?
86 //        Note that we use the 486-only "WP" feature of %cr0, which
87 //        affects the way supervisor-mode writes are checked.)
88 //
89 // This function abstracts away the 2-level nature of
90 // the page directory by allocating new page tables
91 // as needed.
92 // 
93 // boot_pgdir_walk may ONLY be used during initialization,
94 // before the page_free_list has been set up.
95 // It should panic on failure.  (Note that boot_alloc already panics
96 // on failure.)
97 //
98 // Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
99 // 
100 // Maps non-PSE PDEs as U/W.  W so the kernel can, U so the user can read via
101 // UVPT.  UVPT security comes from the UVPT mapping (U/R).  All other kernel pages
102 // protected at the second layer
103 static pte_t*
104 boot_pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, int create)
105 {
106         pde_t* the_pde = &pgdir[PDX(la)];
107         void* new_table;
108
109         if (*the_pde & PTE_P) {
110                 if (*the_pde & PTE_PS)
111                         return (pte_t*)the_pde;
112                 return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
113         }
114         if (!create)
115                 return NULL;
116         if (create == 2) {
117                 if (JPGOFF(la))
118                         panic("Attempting to find a Jumbo PTE at an unaligned VA!");
119                 *the_pde = PTE_PS | PTE_P;
120                 return (pte_t*)the_pde;
121         }
122         new_table = boot_alloc(PGSIZE, PGSIZE);
123         memset(new_table, 0, PGSIZE);
124         *the_pde = (pde_t)PADDR(new_table) | PTE_P | PTE_W | PTE_U | PTE_G;
125         return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
126 }
127
128 //
129 // Map [la, la+size) of linear address space to physical [pa, pa+size)
130 // in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
131 // Use permission bits perm|PTE_P for the entries.
132 //
133 // This function may ONLY be used during initialization,
134 // before the page_free_list has been set up.
135 //
136 // To map with Jumbos, set PTE_PS in perm
137 static void
138 boot_map_segment(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
139 {
140         uintptr_t i;
141         pte_t *pte;
142         // la can be page unaligned, but weird things will happen
143         // unless pa has the same offset.  pa always truncates any
144         // possible offset.  will warn.  size can be weird too. 
145         if (PGOFF(la)) {
146                 warn("la not page aligned in boot_map_segment!");
147                 size += PGOFF(la);
148         }
149         if (perm & PTE_PS) {
150                 if (JPGOFF(la) || JPGOFF(pa))
151                         panic("Tried to map a Jumbo page at an unaligned address!");
152                 // need to index with i instead of la + size, in case of wrap-around
153                 for (i = 0; i < size; i += JPGSIZE, la += JPGSIZE, pa += JPGSIZE) {
154                         pte = boot_pgdir_walk(pgdir, la, 2);
155                         *pte = PTE_ADDR(pa) | PTE_P | perm;
156                 }
157         } else {
158                 for (i = 0; i < size; i += PGSIZE, la += PGSIZE, pa += PGSIZE) {
159                         pte = boot_pgdir_walk(pgdir, la, 1);
160                         if (*pte & PTE_PS)
161                                 // if we start using the extra flag for PAT, which we aren't,
162                                 // this will warn, since PTE_PS and PTE_PAT are the same....
163                                 warn("Possibly attempting to map a regular page into a Jumbo PDE");
164                         *pte = PTE_ADDR(pa) | PTE_P | perm;
165                 }
166         }
167 }
168
169 // Set up a two-level page table:
170 //    boot_pgdir is its linear (virtual) address of the root
171 //    boot_cr3 is the physical adresss of the root
172 // Then turn on paging.  Then effectively turn off segmentation.
173 // (i.e., the segment base addrs are set to zero).
174 // 
175 // This function only sets up the kernel part of the address space
176 // (ie. addresses >= ULIM).  The user part of the address space
177 // will be setup later.
178 //
179 // From UWLIM to ULIM, the user is allowed to read but not write.
180 // Above ULIM the user cannot read (or write). 
181 void
182 vm_init(void)
183 {
184         pde_t* pgdir;
185         uint32_t cr0, edx;
186         size_t n;
187         bool pse;
188
189         pse = enable_pse();
190         if (pse)
191                 cprintf("PSE capability detected.\n");
192
193         // we paniced earlier if we don't support PGE.  turn it on now.
194         // it's used in boot_map_segment, which covers all of the mappings that are
195         // the same for all address spaces.  and also for the VPT mapping below.
196         lcr4(rcr4() | CR4_PGE);
197
198         // set up mtrr's for core0.  other cores will do the same later
199         setup_default_mtrrs(0);
200
201         /*
202          * PSE status: 
203          * - can walk and set up boot_map_segments with jumbos but can't
204          *   insert yet.  need to look at the page_dir and friends.
205          * - anything related to a single struct page still can't handle 
206          *   jumbos.  will need to think about and adjust Page functions
207          * - do we want to store info like this in the struct page?  or just check
208          *   by walking the PTE
209          * - when we alloc a page, and we want it to be 4MB, we'll need
210          *   to have contiguous memory, etc
211          * - there's a difference between having 4MB page table entries
212          *   and having 4MB Page tracking structs.  changing the latter will
213          *   break a lot of things
214          * - showmapping and friends work on a 4KB granularity, but map to the
215          *   correct entries
216          * - need to not insert / boot_map a single page into an area that is 
217          *   already holding a jumbo page.  will need to break the jumbo up so that
218          *   we can then insert the lone page.  currently warns.
219          * - some inherent issues with the pgdir_walks returning a PTE, and we
220          *   don't know whether it is a jumbo (PDE) or a regular PTE.
221          */
222
223         //////////////////////////////////////////////////////////////////////
224         // create initial page directory.
225         pgdir = boot_alloc(PGSIZE, PGSIZE);
226         memset(pgdir, 0, PGSIZE);
227         boot_pgdir = pgdir;
228         boot_cr3 = PADDR(pgdir);
229         // helpful if you want to manually walk with kvm / bochs
230         //printk("pgdir va = %p, pgdir pa = %p\n\n", pgdir, PADDR(pgdir));
231
232         //////////////////////////////////////////////////////////////////////
233         // Recursively insert PD in itself as a page table, to form
234         // a virtual page table at virtual address VPT.
235         // (For now, you don't have understand the greater purpose of the
236         // following two lines.  Unless you are eagle-eyed, in which case you
237         // should already know.)
238
239         // Permissions: kernel RW, user NONE, Global Page
240         pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P | PTE_G;
241
242         // same for UVPT
243         // Permissions: kernel R, user R, Global Page
244         pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P | PTE_G;
245
246         //////////////////////////////////////////////////////////////////////
247         // Map all of physical memory at KERNBASE. 
248         // Ie.  the VA range [KERNBASE, 2^32) should map to
249         //      the PA range [0, 2^32 - KERNBASE)
250         // We might not have 2^32 - KERNBASE bytes of physical memory, but
251         // we just set up the mapping anyway.
252         // Permissions: kernel RW, user NONE
253         // Your code goes here: 
254         
255         // this maps all of the possible phys memory
256         // note the use of unsigned underflow to get size = 0x40000000
257         //boot_map_segment(pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
258         // but this only maps what is available, and saves memory.  every 4MB of
259         // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
260         // need to modify tests below to account for this
261         if (pse) {
262                 // map the first 4MB as regular entries, to support different MTRRs
263                 boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W | PTE_G);
264                 boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxaddrpa - JPGSIZE, JPGSIZE,
265                                  PTE_W | PTE_G | PTE_PS);
266         } else
267                 boot_map_segment(pgdir, KERNBASE, maxaddrpa, 0, PTE_W | PTE_G);
268
269         // APIC mapping: using PAT (but not *the* PAT flag) to make these type UC
270         // IOAPIC
271         boot_map_segment(pgdir, IOAPIC_BASE, PGSIZE, IOAPIC_PBASE, 
272                          PTE_PCD | PTE_PWT | PTE_W | PTE_G);
273         // Local APIC
274         boot_map_segment(pgdir, LAPIC_BASE, PGSIZE, LAPIC_PBASE,
275                          PTE_PCD | PTE_PWT | PTE_W | PTE_G);
276
277         // Check that the initial page directory has been set up correctly.
278         check_boot_pgdir(pse);
279
280         //////////////////////////////////////////////////////////////////////
281         // On x86, segmentation maps a VA to a LA (linear addr) and
282         // paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is
283         // turned off the LA is used as the PA.  Note: there is no way to
284         // turn off segmentation.  The closest thing is to set the base
285         // address to 0, so the VA => LA mapping is the identity.
286
287         // Current mapping: VA KERNBASE+x => PA x.
288         //     (segmentation base=-KERNBASE and paging is off)
289
290         // From here on down we must maintain this VA KERNBASE + x => PA x
291         // mapping, even though we are turning on paging and reconfiguring
292         // segmentation.
293
294         // Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.
295         // (Limits our kernel to <4MB)
296         /* They mean linear address 0:4MB, and the kernel < 4MB is only until 
297          * segmentation is turned off.
298          * once we turn on paging, segmentation is still on, so references to
299          * KERNBASE+x will get mapped to linear address x, which we need to make 
300          * sure can map to phys addr x, until we can turn off segmentation and
301          * KERNBASE+x maps to LA KERNBASE+x, which maps to PA x, via paging
302          */
303         pgdir[0] = pgdir[PDX(KERNBASE)];
304
305         // Install page table.
306         lcr3(boot_cr3);
307
308         // Turn on paging.
309         cr0 = rcr0();
310         // CD and NW should already be on, but just in case these turn on caching
311         cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
312         cr0 &= ~(CR0_TS|CR0_EM|CR0_CD|CR0_NW);
313         lcr0(cr0);
314
315         // Current mapping: KERNBASE+x => x => x.
316         // (x < 4MB so uses paging pgdir[0])
317
318         // Reload all segment registers. 
319
320         /* Pending 64b rewrite */
321         //asm volatile("lgdt gdt_pd");
322         //asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
323         //asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
324         //asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
325         //asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
326         //asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
327         //asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs
328         //asm volatile("lldt %%ax" :: "a" (0));
329
330         // Final mapping: KERNBASE+x => KERNBASE+x => x.
331
332         // This mapping was only used after paging was turned on but
333         // before the segment registers were reloaded.
334         pgdir[0] = 0;
335
336         // Flush the TLB for good measure, to kill the pgdir[0] mapping.
337         tlb_flush_global();
338 }
339
340 //
341 // Checks that the kernel part of virtual address space
342 // has been setup roughly correctly(by i386_vm_init()).
343 //
344 // This function doesn't test every corner case,
345 // in fact it doesn't test the permission bits at all,
346 // but it is a pretty good sanity check. 
347 //
348 static physaddr_t check_va2pa(pde_t *COUNT(NPDENTRIES) pgdir, uintptr_t va);
349
350 static void
351 check_boot_pgdir(bool pse)
352 {
353         unsigned long i, n;
354         pde_t *pgdir, pte;
355
356         pgdir = boot_pgdir;
357
358         // check phys mem
359         //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
360         // adjusted check to account for only mapping avail mem
361         if (pse)
362                 for (i = 0; i < maxaddrpa; i += JPGSIZE)
363                         assert(check_va2pa(pgdir, KERNBASE + i) == i);
364         else
365                 for (i = 0; i < maxaddrpa; i += PGSIZE)
366                         assert(check_va2pa(pgdir, KERNBASE + i) == i);
367
368         // check for zero/non-zero in PDEs
369         for (i = 0; i < NPDENTRIES; i++) {
370                 switch (i) {
371                 /* XXX this old PDX shit is broken with 4 PMLs */
372                 //case PDX(VPT):
373                 //case PDX(UVPT):
374                 case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
375                         assert(pgdir[i]);
376                         break;
377                 default:
378                         //if (i >= PDX(KERNBASE))
379                         // adjusted check to account for only mapping avail mem
380                         // and you can't KADDR maxpa (just above legal range)
381                         // maxaddrpa can be up to maxpa, so assume the worst
382                         if (i >= PDX(KERNBASE) && i <= PDX(KADDR(maxaddrpa-1)))
383                                 assert(pgdir[i]);
384                         else
385                                 assert(pgdir[i] == 0);
386                         break;
387                 }
388         }
389
390         /* check permissions
391          * user read-only.  check for user and write, should be only user
392          * eagle-eyed viewers should be able to explain the extra cases.
393          * for the mongoose-eyed, remember that weird shit happens when you loop
394          * through UVPT.  Specifically, you can't loop once, then look at a jumbo
395          * page that is kernel only.  That's the end of the page table for you, so
396          * having a U on the entry doesn't make sense.  Thus we check for a jumbo
397          * page, and special case it.  This will happen at 0xbf701000.  Why is this
398          * magical?  Get your eagle glasses and figure it out. */
399         for (i = UWLIM; i < ULIM; i+=PGSIZE) {
400                 pte = get_va_perms(pgdir, (void*SAFE)TC(i));
401                 if (pte & PTE_P) {
402                         if (i == UVPT+(VPT >> 10))
403                                 continue;
404                         if (*pgdir_walk(pgdir, (void*SAFE)TC(i), 0) & PTE_PS) {
405                                 assert((pte & PTE_U) != PTE_U);
406                                 assert((pte & PTE_W) != PTE_W);
407                         } else {
408                                 assert((pte & PTE_U) == PTE_U);
409                                 assert((pte & PTE_W) != PTE_W);
410                         }
411                 }
412         }
413         // kernel read-write.
414         for (i = ULIM; i <= KERNBASE + maxaddrpa - PGSIZE; i+=PGSIZE) {
415                 pte = get_va_perms(pgdir, (void*SAFE)TC(i));
416                 if ((pte & PTE_P) && (i != VPT+(UVPT>>10))) {
417                         assert((pte & PTE_U) != PTE_U);
418                         assert((pte & PTE_W) == PTE_W);
419                 }
420         }
421         // special mappings
422         pte = get_va_perms(pgdir, (void*SAFE)TC(UVPT+(VPT>>10)));
423         assert((pte & PTE_U) != PTE_U);
424         assert((pte & PTE_W) != PTE_W);
425
426         // note this means the kernel cannot directly manipulate this virtual address
427         // convince yourself this isn't a big deal, eagle-eyes!
428         pte = get_va_perms(pgdir, (void*SAFE)TC(VPT+(UVPT>>10)));
429         assert((pte & PTE_U) != PTE_U);
430         assert((pte & PTE_W) != PTE_W);
431
432         cprintf("check_boot_pgdir() succeeded!\n");
433 }
434
435 // This function returns the physical address of the page containing 'va',
436 // defined by the page directory 'pgdir'.  The hardware normally performs
437 // this functionality for us!  We define our own version to help check
438 // the check_boot_pgdir() function; it shouldn't be used elsewhere.
439
440 static physaddr_t
441 check_va2pa(pde_t *COUNT(NPDENTRIES) _pgdir, uintptr_t va)
442 {
443         pte_t *COUNT(NPTENTRIES) p;
444         pde_t *COUNT(1) pgdir;
445
446         pgdir = &_pgdir[PDX(va)];
447         if (!(*pgdir & PTE_P))
448                 return ~0;
449         if (*pgdir & PTE_PS)
450                 return PTE_ADDR(*pgdir);
451         p = (pte_t*COUNT(NPTENTRIES)) KADDR(PTE_ADDR(*pgdir));
452         if (!(p[PTX(va)] & PTE_P))
453                 return ~0;
454         return PTE_ADDR(p[PTX(va)]);
455 }
456
457 /* 
458  * Remove the second level page table associated with virtual address va.
459  * Will 0 out the PDE for that page table.
460  * Panics if the page table has any present entries.
461  * This should be called rarely and with good cause.
462  * Currently errors if the PDE is jumbo or not present.
463  */
464 error_t pagetable_remove(pde_t *pgdir, void *va)
465 {
466         pde_t* the_pde = &pgdir[PDX(va)];
467
468         if (!(*the_pde & PTE_P) || (*the_pde & PTE_PS))
469                 return -EFAULT;
470         pte_t* page_table = (pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde));
471         for (int i = 0; i < NPTENTRIES; i++) 
472                 if (page_table[i] & PTE_P)
473                         panic("Page table not empty during attempted removal!");
474         *the_pde = 0;
475         page_decref(pa2page(PADDR(page_table)));
476         return 0;
477 }
478
479 // Given 'pgdir', a pointer to a page directory, pgdir_walk returns
480 // a pointer to the page table entry (PTE) for linear address 'va'.
481 // This requires walking the two-level page table structure.
482 //
483 // If the relevant page table doesn't exist in the page directory, then:
484 //    - If create == 0, pgdir_walk returns NULL.
485 //    - Otherwise, pgdir_walk tries to allocate a new page table
486 //      with page_alloc.  If this fails, pgdir_walk returns NULL.
487 //    - Otherwise, pgdir_walk returns a pointer into the new page table.
488 //
489 // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
490 // Unlike boot_pgdir_walk, pgdir_walk can fail.
491 //
492 // Hint: you can turn a Page * into the physical address of the
493 // page it refers to with page2pa() from kern/pmap.h.
494 //
495 // Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
496 pte_t*
497 pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
498 {
499         pde_t* the_pde = &pgdir[PDX(va)];
500         page_t *new_table;
501
502         if (*the_pde & PTE_P) {
503                 if (*the_pde & PTE_PS)
504                         return (pte_t*)the_pde;
505                 return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
506         }
507         if (!create)
508                 return NULL;
509         if (create == 2) {
510                 if (JPGOFF(va))
511                         panic("Attempting to find a Jumbo PTE at an unaligned VA!");
512                 *the_pde = PTE_PS | PTE_P;
513                 return (pte_t*)the_pde;
514         }
515         if (kpage_alloc(&new_table))
516                 return NULL;
517         memset(page2kva(new_table), 0, PGSIZE);
518         /* storing our ref to new_table in the PTE */
519         *the_pde = (pde_t)page2pa(new_table) | PTE_P | PTE_W | PTE_U;
520         return &((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
521 }
522
523 /* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given
524  * virtual address.  Note we need to consider the composition of every PTE in
525  * the page table walk. */
526 int get_va_perms(pde_t *pgdir, const void *SNT va)
527 {
528         pde_t the_pde = pgdir[PDX(va)];
529         pte_t the_pte;
530
531         if (!(the_pde & PTE_P))
532                 return 0;
533         if (the_pde & PTE_PS)
534                 return the_pde & (PTE_U | PTE_W | PTE_P);
535         the_pte = ((pde_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(the_pde)))[PTX(va)];
536         if (!(the_pte & PTE_P))
537                 return 0;
538         return the_pte & the_pde & (PTE_U | PTE_W | PTE_P);
539 }
540
541 void
542 page_check(void)
543 {
544         page_t *pp, *pp0, *pp1, *pp2;
545         page_list_t fl[1024];
546         pte_t *ptep;
547
548         // should be able to allocate three pages
549         pp0 = pp1 = pp2 = 0;
550         assert(kpage_alloc(&pp0) == 0);
551         assert(kpage_alloc(&pp1) == 0);
552         assert(kpage_alloc(&pp2) == 0);
553
554         assert(pp0);
555         assert(pp1 && pp1 != pp0);
556         assert(pp2 && pp2 != pp1 && pp2 != pp0);
557
558         // temporarily steal the rest of the free pages
559         for(int i=0; i<llc_cache->num_colors; i++) {
560                 fl[i] = colored_page_free_list[i];
561                 LIST_INIT(&colored_page_free_list[i]);
562         }
563
564         // should be no free memory
565         assert(kpage_alloc(&pp) == -ENOMEM);
566
567         // Fill pp1 with bogus data and check for invalid tlb entries
568         memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
569
570         // there is no page allocated at address 0
571         assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
572
573         // there is no free memory, so we can't allocate a page table 
574         assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
575
576         // free pp0 and try again: pp0 should be used for page table
577         page_decref(pp0);
578         assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
579         tlb_invalidate(boot_pgdir, 0x0);
580         // DEP Should have shot down invalid TLB entry - let's check
581         { TRUSTEDBLOCK
582           int *x = 0x0;
583           assert(*x == 0xFFFFFFFF);
584         }
585         assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
586         assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
587         assert(kref_refcnt(&pp1->pg_kref) == 2);
588         assert(kref_refcnt(&pp0->pg_kref) == 1);
589
590         // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
591         assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, 0) == 0);
592         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
593         assert(kref_refcnt(&pp2->pg_kref) == 2);
594
595         // Make sure that pgdir_walk returns a pointer to the pte and
596         // not the table or some other garbage
597         {
598           pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)]));
599           assert(pgdir_walk(boot_pgdir, (void *SNT)PGSIZE, 0) == &p[PTX(PGSIZE)]);
600         }
601
602         // should be no free memory
603         assert(kpage_alloc(&pp) == -ENOMEM);
604
605         // should be able to map pp2 at PGSIZE because it's already there
606         assert(page_insert(boot_pgdir, pp2, (void*SNT) PGSIZE, PTE_U) == 0);
607         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
608         assert(kref_refcnt(&pp2->pg_kref) == 2);
609
610         // Make sure that we actually changed the permission on pp2 when we re-mapped it
611         {
612           pte_t *p = pgdir_walk(boot_pgdir, (void*SNT)PGSIZE, 0);
613           assert(((*p) & PTE_U) == PTE_U);
614         }
615
616         // pp2 should NOT be on the free list
617         // could happen if ref counts are handled sloppily in page_insert
618         assert(kpage_alloc(&pp) == -ENOMEM);
619
620         // should not be able to map at PTSIZE because need free page for page table
621         assert(page_insert(boot_pgdir, pp0, (void*SNT) PTSIZE, 0) < 0);
622
623         // insert pp1 at PGSIZE (replacing pp2)
624         assert(page_insert(boot_pgdir, pp1, (void*SNT) PGSIZE, 0) == 0);
625
626         // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
627         assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
628         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
629         // ... and ref counts should reflect this
630         assert(kref_refcnt(&pp1->pg_kref) == 3);
631         assert(kref_refcnt(&pp2->pg_kref) == 1);
632
633         // pp2 should be returned by page_alloc
634         page_decref(pp2);       /* should free it */
635         assert(kpage_alloc(&pp) == 0 && pp == pp2);
636
637         // unmapping pp1 at 0 should keep pp1 at PGSIZE
638         page_remove(boot_pgdir, 0x0);
639         assert(check_va2pa(boot_pgdir, 0x0) == ~0);
640         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
641         assert(kref_refcnt(&pp1->pg_kref) == 2);
642         assert(kref_refcnt(&pp2->pg_kref) == 1);
643
644         // unmapping pp1 at PGSIZE should free it
645         page_remove(boot_pgdir, (void*SNT) PGSIZE);
646         assert(check_va2pa(boot_pgdir, 0x0) == ~0);
647         assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
648         assert(kref_refcnt(&pp1->pg_kref) == 1);
649         assert(kref_refcnt(&pp2->pg_kref) == 1);
650         page_decref(pp1);
651
652         // so it should be returned by page_alloc
653         assert(kpage_alloc(&pp) == 0 && pp == pp1);
654
655         // should be no free memory
656         assert(kpage_alloc(&pp) == -ENOMEM);
657
658         // forcibly take pp0 back
659         assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
660         boot_pgdir[0] = 0;
661         assert(kref_refcnt(&pp0->pg_kref) == 1);
662
663         // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
664         {
665           // Give back pp0 for a bit
666           page_decref(pp0);
667
668           void *SNT va = (void *SNT)((PGSIZE * NPDENTRIES) + PGSIZE);
669           pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
670           pte_t *p = (pte_t*COUNT(NPTENTRIES))KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));
671           assert(p2 == &p[PTX(va)]);
672
673           // Clean up again
674           boot_pgdir[PDX(va)] = 0;
675         }
676
677         // give free list back
678         for(int i=0; i<llc_cache->num_colors; i++)
679                 colored_page_free_list[i] = fl[i];
680
681         // free the pages we took
682         page_decref(pp0);
683         page_decref(pp1);
684         page_decref(pp2);
685         assert(!kref_refcnt(&pp0->pg_kref));
686         assert(!kref_refcnt(&pp1->pg_kref));
687         assert(!kref_refcnt(&pp2->pg_kref));
688
689         cprintf("page_check() succeeded!\n");
690 }
691
692 /* Walks len bytes from start, executing 'callback' on every PTE, passing it a
693  * specific VA and whatever arg is passed in.  Note, this cannot handle jumbo
694  * pages. */
695 int env_user_mem_walk(env_t* e, void* start, size_t len,
696                       mem_walk_callback_t callback, void* arg)
697 {
698         pte_t *pt;
699         uintptr_t pdeno, pteno;
700         physaddr_t pa;
701
702         assert((uintptr_t)start % PGSIZE == 0 && len % PGSIZE == 0);
703         void* end = (char*)start+len;
704         uintptr_t pdeno_start = PDX(start);
705         uintptr_t pdeno_end = PDX(ROUNDUP(end,PTSIZE));
706         /* concerned about overflow.  this should catch it for now, given the above
707          * assert. */
708         assert((len == 0) || (pdeno_start < pdeno_end));
709
710         for (pdeno = pdeno_start; pdeno < pdeno_end; pdeno++) {
711                 if (!(e->env_pgdir[pdeno] & PTE_P))
712                         continue;
713                 /* find the pa and a pointer to the page table */
714                 pa = PTE_ADDR(e->env_pgdir[pdeno]);
715                 pt = (pte_t*COUNT(NPTENTRIES)) KADDR(pa);
716                 /* figure out where we start and end within the page table */
717                 uintptr_t pteno_start = (pdeno == pdeno_start ? PTX(start) : 0);
718                 uintptr_t pteno_end = (pdeno == pdeno_end - 1 && PTX(end) != 0 ?
719                                       PTX(end) : NPTENTRIES );
720                 int ret;
721                 for (pteno = pteno_start; pteno < pteno_end; pteno++) {
722                         if (!PAGE_UNMAPPED(pt[pteno]))
723                                 if((ret = callback(e, &pt[pteno], PGADDR(pdeno, pteno, 0), arg)))
724                                         return ret;
725                 }
726         }
727         return 0;
728 }
729
730 /* Frees (decrefs) all pages of the process's page table, including the page
731  * directory.  Does not free the memory that is actually mapped. */
732 void env_pagetable_free(env_t* e)
733 {
734         static_assert(UVPT % PTSIZE == 0);
735         assert(e->env_cr3 != rcr3());
736         for(uint32_t pdeno = 0; pdeno < PDX(UVPT); pdeno++)
737         {
738                 // only look at mapped page tables
739                 if (!(e->env_pgdir[pdeno] & PTE_P))
740                         continue;
741
742                 // find the pa and va of the page table
743                 physaddr_t pa = PTE_ADDR(e->env_pgdir[pdeno]);
744
745                 // free the page table itself
746                 e->env_pgdir[pdeno] = 0;
747                 page_decref(pa2page(pa));
748         }
749
750         // free the page directory
751         physaddr_t pa = e->env_cr3;
752         e->env_cr3 = 0;
753         page_decref(pa2page(pa));
754         tlbflush();
755 }
756
757 /* 
758
759     // testing code for boot_pgdir_walk 
760         pte_t* temp;
761         temp = boot_pgdir_walk(pgdir, VPT + (VPT >> 10), 1);
762         cprintf("pgdir = %p\n", pgdir);
763         cprintf("test recursive walking pte_t* = %p\n", temp);
764         cprintf("test recursive walking entry = %p\n", PTE_ADDR(temp));
765         temp = boot_pgdir_walk(pgdir, 0xc0400000, 1);
766         cprintf("LA = 0xc0400000 = %p\n", temp);
767         temp = boot_pgdir_walk(pgdir, 0xc0400070, 1);
768         cprintf("LA = 0xc0400070 = %p\n", temp);
769         temp = boot_pgdir_walk(pgdir, 0xc0800000, 0);
770         cprintf("LA = 0xc0800000, no create = %p\n", temp);
771         temp = boot_pgdir_walk(pgdir, 0xc0600070, 1);
772         cprintf("LA = 0xc0600070 = %p\n", temp);
773         temp = boot_pgdir_walk(pgdir, 0xc0600090, 0);
774         cprintf("LA = 0xc0600090, nc = %p\n", temp);
775         temp = boot_pgdir_walk(pgdir, 0xc0608070, 0);
776         cprintf("LA = 0xc0608070, nc = %p\n", temp);
777         temp = boot_pgdir_walk(pgdir, 0xc0800070, 1);
778         cprintf("LA = 0xc0800070 = %p\n", temp);
779         temp = boot_pgdir_walk(pgdir, 0xc0b00070, 0);
780         cprintf("LA = 0xc0b00070, nc = %p\n", temp);
781         temp = boot_pgdir_walk(pgdir, 0xc0c00000, 0);
782         cprintf("LA = 0xc0c00000, nc = %p\n", temp);
783
784         // testing for boot_map_seg
785         cprintf("\n");
786         cprintf("before mapping 1 page to 0x00350000\n");
787         cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
788         cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
789         boot_map_segment(pgdir, 0xc4000000, 4096, 0x00350000, PTE_W);
790         cprintf("after mapping\n");
791         cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
792         cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
793
794         cprintf("\n");
795         cprintf("before mapping 3 pages to 0x00700000\n");
796         cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
797         cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
798         cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
799         cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
800         cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
801         cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
802         boot_map_segment(pgdir, 0xd0000000, 4096*3, 0x00700000, 0);
803         cprintf("after mapping\n");
804         cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
805         cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
806         cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
807         cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
808         cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
809         cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
810
811         cprintf("\n");
812         cprintf("before mapping 1 unaligned to 0x00500010\n");
813         cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
814         cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
815         cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
816         cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
817         boot_map_segment(pgdir, 0xc8000010, 4096, 0x00500010, PTE_W);
818         cprintf("after mapping\n");
819         cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
820         cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
821         cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
822         cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
823
824         cprintf("\n");
825         boot_map_segment(pgdir, 0xe0000000, 4096, 0x10000000, PTE_W);
826
827 */