4f06ffaaa3cfd1481019ad796d088b115658e20c
[akaros.git] / kern / pmap.c
1 /* See COPYRIGHT for copyright information. */
2 #ifdef __DEPUTY__
3 #pragma nodeputy
4 #endif
5
6 #include <inc/x86.h>
7 #include <inc/mmu.h>
8 #include <inc/error.h>
9 #include <inc/string.h>
10 #include <inc/assert.h>
11
12 #include <kern/pmap.h>
13 #include <kern/kclock.h>
14 #include <kern/env.h>
15 #include <kern/apic.h>
16 #include <kern/atomic.h>
17
18 // These variables are set by i386_detect_memory()
19 static physaddr_t maxpa;        // Maximum physical address
20 static physaddr_t maxaddrpa;    // Maximum directly addressable physical address
21 size_t npage;                   // Amount of physical memory (in pages)
22 size_t naddrpage;                       // Amount of addressable physical memory (in pages)
23 static size_t basemem;          // Amount of base memory (in bytes)
24 static size_t extmem;           // Amount of extended memory (in bytes)
25
26 // These variables are set in i386_vm_init()
27 pde_t* boot_pgdir;              // Virtual address of boot time page directory
28 physaddr_t boot_cr3;            // Physical address of boot time page directory
29 static char* boot_freemem;      // Pointer to next byte of free mem
30
31 page_t *pages;          // Virtual address of physical page array
32 static page_list_t page_free_list;      // Free list of physical pages
33
34 extern env_t *envs;
35
36 // Global descriptor table.
37 //
38 // The kernel and user segments are identical (except for the DPL).
39 // To load the SS register, the CPL must equal the DPL.  Thus,
40 // we must duplicate the segments for the user and the kernel.
41 //
42 segdesc_t gdt[] =
43 {
44         // 0x0 - unused (always faults -- for trapping NULL far pointers)
45         SEG_NULL,
46
47         // 0x8 - kernel code segment
48         [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
49
50         // 0x10 - kernel data segment
51         [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
52
53         // 0x18 - user code segment
54         [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
55
56         // 0x20 - user data segment
57         [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
58
59         // 0x28 - tss, initialized in idt_init()
60         [GD_TSS >> 3] = SEG_NULL
61 };
62
63 pseudodesc_t gdt_pd = {
64         sizeof(gdt) - 1, (unsigned long) gdt
65 };
66
67 static int
68 nvram_read(int r)
69 {
70         return mc146818_read(r) | (mc146818_read(r + 1) << 8);
71 }
72
73 void i386_print_memory_map(multiboot_info_t *mbi) {
74         const char* memory_type[] = {"", "FREE", "RESERVED", "UNDEFINED", "UNDEFINED4"};
75
76
77         if(CHECK_FLAG(mbi->flags, 6)) {
78                 cprintf ("mmap_addr = 0x%x, mmap_length = 0x%x\n", (unsigned long)mbi->mmap_addr,
79                                                                    (unsigned long)mbi->mmap_length);
80                 
81                 memory_map_t* mmap = (memory_map_t*) ((uint32_t)mbi->mmap_addr + KERNBASE);
82                 while((uint32_t)mmap < ((uint32_t)mbi->mmap_addr + KERNBASE) + mbi->mmap_length) {                      
83                         cprintf ("base = 0x%08x%08x, length = 0x%08x%08x, type = %s\n",
84                                 (unsigned) mmap->base_addr_high,
85                                 (unsigned) mmap->base_addr_low,
86                                 (unsigned) mmap->length_high,
87                                 (unsigned) mmap->length_low,
88                                 (unsigned) memory_type[mmap->type]);
89                         mmap = (memory_map_t*) ((uint32_t) mmap + mmap->size + sizeof (mmap->size));
90                 }
91         }
92 }
93
94 void i386_detect_memory(multiboot_info_t *mbi)
95 {
96         // Tells us how many kilobytes there are
97         basemem = ROUNDDOWN(mbi->mem_lower*1024, PGSIZE);
98         extmem = ROUNDDOWN(mbi->mem_upper*1024, PGSIZE);
99
100         // Calculate the maximum physical address based on whether
101         // or not there is any extended memory.  See comment in <inc/memlayout.h>
102         if (extmem)
103                 maxpa = EXTPHYSMEM + extmem;
104         else
105                 maxpa = basemem;
106
107         npage = maxpa / PGSIZE;
108         // IOAPIC - KERNBASE is the max amount of virtual addresses we can use
109         // for the physical memory mapping (aka - the KERNBASE mapping)
110         maxaddrpa = MIN(maxpa, IOAPIC_BASE - KERNBASE);
111         naddrpage = maxaddrpa / PGSIZE;
112
113         cprintf("Physical memory: %dK available, ", (int)(maxpa/1024));
114         cprintf("base = %dK, extended = %dK\n", (int)(basemem/1024), (int)(extmem/1024));
115         printk("Maximum directly addressable physical memory: %dK\n", (int)(maxaddrpa/1024));
116 }
117
118 bool enable_pse(void)
119 {
120         uint32_t edx, cr4;
121         cpuid(1, 0, 0, 0, &edx);
122         if (edx & CPUID_PSE_SUPPORT) {
123                 cr4 = rcr4();
124                 cr4 |= CR4_PSE;
125                 lcr4(cr4);
126                 return 1;
127         } else
128                 return 0;
129 }
130
131 // --------------------------------------------------------------
132 // Set up initial memory mappings and turn on MMU.
133 // --------------------------------------------------------------
134
135 static void check_boot_pgdir(bool pse);
136
137 //
138 // Allocate n bytes of physical memory aligned on an 
139 // align-byte boundary.  Align must be a power of two.
140 // Return kernel virtual address.  Returned memory is uninitialized.
141 //
142 // If we're out of memory, boot_alloc should panic.
143 // This function may ONLY be used during initialization,
144 // before the page_free_list has been set up.
145 // 
146 static void*
147 boot_alloc(uint32_t n, uint32_t align)
148 {
149         extern char end[];
150         void *v;
151
152         // Initialize boot_freemem if this is the first time.
153         // 'end' is a magic symbol automatically generated by the linker,
154         // which points to the end of the kernel's bss segment -
155         // i.e., the first virtual address that the linker
156         // did _not_ assign to any kernel code or global variables.
157         if (boot_freemem == 0)
158                 boot_freemem = end;
159
160         //      Step 1: round boot_freemem up to be aligned properly
161         boot_freemem = ROUNDUP(boot_freemem, align);
162
163         //      Step 2: save current value of boot_freemem as allocated chunk
164         v = boot_freemem;
165         //  Step 2.5: check if we can alloc
166         if (PADDR(boot_freemem + n) > maxaddrpa)
167                 panic("Out of memory in boot alloc, you fool!\n");
168         //      Step 3: increase boot_freemem to record allocation
169         boot_freemem += n;      
170         //      Step 4: return allocated chunk
171         return v;
172 }
173
174 //
175 // Given pgdir, a pointer to a page directory,
176 // walk the 2-level page table structure to find
177 // the page table entry (PTE) for linear address la.
178 // Return a pointer to this PTE.
179 //
180 // If the relevant page table doesn't exist in the page directory:
181 //      - If create == 0, return 0.
182 //      - Otherwise allocate a new page table, install it into pgdir,
183 //        and return a pointer into it.
184 //        (Questions: What data should the new page table contain?
185 //        And what permissions should the new pgdir entry have?
186 //        Note that we use the 486-only "WP" feature of %cr0, which
187 //        affects the way supervisor-mode writes are checked.)
188 //
189 // This function abstracts away the 2-level nature of
190 // the page directory by allocating new page tables
191 // as needed.
192 // 
193 // boot_pgdir_walk may ONLY be used during initialization,
194 // before the page_free_list has been set up.
195 // It should panic on failure.  (Note that boot_alloc already panics
196 // on failure.)
197 //
198 // Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
199 // 
200 // Maps non-PSE PDEs as U/W.  W so the kernel can, U so the user can read via
201 // UVPT.  UVPT security comes from the UVPT mapping (U/R).  All other kernel pages
202 // protected at the second layer
203 static pte_t*
204 boot_pgdir_walk(pde_t *pgdir, uintptr_t la, int create)
205 {
206         pde_t* the_pde = &pgdir[PDX(la)];
207         void* new_table;
208
209         if (*the_pde & PTE_P) {
210                 if (*the_pde & PTE_PS)
211                         return (pte_t*)the_pde;
212                 return &((pde_t*)KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
213         }
214         if (!create)
215                 return NULL;
216         if (create == 2) {
217                 if (JPGOFF(la))
218                         panic("Attempting to find a Jumbo PTE at an unaligned VA!");
219                 *the_pde = PTE_PS | PTE_P;
220                 return (pte_t*)the_pde;
221         }
222         new_table = boot_alloc(PGSIZE, PGSIZE);
223         memset(new_table, 0, PGSIZE);
224         *the_pde = (pde_t)PADDR(new_table) | PTE_P | PTE_W | PTE_U | PTE_G;
225         return &((pde_t*)KADDR(PTE_ADDR(*the_pde)))[PTX(la)];
226 }
227
228 //
229 // Map [la, la+size) of linear address space to physical [pa, pa+size)
230 // in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
231 // Use permission bits perm|PTE_P for the entries.
232 //
233 // This function may ONLY be used during initialization,
234 // before the page_free_list has been set up.
235 //
236 // To map with Jumbos, set PTE_PS in perm
237 static void
238 boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
239 {
240         uintptr_t i;
241         pte_t *pte;
242         // la can be page unaligned, but weird things will happen
243         // unless pa has the same offset.  pa always truncates any
244         // possible offset.  will warn.  size can be weird too. 
245         if (PGOFF(la)) {
246                 warn("la not page aligned in boot_map_segment!");
247                 size += PGOFF(la);
248         }
249         if (perm & PTE_PS) {
250                 if (JPGOFF(la) || JPGOFF(pa))
251                         panic("Tried to map a Jumbo page at an unaligned address!");
252                 // need to index with i instead of la + size, in case of wrap-around
253                 for (i = 0; i < size; i += JPGSIZE, la += JPGSIZE, pa += JPGSIZE) {
254                         pte = boot_pgdir_walk(pgdir, la, 2);
255                         *pte = PTE_ADDR(pa) | PTE_P | perm;
256                 }
257         } else {
258                 for (i = 0; i < size; i += PGSIZE, la += PGSIZE, pa += PGSIZE) {
259                         pte = boot_pgdir_walk(pgdir, la, 1);
260                         if (*pte & PTE_PS)
261                                 // if we start using the extra flag for PAT, which we aren't,
262                                 // this will warn, since PTE_PS and PTE_PAT are the same....
263                                 warn("Possibly attempting to map a regular page into a Jumbo PDE");
264                         *pte = PTE_ADDR(pa) | PTE_P | perm;
265                 }
266         }
267 }
268
269 // could consider having an API to allow these to dynamically change
270 // MTRRs are for physical, static ranges.  PAT are linear, more granular, and 
271 // more dynamic
272 void setup_default_mtrrs(barrier_t* smp_barrier)
273 {
274         // disable interrupts
275         int8_t state = 0;
276         disable_irqsave(&state);
277         // barrier - if we're meant to do this for all cores, we'll be 
278         // passed a pointer to an initialized barrier
279         if (smp_barrier)
280                 waiton_barrier(smp_barrier);
281         
282         // disable caching      cr0: set CD and clear NW
283         lcr0((rcr0() | CR0_CD) & ~CR0_NW);
284         // flush caches
285         cache_flush();
286         // flush tlb
287         tlb_flush_global();
288         // disable MTRRs, and sets default type to WB (06)
289         write_msr(IA32_MTRR_DEF_TYPE, 0x00000006);
290
291         // Now we can actually safely adjust the MTRRs
292         // MTRR for IO Holes (note these are 64 bit values we are writing)
293         // 0x000a0000 - 0x000c0000 : VGA - WC 0x01
294         write_msr(IA32_MTRR_PHYSBASE0, PTE_ADDR(VGAPHYSMEM) | 0x01);
295         // if we need to have a full 64bit val, use the UINT64 macro
296         write_msr(IA32_MTRR_PHYSMASK0, 0x0000000ffffe0800);
297         // 0x000c0000 - 0x00100000 : IO devices (and ROM BIOS) - UC 0x00
298         write_msr(IA32_MTRR_PHYSBASE1, PTE_ADDR(DEVPHYSMEM) | 0x00);
299         write_msr(IA32_MTRR_PHYSMASK1, 0x0000000ffffc0800);
300         // APIC/IOAPIC holes
301         /* Going to skip them, since we set their mode using PAT when we 
302          * map them in 
303          */
304         // make sure all other MTRR ranges are disabled (should be unnecessary)
305         write_msr(IA32_MTRR_PHYSMASK2, 0);
306         write_msr(IA32_MTRR_PHYSMASK3, 0);
307         write_msr(IA32_MTRR_PHYSMASK4, 0);
308         write_msr(IA32_MTRR_PHYSMASK5, 0);
309         write_msr(IA32_MTRR_PHYSMASK6, 0);
310         write_msr(IA32_MTRR_PHYSMASK7, 0);
311
312         // keeps default type to WB (06), turns MTRRs on, and turns off fixed ranges
313         write_msr(IA32_MTRR_DEF_TYPE, 0x00000806);
314         // reflush caches and TLB
315         cache_flush();
316         tlb_flush_global();
317         // turn on caching
318         lcr0(rcr0() & ~(CR0_CD | CR0_NW));
319         // barrier
320         if (smp_barrier)
321                 waiton_barrier(smp_barrier);
322         // enable interrupts
323         enable_irqsave(&state);
324 }
325
326
327 // Set up a two-level page table:
328 //    boot_pgdir is its linear (virtual) address of the root
329 //    boot_cr3 is the physical adresss of the root
330 // Then turn on paging.  Then effectively turn off segmentation.
331 // (i.e., the segment base addrs are set to zero).
332 // 
333 // This function only sets up the kernel part of the address space
334 // (ie. addresses >= UTOP).  The user part of the address space
335 // will be setup later.
336 //
337 // From UTOP to ULIM, the user is allowed to read but not write.
338 // Above ULIM the user cannot read (or write). 
339 void
340 i386_vm_init(void)
341 {
342         pde_t* pgdir;
343         uint32_t cr0, edx;
344         size_t n;
345         bool pse;
346
347         pse = enable_pse();
348         if (pse)
349                 cprintf("PSE capability detected.\n");
350
351         // we paniced earlier if we don't support PGE.  turn it on now.
352         // it's used in boot_map_segment, which covers all of the mappings that are
353         // the same for all address spaces.  and also for the VPT mapping below.
354         lcr4(rcr4() | CR4_PGE);
355
356         // set up mtrr's for core0.  other cores will do the same later
357         setup_default_mtrrs(0);
358
359         /*
360          * PSE status: 
361          * - can walk and set up boot_map_segments with jumbos but can't
362          *   insert yet.  need to look at the page_dir and friends.
363          * - anything related to a single struct Page still can't handle 
364          *   jumbos.  will need to think about and adjust Page functions
365          * - do we want to store info like this in the struct Page?  or just check
366          *   by walking the PTE
367          * - when we alloc a page, and we want it to be 4MB, we'll need
368          *   to have contiguous memory, etc
369          * - there's a difference between having 4MB page table entries
370          *   and having 4MB Page tracking structs.  changing the latter will
371          *   break a lot of things
372          * - showmapping and friends work on a 4KB granularity, but map to the
373          *   correct entries
374          * - need to not insert / boot_map a single page into an area that is 
375          *   already holding a jumbo page.  will need to break the jumbo up so that
376          *   we can then insert the lone page.  currently warns.
377          * - some inherent issues with the pgdir_walks returning a PTE, and we
378          *   don't know whether it is a jumbo (PDE) or a regular PTE.
379          */
380
381         //////////////////////////////////////////////////////////////////////
382         // create initial page directory.
383         pgdir = boot_alloc(PGSIZE, PGSIZE);
384         memset(pgdir, 0, PGSIZE);
385         boot_pgdir = pgdir;
386         boot_cr3 = PADDR(pgdir);
387         // helpful if you want to manually walk with kvm / bochs
388         //printk("pgdir va = %08p, pgdir pa = %08p\n\n", pgdir, PADDR(pgdir));
389
390         //////////////////////////////////////////////////////////////////////
391         // Recursively insert PD in itself as a page table, to form
392         // a virtual page table at virtual address VPT.
393         // (For now, you don't have understand the greater purpose of the
394         // following two lines.  Unless you are eagle-eyed, in which case you
395         // should already know.)
396
397         // Permissions: kernel RW, user NONE, Global Page
398         pgdir[PDX(VPT)] = PADDR(pgdir) | PTE_W | PTE_P | PTE_G;
399
400         // same for UVPT
401         // Permissions: kernel R, user R, Global Page
402         pgdir[PDX(UVPT)] = PADDR(pgdir) | PTE_U | PTE_P | PTE_G;
403
404         //////////////////////////////////////////////////////////////////////
405         // Map the kernel stack (symbol name "bootstack").  The complete VA
406         // range of the stack, [KSTACKTOP-PTSIZE, KSTACKTOP), breaks into two
407         // pieces:
408         //     * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory
409         //     * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed => faults
410         //     Permissions: kernel RW, user NONE
411         // Your code goes here:
412
413         // remember that the space for the kernel stack is allocated in the binary.
414         // bootstack and bootstacktop point to symbols in the data section, which 
415         // at this point are like 0xc010b000.  KSTACKTOP is the desired loc in VM
416         boot_map_segment(pgdir, (uintptr_t)KSTACKTOP - KSTKSIZE, 
417                          KSTKSIZE, PADDR(bootstack), PTE_W | PTE_G);
418
419         //////////////////////////////////////////////////////////////////////
420         // Map all of physical memory at KERNBASE. 
421         // Ie.  the VA range [KERNBASE, 2^32) should map to
422         //      the PA range [0, 2^32 - KERNBASE)
423         // We might not have 2^32 - KERNBASE bytes of physical memory, but
424         // we just set up the mapping anyway.
425         // Permissions: kernel RW, user NONE
426         // Your code goes here: 
427         
428         // this maps all of the possible phys memory
429         // note the use of unsigned underflow to get size = 0x40000000
430         //boot_map_segment(pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
431         // but this only maps what is available, and saves memory.  every 4MB of
432         // mapped memory requires a 2nd level page: 2^10 entries, each covering 2^12
433         // need to modify tests below to account for this
434         if (pse) {
435                 // map the first 4MB as regular entries, to support different MTRRs
436                 boot_map_segment(pgdir, KERNBASE, JPGSIZE, 0, PTE_W | PTE_G);
437                 boot_map_segment(pgdir, KERNBASE + JPGSIZE, maxaddrpa - JPGSIZE, JPGSIZE,
438                                  PTE_W | PTE_G | PTE_PS);
439         } else
440                 boot_map_segment(pgdir, KERNBASE, maxaddrpa, 0, PTE_W | PTE_G);
441
442         // APIC mapping: using PAT (but not *the* PAT flag) to make these type UC
443         // IOAPIC
444         boot_map_segment(pgdir, (uintptr_t)IOAPIC_BASE, PGSIZE, IOAPIC_BASE, 
445                          PTE_PCD | PTE_PWT | PTE_W | PTE_G);
446         // Local APIC
447         boot_map_segment(pgdir, (uintptr_t)LAPIC_BASE, PGSIZE, LAPIC_BASE,
448                          PTE_PCD | PTE_PWT | PTE_W | PTE_G);
449
450         //////////////////////////////////////////////////////////////////////
451         // Make 'pages' point to an array of size 'npage' of 'struct Page'.
452         // The kernel uses this structure to keep track of physical pages;
453         // 'npage' equals the number of physical pages in memory.  User-level
454         // programs get read-only access to the array as well.
455         // You must allocate the array yourself.
456         // Map this array read-only by the user at linear address UPAGES
457         // (ie. perm = PTE_U | PTE_P)
458         // Permissions:
459         //    - pages -- kernel RW, user NONE
460         //    - the read-only version mapped at UPAGES -- kernel R, user R
461         // Your code goes here: 
462         
463         // round up to the nearest page
464         size_t page_array_size = ROUNDUP(npage*sizeof(page_t), PGSIZE);
465         pages = (page_t *)boot_alloc(page_array_size, PGSIZE);
466         memset(pages, 0, page_array_size);
467         if (page_array_size > PTSIZE) {
468                 warn("page_array_size bigger than PTSIZE, userland will not see all pages");
469                 page_array_size = PTSIZE;
470         }
471         boot_map_segment(pgdir, UPAGES, page_array_size, PADDR(pages), PTE_U | PTE_G);
472
473         //////////////////////////////////////////////////////////////////////
474         // Make 'envs' point to an array of size 'NENV' of 'env_t'.
475         // Map this array read-only by the user at linear address UENVS
476         // (ie. perm = PTE_U | PTE_P).
477         // Permissions:
478         //    - envs itself -- kernel RW, user NONE
479         //    - the image of envs mapped at UENVS  -- kernel R, user R
480         
481         // round up to the nearest page
482         size_t env_array_size = ROUNDUP(NENV*sizeof(env_t), PGSIZE);
483         envs = (env_t *)boot_alloc(env_array_size, PGSIZE);
484         memset(envs, 0, env_array_size);
485         if (env_array_size > PTSIZE) {
486                 warn("env_array_size bigger than PTSIZE, userland will not see all environments");
487                 env_array_size = PTSIZE;
488         }
489         boot_map_segment(pgdir, UENVS, env_array_size, PADDR(envs), PTE_U | PTE_G);
490
491         // Check that the initial page directory has been set up correctly.
492         check_boot_pgdir(pse);
493
494         //////////////////////////////////////////////////////////////////////
495         // On x86, segmentation maps a VA to a LA (linear addr) and
496         // paging maps the LA to a PA.  I.e. VA => LA => PA.  If paging is
497         // turned off the LA is used as the PA.  Note: there is no way to
498         // turn off segmentation.  The closest thing is to set the base
499         // address to 0, so the VA => LA mapping is the identity.
500
501         // Current mapping: VA KERNBASE+x => PA x.
502         //     (segmentation base=-KERNBASE and paging is off)
503
504         // From here on down we must maintain this VA KERNBASE + x => PA x
505         // mapping, even though we are turning on paging and reconfiguring
506         // segmentation.
507
508         // Map VA 0:4MB same as VA KERNBASE, i.e. to PA 0:4MB.
509         // (Limits our kernel to <4MB)
510         /* They mean linear address 0:4MB, and the kernel < 4MB is only until 
511          * segmentation is turned off.
512          * once we turn on paging, segmentation is still on, so references to
513          * KERNBASE+x will get mapped to linear address x, which we need to make 
514          * sure can map to phys addr x, until we can turn off segmentation and
515          * KERNBASE+x maps to LA KERNBASE+x, which maps to PA x, via paging
516          */
517         pgdir[0] = pgdir[PDX(KERNBASE)];
518
519         // Install page table.
520         lcr3(boot_cr3);
521
522         // Turn on paging.
523         cr0 = rcr0();
524         // CD and NW should already be on, but just in case these turn on caching
525         cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
526         cr0 &= ~(CR0_TS|CR0_EM|CR0_CD|CR0_NW);
527         lcr0(cr0);
528
529         // Current mapping: KERNBASE+x => x => x.
530         // (x < 4MB so uses paging pgdir[0])
531
532         // Reload all segment registers.
533         asm volatile("lgdt gdt_pd");
534         asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
535         asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
536         asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
537         asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
538         asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
539         asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT));  // reload cs
540         asm volatile("lldt %%ax" :: "a" (0));
541
542         // Final mapping: KERNBASE+x => KERNBASE+x => x.
543
544         // This mapping was only used after paging was turned on but
545         // before the segment registers were reloaded.
546         pgdir[0] = 0;
547
548         // Flush the TLB for good measure, to kill the pgdir[0] mapping.
549         lcr3(boot_cr3);
550 }
551
552 //
553 // Checks that the kernel part of virtual address space
554 // has been setup roughly correctly(by i386_vm_init()).
555 //
556 // This function doesn't test every corner case,
557 // in fact it doesn't test the permission bits at all,
558 // but it is a pretty good sanity check. 
559 //
560 static physaddr_t check_va2pa(pde_t *pgdir, uintptr_t va);
561 static pte_t get_vaperms(pde_t *pgdir, uintptr_t va);
562
563 static void
564 check_boot_pgdir(bool pse)
565 {
566         uint32_t i, n;
567         pde_t *pgdir, pte;
568
569         pgdir = boot_pgdir;
570
571         // check pages array
572         n = ROUNDUP(naddrpage*sizeof(page_t), PGSIZE);
573         for (i = 0; i < n; i += PGSIZE)
574                 assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);
575
576         // check envs array (new test for lab 3)
577         n = ROUNDUP(NENV*sizeof(env_t), PGSIZE);
578         for (i = 0; i < n; i += PGSIZE)
579                 assert(check_va2pa(pgdir, UENVS + i) == PADDR(envs) + i);
580
581         // check phys mem
582         //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
583         // adjusted check to account for only mapping avail mem
584         if (pse)
585                 for (i = 0; i < maxaddrpa; i += JPGSIZE)
586                         assert(check_va2pa(pgdir, KERNBASE + i) == i);
587         else
588                 for (i = 0; i < maxaddrpa; i += PGSIZE)
589                         assert(check_va2pa(pgdir, KERNBASE + i) == i);
590
591         // check kernel stack
592         for (i = 0; i < KSTKSIZE; i += PGSIZE)
593                 assert(check_va2pa(pgdir, KSTACKTOP - KSTKSIZE + i) == PADDR(bootstack) + i);
594
595         // check for zero/non-zero in PDEs
596         for (i = 0; i < NPDENTRIES; i++) {
597                 switch (i) {
598                 case PDX(VPT):
599                 case PDX(UVPT):
600                 case PDX(KSTACKTOP-1):
601                 case PDX(UPAGES):
602                 case PDX(UENVS):
603                 case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
604                         assert(pgdir[i]);
605                         break;
606                 default:
607                         //if (i >= PDX(KERNBASE))
608                         // adjusted check to account for only mapping avail mem
609                         // and you can't KADDR maxpa (just above legal range)
610                         // maxaddrpa can be up to maxpa, so assume the worst
611                         if (i >= PDX(KERNBASE) && i <= PDX(KADDR(maxaddrpa-1)))
612                                 assert(pgdir[i]);
613                         else
614                                 assert(pgdir[i] == 0);
615                         break;
616                 }
617         }
618
619         // check permissions
620         // user read-only.  check for user and write, should be only user
621         // eagle-eyed viewers should be able to explain the extra cases
622         for (i = UENVS; i < ULIM; i+=PGSIZE) {
623                 pte = get_vaperms(pgdir, i);
624                 if ((pte & PTE_P) && (i != UVPT+(VPT>>10))) {
625                         if (pte & PTE_PS) {
626                                 assert((pte & PTE_U) != PTE_U);
627                                 assert((pte & PTE_W) != PTE_W);
628                         } else {
629                                 assert((pte & PTE_U) == PTE_U);
630                                 assert((pte & PTE_W) != PTE_W);
631                         }
632                 }
633         }
634         // kernel read-write.
635         for (i = ULIM; i <= KERNBASE + maxaddrpa - PGSIZE; i+=PGSIZE) {
636                 pte = get_vaperms(pgdir, i);
637                 if ((pte & PTE_P) && (i != VPT+(UVPT>>10))) {
638                         assert((pte & PTE_U) != PTE_U);
639                         assert((pte & PTE_W) == PTE_W);
640                 }
641         }
642         // special mappings
643         pte = get_vaperms(pgdir, UVPT+(VPT>>10));
644         assert((pte & PTE_U) != PTE_U);
645         assert((pte & PTE_W) != PTE_W);
646
647         // note this means the kernel cannot directly manipulate this virtual address
648         // convince yourself this isn't a big deal, eagle-eyes!
649         pte = get_vaperms(pgdir, VPT+(UVPT>>10));
650         assert((pte & PTE_U) != PTE_U);
651         assert((pte & PTE_W) != PTE_W);
652
653         cprintf("check_boot_pgdir() succeeded!\n");
654 }
655
656 // This function returns the physical address of the page containing 'va',
657 // defined by the page directory 'pgdir'.  The hardware normally performs
658 // this functionality for us!  We define our own version to help check
659 // the check_boot_pgdir() function; it shouldn't be used elsewhere.
660
661 static physaddr_t
662 check_va2pa(pde_t *pgdir, uintptr_t va)
663 {
664         pte_t *p;
665
666         pgdir = &pgdir[PDX(va)];
667         if (!(*pgdir & PTE_P))
668                 return ~0;
669         if (*pgdir & PTE_PS)
670                 return PTE_ADDR(*pgdir);
671         p = (pte_t*) KADDR(PTE_ADDR(*pgdir));
672         if (!(p[PTX(va)] & PTE_P))
673                 return ~0;
674         return PTE_ADDR(p[PTX(va)]);
675 }
676
677 /* 
678  * This function returns a PTE with the aggregate permissions equivalent
679  * to walking the two levels of paging.  PPN = 0.  Somewhat fragile, in that
680  * it returns PTE_PS if either entry has PTE_PS (which should only happen
681  * for some of the recusive walks)
682  */
683
684 static pte_t
685 get_vaperms(pde_t *pgdir, uintptr_t va)
686 {
687         pde_t* pde = &pgdir[PDX(va)];
688         pte_t* pte = pgdir_walk(pgdir, (void*)va, 0);
689         if (!pte || !(*pte & PTE_P))
690                 return 0;
691         return PGOFF(*pde & *pte) + PTE_PS & (*pde | *pte);
692 }
693                 
694 // --------------------------------------------------------------
695 // Tracking of physical pages.
696 // The 'pages' array has one 'page_t' entry per physical page.
697 // Pages are reference counted, and free pages are kept on a linked list.
698 // --------------------------------------------------------------
699
700 //  
701 // Initialize page structure and memory free list.
702 // After this point, ONLY use the functions below
703 // to allocate and deallocate physical memory via the page_free_list,
704 // and NEVER use boot_alloc() or the related boot-time functions above.
705 //
706 void
707 page_init(void)
708 {
709         // The example code here marks all pages as free.
710         // However this is not truly the case.  What memory is free?
711         //  1) Mark page 0 as in use.
712         //     This way we preserve the real-mode IDT and BIOS structures
713         //     in case we ever need them.  (Currently we don't, but...)
714         //  2) Mark the rest of base memory as free.
715         //  3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM).
716         //     Mark it as in use so that it can never be allocated.      
717         //  4) Then extended memory [EXTPHYSMEM, ...).
718         //     Some of it is in use, some is free. Where is the kernel?
719         //     Which pages are used for page tables and other data structures?
720         //
721         // Change the code to reflect this.
722         int i;
723         physaddr_t physaddr_after_kernel = PADDR(ROUNDUP(boot_freemem, PGSIZE));
724         LIST_INIT(&page_free_list);
725
726         pages[0].pp_ref = 1;
727         // alloc the second page, since we will need it later to init the other cores
728         // probably need to be smarter about what page we use (make this dynamic) TODO
729         pages[1].pp_ref = 1;
730         for (i = 2; i < PPN(IOPHYSMEM); i++) {
731                 pages[i].pp_ref = 0;
732                 LIST_INSERT_HEAD(&page_free_list, &pages[i], pp_link);
733         }
734         for (i = PPN(IOPHYSMEM); i < PPN(EXTPHYSMEM); i++) {
735                 pages[i].pp_ref = 1;
736         }
737         for (i = PPN(EXTPHYSMEM); i < PPN(physaddr_after_kernel); i++) {
738                 pages[i].pp_ref = 1;
739         }
740         for (i = PPN(physaddr_after_kernel); i < PPN(maxaddrpa); i++) {
741                 pages[i].pp_ref = 0;
742                 LIST_INSERT_HEAD(&page_free_list, &pages[i], pp_link);
743         }
744         // this block out all memory above maxaddrpa.  will need another mechanism
745         // to allocate and map these into the kernel address space
746         for (i = PPN(maxaddrpa); i < npage; i++) {
747                 pages[i].pp_ref = 1;
748         }
749 }
750
751 //
752 // Initialize a Page structure.
753 // The result has null links and 0 refcount.
754 // Note that the corresponding physical page is NOT initialized!
755 //
756 static void
757 page_initpp(page_t *pp)
758 {
759         memset(pp, 0, sizeof(*pp));
760 }
761
762 //
763 // Allocates a physical page.
764 // Does NOT set the contents of the physical page to zero -
765 // the caller must do that if necessary.
766 //
767 // *pp_store -- is set to point to the Page struct of the newly allocated
768 // page
769 //
770 // RETURNS 
771 //   0 -- on success
772 //   -E_NO_MEM -- otherwise 
773 //
774 // Hint: use LIST_FIRST, LIST_REMOVE, and page_initpp
775 // Hint: pp_ref should not be incremented 
776 int
777 page_alloc(page_t **pp_store)
778 {
779         if (LIST_EMPTY(&page_free_list))
780                 return -E_NO_MEM;
781         *pp_store = LIST_FIRST(&page_free_list);
782         LIST_REMOVE(*pp_store, pp_link);
783         page_initpp(*pp_store);
784         return 0;
785 }
786
787 //
788 // Return a page to the free list.
789 // (This function should only be called when pp->pp_ref reaches 0.)
790 //
791 void
792 page_free(page_t *pp)
793 {
794         if (pp->pp_ref)
795                 panic("Attempting to free page with non-zero reference count!");
796         LIST_INSERT_HEAD(&page_free_list, pp, pp_link);
797 }
798
799 //
800 // Decrement the reference count on a page,
801 // freeing it if there are no more refs.
802 //
803 void
804 page_decref(page_t *pp)
805 {
806         if (--pp->pp_ref == 0)
807                 page_free(pp);
808 }
809
810 // Given 'pgdir', a pointer to a page directory, pgdir_walk returns
811 // a pointer to the page table entry (PTE) for linear address 'va'.
812 // This requires walking the two-level page table structure.
813 //
814 // If the relevant page table doesn't exist in the page directory, then:
815 //    - If create == 0, pgdir_walk returns NULL.
816 //    - Otherwise, pgdir_walk tries to allocate a new page table
817 //      with page_alloc.  If this fails, pgdir_walk returns NULL.
818 //    - Otherwise, pgdir_walk returns a pointer into the new page table.
819 //
820 // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc().
821 // Unlike boot_pgdir_walk, pgdir_walk can fail.
822 //
823 // Hint: you can turn a Page * into the physical address of the
824 // page it refers to with page2pa() from kern/pmap.h.
825 //
826 // Supports returning jumbo (4MB PSE) PTEs.  To create with a jumbo, pass in 2.
827 pte_t*
828 pgdir_walk(pde_t *pgdir, const void *SNT va, int create)
829 {
830         pde_t* the_pde = &pgdir[PDX(va)];
831         page_t *new_table;
832
833         if (*the_pde & PTE_P) {
834                 if (*the_pde & PTE_PS)
835                         return (pte_t*)the_pde;
836                 return &((pde_t*)KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
837         }
838         if (!create)
839                 return NULL;
840         if (create == 2) {
841                 if (JPGOFF(va))
842                         panic("Attempting to find a Jumbo PTE at an unaligned VA!");
843                 *the_pde = PTE_PS | PTE_P;
844                 return (pte_t*)the_pde;
845         }
846         if (page_alloc(&new_table))
847                 return NULL;
848         new_table->pp_ref = 1;
849         memset(page2kva(new_table), 0, PGSIZE);
850         *the_pde = (pde_t)page2pa(new_table) | PTE_P | PTE_W | PTE_U;
851         return &((pde_t*)KADDR(PTE_ADDR(*the_pde)))[PTX(va)];
852 }
853 //
854 // Map the physical page 'pp' at virtual address 'va'.
855 // The permissions (the low 12 bits) of the page table
856 //  entry should be set to 'perm|PTE_P'.
857 //
858 // Details
859 //   - If there is already a page mapped at 'va', it is page_remove()d.
860 //   - If necessary, on demand, allocates a page table and inserts it into
861 //     'pgdir'.
862 //   - pp->pp_ref should be incremented if the insertion succeeds.
863 //   - The TLB must be invalidated if a page was formerly present at 'va'.
864 //     (this is handled in page_remove)
865 //
866 // RETURNS: 
867 //   0 on success
868 //   -E_NO_MEM, if page table couldn't be allocated
869 //
870 // Hint: The TA solution is implemented using pgdir_walk, page_remove,
871 // and page2pa.
872 //
873 // No support for jumbos here.  will need to be careful of trying to insert
874 // regular pages into something that was already jumbo, and the overloading
875 // of the PTE_PS and PTE_PAT flags...
876 int
877 page_insert(pde_t *pgdir, page_t *pp, void *va, int perm) 
878 {
879         pte_t* pte = pgdir_walk(pgdir, va, 1);
880         if (!pte)
881                 return -E_NO_MEM;
882         // need to up the ref count in case pp is already mapped at va
883         // and we don't want to page_remove (which could free pp) and then 
884         // continue as if pp wasn't freed.  moral = up the ref asap
885         pp->pp_ref++;
886         if (*pte & PTE_P) {
887                 page_remove(pgdir, va);
888         }
889         *pte = page2pa(pp) | PTE_P | perm;
890         return 0;
891 }
892
893 //
894 // Return the page mapped at virtual address 'va'.
895 // If pte_store is not zero, then we store in it the address
896 // of the pte for this page.  This is used by page_remove
897 // but should not be used by other callers.
898 //
899 // Return 0 if there is no page mapped at va.
900 //
901 // Hint: the TA solution uses pgdir_walk and pa2page.
902 //
903 // For jumbos, right now this returns the first Page* in the 4MB
904 page_t *page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
905 {
906         pte_t* pte = pgdir_walk(pgdir, va, 0);
907         if (!pte || !(*pte & PTE_P))
908                 return 0;
909         if (pte_store)
910                 *pte_store = pte;
911         return pa2page(PTE_ADDR(*pte));
912 }
913
914 //
915 // Unmaps the physical page at virtual address 'va'.
916 // If there is no physical page at that address, silently does nothing.
917 //
918 // Details:
919 //   - The ref count on the physical page should decrement.
920 //   - The physical page should be freed if the refcount reaches 0.
921 //   - The pg table entry corresponding to 'va' should be set to 0.
922 //     (if such a PTE exists)
923 //   - The TLB must be invalidated if you remove an entry from
924 //     the pg dir/pg table.
925 //
926 // Hint: The TA solution is implemented using page_lookup,
927 //      tlb_invalidate, and page_decref.
928 //
929 // This may be wonky wrt Jumbo pages and decref.  
930 void
931 page_remove(pde_t *pgdir, void *va)
932 {
933         pte_t* pte;
934         page_t *page;
935         page = page_lookup(pgdir, va, &pte);
936         if (!page)
937                 return;
938         *pte = 0;
939         tlb_invalidate(pgdir, va);
940         page_decref(page);
941 }
942
943 //
944 // Invalidate a TLB entry, but only if the page tables being
945 // edited are the ones currently in use by the processor.
946 //
947 // Need to sort this for cross core lovin'  TODO
948 void
949 tlb_invalidate(pde_t *pgdir, void *va)
950 {
951         // Flush the entry only if we're modifying the current address space.
952         // For now, there is only one address space, so always invalidate.
953         invlpg(va);
954 }
955
956 /* Flushes a TLB, including global pages.  We should always have the CR4_PGE
957  * flag set, but just in case, we'll check.  Toggling this bit flushes the TLB.
958  */
959 void tlb_flush_global(void)
960 {
961         uint32_t cr4 = rcr4();
962         if (cr4 & CR4_PGE) {
963                 lcr4(cr4 & ~CR4_PGE);
964                 lcr4(cr4);
965         } else 
966                 lcr3(rcr3());
967 }
968
969 static void *DANGEROUS user_mem_check_addr;
970
971 //
972 // Check that an environment is allowed to access the range of memory
973 // [va, va+len) with permissions 'perm | PTE_P'.
974 // Normally 'perm' will contain PTE_U at least, but this is not required.
975 // 'va' and 'len' need not be page-aligned; you must test every page that
976 // contains any of that range.  You will test either 'len/PGSIZE',
977 // 'len/PGSIZE + 1', or 'len/PGSIZE + 2' pages.
978 //
979 // A user program can access a virtual address if (1) the address is below
980 // ULIM, and (2) the page table gives it permission.  These are exactly
981 // the tests you should implement here.
982 //
983 // If there is an error, set the 'user_mem_check_addr' variable to the first
984 // erroneous virtual address.
985 //
986 // Returns 0 if the user program can access this range of addresses,
987 // and -E_FAULT otherwise.
988 //
989 // Hint: The TA solution uses pgdir_walk.
990 //
991
992 // zra: I've modified the interface to these two functions so that Ivy can
993 // check that user pointers aren't dereferenced. User pointers get the
994 // DANGEROUS qualifier. After validation, these functions return a
995 // COUNT(len) pointer. user_mem_check now returns NULL on error instead of
996 // -E_FAULT.
997
998 void *COUNT(len)
999 user_mem_check(env_t *env, const void *DANGEROUS va, size_t len, int perm)
1000 {
1001         // TODO - will need to sort this out wrt page faulting / PTE_P
1002         // also could be issues with sleeping and waking up to find pages
1003         // are unmapped, though i think the lab ignores this since the 
1004         // kernel is uninterruptible
1005         void *DANGEROUS start, *DANGEROUS end;
1006         size_t num_pages, i;
1007         pte_t *pte;
1008
1009         perm |= PTE_P;
1010         start = ROUNDDOWN((void*)va, PGSIZE);
1011         end = ROUNDUP((void*)va + len, PGSIZE);
1012         if (start >= end) {
1013                 warn("Blimey!  Wrap around in VM range calculation!");  
1014                 return NULL;
1015         }
1016         num_pages = PPN(end - start);
1017         for (i = 0; i < num_pages; i++, start += PGSIZE) {
1018                 pte = pgdir_walk(env->env_pgdir, start, 0);
1019                 // ensures the bits we want on are turned on.  if not, error out
1020                 if ( !pte || ((*pte & perm) != perm) ) {
1021                         if (i = 0)
1022                                 user_mem_check_addr = (void*)va;
1023                         else
1024                                 user_mem_check_addr = start;
1025                         return NULL;
1026                 }
1027         }
1028         // this should never be needed, since the perms should catch it
1029         if ((uintptr_t)end > ULIM) {
1030                 warn ("I suck - Bug in user permission mappings!");
1031                 return NULL;
1032         }
1033         return (void *COUNT(len))TC(va);
1034 }
1035
1036 //
1037 // Checks that environment 'env' is allowed to access the range
1038 // of memory [va, va+len) with permissions 'perm | PTE_U'.
1039 // If it can, then the function simply returns.
1040 // If it cannot, 'env' is destroyed.
1041 //
1042 void *COUNT(len)
1043 user_mem_assert(env_t *env, const void *DANGEROUS va, size_t len, int perm)
1044 {
1045     void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_U);
1046         if (!res) {
1047                 cprintf("[%08x] user_mem_check assertion failure for "
1048                         "va %08x\n", curenv->env_id, user_mem_check_addr);
1049                 env_destroy(env);       // may not return
1050         return NULL;
1051         }
1052     return res;
1053 }
1054
1055 void
1056 page_check(void)
1057 {
1058         page_t *pp, *pp0, *pp1, *pp2;
1059         page_list_t fl;
1060         pte_t *ptep;
1061
1062         // should be able to allocate three pages
1063         pp0 = pp1 = pp2 = 0;
1064         assert(page_alloc(&pp0) == 0);
1065         assert(page_alloc(&pp1) == 0);
1066         assert(page_alloc(&pp2) == 0);
1067
1068         assert(pp0);
1069         assert(pp1 && pp1 != pp0);
1070         assert(pp2 && pp2 != pp1 && pp2 != pp0);
1071
1072         // temporarily steal the rest of the free pages
1073         fl = page_free_list;
1074         LIST_INIT(&page_free_list);
1075
1076         // should be no free memory
1077         assert(page_alloc(&pp) == -E_NO_MEM);
1078
1079         // Fill pp1 with bogus data and check for invalid tlb entries
1080         memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
1081
1082         // there is no page allocated at address 0
1083         assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
1084
1085         // there is no free memory, so we can't allocate a page table 
1086         assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
1087
1088         // free pp0 and try again: pp0 should be used for page table
1089         page_free(pp0);
1090         assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
1091         tlb_invalidate(boot_pgdir, 0x0);
1092         // DEP Should have shot down invalid TLB entry - let's check
1093         {
1094           int *x = 0x0;
1095           assert(*x == 0xFFFFFFFF);
1096         }
1097         assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
1098         assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
1099         assert(pp1->pp_ref == 1);
1100         assert(pp0->pp_ref == 1);
1101
1102         // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
1103         assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, 0) == 0);
1104         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
1105         assert(pp2->pp_ref == 1);
1106
1107         // Make sure that pgdir_walk returns a pointer to the pte and
1108         // not the table or some other garbage
1109         {
1110           pte_t *p = KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)]));
1111           assert(pgdir_walk(boot_pgdir, (void *)PGSIZE, 0) == &p[PTX(PGSIZE)]);
1112         }
1113
1114         // should be no free memory
1115         assert(page_alloc(&pp) == -E_NO_MEM);
1116
1117         // should be able to map pp2 at PGSIZE because it's already there
1118         assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, PTE_U) == 0);
1119         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
1120         assert(pp2->pp_ref == 1);
1121
1122         // Make sure that we actually changed the permission on pp2 when we re-mapped it
1123         {
1124           pte_t *p = pgdir_walk(boot_pgdir, (void*)PGSIZE, 0);
1125           assert(((*p) & PTE_U) == PTE_U);
1126         }
1127
1128         // pp2 should NOT be on the free list
1129         // could happen in ref counts are handled sloppily in page_insert
1130         assert(page_alloc(&pp) == -E_NO_MEM);
1131
1132         // should not be able to map at PTSIZE because need free page for page table
1133         assert(page_insert(boot_pgdir, pp0, (void*) PTSIZE, 0) < 0);
1134
1135         // insert pp1 at PGSIZE (replacing pp2)
1136         assert(page_insert(boot_pgdir, pp1, (void*) PGSIZE, 0) == 0);
1137
1138         // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
1139         assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
1140         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
1141         // ... and ref counts should reflect this
1142         assert(pp1->pp_ref == 2);
1143         assert(pp2->pp_ref == 0);
1144
1145         // pp2 should be returned by page_alloc
1146         assert(page_alloc(&pp) == 0 && pp == pp2);
1147
1148         // unmapping pp1 at 0 should keep pp1 at PGSIZE
1149         page_remove(boot_pgdir, 0x0);
1150         assert(check_va2pa(boot_pgdir, 0x0) == ~0);
1151         assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
1152         assert(pp1->pp_ref == 1);
1153         assert(pp2->pp_ref == 0);
1154
1155         // unmapping pp1 at PGSIZE should free it
1156         page_remove(boot_pgdir, (void*) PGSIZE);
1157         assert(check_va2pa(boot_pgdir, 0x0) == ~0);
1158         assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
1159         assert(pp1->pp_ref == 0);
1160         assert(pp2->pp_ref == 0);
1161
1162         // so it should be returned by page_alloc
1163         assert(page_alloc(&pp) == 0 && pp == pp1);
1164
1165         // should be no free memory
1166         assert(page_alloc(&pp) == -E_NO_MEM);
1167
1168         // forcibly take pp0 back
1169         assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0));
1170         boot_pgdir[0] = 0;
1171         assert(pp0->pp_ref == 1);
1172         pp0->pp_ref = 0;
1173
1174         // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
1175         {
1176           // Give back pp0 for a bit
1177           page_free(pp0);
1178
1179           void * va = (void *)((PGSIZE * NPDENTRIES) + PGSIZE);
1180           pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
1181           pte_t *p = KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));
1182           assert(p2 == &p[PTX(va)]);
1183
1184           // Clean up again
1185           boot_pgdir[PDX(va)] = 0;
1186           pp0->pp_ref = 0;
1187         }
1188
1189         // give free list back
1190         page_free_list = fl;
1191
1192         // free the pages we took
1193         page_free(pp0);
1194         page_free(pp1);
1195         page_free(pp2);
1196
1197         cprintf("page_check() succeeded!\n");
1198 }
1199
1200 /* 
1201
1202     // testing code for boot_pgdir_walk 
1203         pte_t* temp;
1204         temp = boot_pgdir_walk(pgdir, VPT + (VPT >> 10), 1);
1205         cprintf("pgdir = %p\n", pgdir);
1206         cprintf("test recursive walking pte_t* = %p\n", temp);
1207         cprintf("test recursive walking entry = %p\n", PTE_ADDR(temp));
1208         temp = boot_pgdir_walk(pgdir, 0xc0400000, 1);
1209         cprintf("LA = 0xc0400000 = %p\n", temp);
1210         temp = boot_pgdir_walk(pgdir, 0xc0400070, 1);
1211         cprintf("LA = 0xc0400070 = %p\n", temp);
1212         temp = boot_pgdir_walk(pgdir, 0xc0800000, 0);
1213         cprintf("LA = 0xc0800000, no create = %p\n", temp);
1214         temp = boot_pgdir_walk(pgdir, 0xc0600070, 1);
1215         cprintf("LA = 0xc0600070 = %p\n", temp);
1216         temp = boot_pgdir_walk(pgdir, 0xc0600090, 0);
1217         cprintf("LA = 0xc0600090, nc = %p\n", temp);
1218         temp = boot_pgdir_walk(pgdir, 0xc0608070, 0);
1219         cprintf("LA = 0xc0608070, nc = %p\n", temp);
1220         temp = boot_pgdir_walk(pgdir, 0xc0800070, 1);
1221         cprintf("LA = 0xc0800070 = %p\n", temp);
1222         temp = boot_pgdir_walk(pgdir, 0xc0b00070, 0);
1223         cprintf("LA = 0xc0b00070, nc = %p\n", temp);
1224         temp = boot_pgdir_walk(pgdir, 0xc0c00000, 0);
1225         cprintf("LA = 0xc0c00000, nc = %p\n", temp);
1226
1227         // testing for boot_map_seg
1228         cprintf("\n");
1229         cprintf("before mapping 1 page to 0x00350000\n");
1230         cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
1231         cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
1232         boot_map_segment(pgdir, 0xc4000000, 4096, 0x00350000, PTE_W);
1233         cprintf("after mapping\n");
1234         cprintf("0xc4000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc4000000, 1));
1235         cprintf("0xc4000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc4000000, 1)));
1236
1237         cprintf("\n");
1238         cprintf("before mapping 3 pages to 0x00700000\n");
1239         cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
1240         cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
1241         cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
1242         cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
1243         cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
1244         cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
1245         boot_map_segment(pgdir, 0xd0000000, 4096*3, 0x00700000, 0);
1246         cprintf("after mapping\n");
1247         cprintf("0xd0000000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0000000, 1));
1248         cprintf("0xd0000000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0000000, 1)));
1249         cprintf("0xd0001000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0001000, 1));
1250         cprintf("0xd0001000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0001000, 1)));
1251         cprintf("0xd0002000's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xd0002000, 1));
1252         cprintf("0xd0002000's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xd0002000, 1)));
1253
1254         cprintf("\n");
1255         cprintf("before mapping 1 unaligned to 0x00500010\n");
1256         cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
1257         cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
1258         cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
1259         cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
1260         boot_map_segment(pgdir, 0xc8000010, 4096, 0x00500010, PTE_W);
1261         cprintf("after mapping\n");
1262         cprintf("0xc8000010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8000010, 1));
1263         cprintf("0xc8000010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8000010, 1)));
1264         cprintf("0xc8001010's &pte: %08x\n",boot_pgdir_walk(pgdir, 0xc8001010, 1));
1265         cprintf("0xc8001010's pte: %08x\n",*(boot_pgdir_walk(pgdir, 0xc8001010, 1)));
1266
1267         cprintf("\n");
1268         boot_map_segment(pgdir, 0xe0000000, 4096, 0x10000000, PTE_W);
1269
1270 */