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