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