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