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