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