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