· 9 years ago · Nov 03, 2016, 07:06 PM
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#include <kern/cpu.h>
13
14// These variables are set by i386_detect_memory()
15size_t npages; // Amount of physical memory (in pages)
16static size_t npages_basemem; // Amount of base memory (in pages)
17
18// These variables are set in mem_init()
19pde_t *kern_pgdir; // Kernel's initial page directory
20struct PageInfo *pages; // Physical page state array
21static struct PageInfo *page_free_list; // Free list of physical pages
22
23
24// --------------------------------------------------------------
25// Detect machine's physical memory setup.
26// --------------------------------------------------------------
27
28static int
29nvram_read(int r)
30{
31 return mc146818_read(r) | (mc146818_read(r + 1) << 8);
32}
33
34static void
35i386_detect_memory(void)
36{
37 size_t basemem, extmem, ext16mem, totalmem;
38
39 // Use CMOS calls to measure available base & extended memory.
40 // (CMOS calls return results in kilobytes.)
41 basemem = nvram_read(NVRAM_BASELO);
42 extmem = nvram_read(NVRAM_EXTLO);
43 ext16mem = nvram_read(NVRAM_EXT16LO) * 64;
44
45 // Calculate the number of physical pages available in both base
46 // and extended memory.
47 if (ext16mem)
48 totalmem = 16 * 1024 + ext16mem;
49 else if (extmem)
50 totalmem = 1 * 1024 + extmem;
51 else
52 totalmem = basemem;
53
54 npages = totalmem / (PGSIZE / 1024);
55 npages_basemem = basemem / (PGSIZE / 1024);
56
57 cprintf("Physical memory: %uK available, base = %uK, extended = %uK\n",
58 totalmem, basemem, totalmem - basemem);
59}
60
61
62// --------------------------------------------------------------
63// Set up memory mappings above UTOP.
64// --------------------------------------------------------------
65
66static void mem_init_mp(void);
67static void boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm);
68static void check_page_free_list(bool only_low_memory);
69static void check_page_alloc(void);
70static void check_kern_pgdir(void);
71static physaddr_t check_va2pa(pde_t *pgdir, uintptr_t va);
72static void check_page(void);
73static void check_page_installed_pgdir(void);
74
75// This simple physical memory allocator is used only while JOS is setting
76// up its virtual memory system. page_alloc() is the real allocator.
77//
78// If n>0, allocates enough pages of contiguous physical memory to hold 'n'
79// bytes. Doesn't initialize the memory. Returns a kernel virtual address.
80//
81// If n==0, returns the address of the next free page without allocating
82// anything.
83//
84// If we're out of memory, boot_alloc should panic.
85// This function may ONLY be used during initialization,
86// before the page_free_list list has been set up.
87static void *
88boot_alloc(uint32_t n)
89{
90 static char *nextfree; // virtual address of next byte of free memory
91 //char *result;
92
93 // Initialize nextfree if this is the first time.
94 // 'end' is a magic symbol automatically generated by the linker,
95 // which points to the end of the kernel's bss segment:
96 // the first virtual address that the linker did *not* assign
97 // to any kernel code or global variables.
98
99 if (!nextfree) { //nextfree je 0
100 extern char end[];
101 nextfree = ROUNDUP((char *) end, PGSIZE);
102 }
103
104 // Allocate a chunk large enough to hold 'n' bytes, then update
105 // nextfree. Make sure nextfree is kept aligned
106 // to a multiple of PGSIZE.
107 //
108 // LAB 2: Your code here.
109
110 // ROUNDUP to make sure nextfree is kept aligned
111 // to a multiple of PGSIZE
112
113 if(n==0) return nextfree;
114
115 if (n > 0 || n < 0) {
116 nextfree = ROUNDUP((char *) (nextfree+n), PGSIZE);
117 char **adresa = &nextfree;
118
119 int freebytes = 0;
120 uint32_t RAMsize = npages*PGSIZE;
121
122 //}
123 }
124
125 return nextfree;
126}
127
128// Set up a two-level page table:
129// kern_pgdir is its linear (virtual) address of the root
130//
131// This function only sets up the kernel part of the address space
132// (ie. addresses >= UTOP). The user part of the address space
133// will be setup later.
134//
135// From UTOP to ULIM, the user is allowed to read but not write.
136// Above ULIM the user cannot read or write.
137void
138mem_init(void)
139{
140 uint32_t cr0;
141 size_t n;
142
143 // Find out how much memory the machine has (npages & npages_basemem).
144 i386_detect_memory();
145
146 // Remove this line when you're ready to test this function.
147 //panic("mem_init: This function is not finished\n");
148
149 //////////////////////////////////////////////////////////////////////
150 // create initial page directory.
151 kern_pgdir = (pde_t *) boot_alloc(PGSIZE);
152 memset(kern_pgdir, 0, PGSIZE);
153
154 //////////////////////////////////////////////////////////////////////
155 // Recursively insert PD in itself as a page table, to form
156 // a virtual page table at virtual address UVPT.
157 // (For now, you don't have understand the greater purpose of the
158 // following line.)
159
160 // Permissions: kernel R, user R
161 kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;
162
163 //////////////////////////////////////////////////////////////////////
164 // Allocate an array of npages 'struct PageInfo's and store it in 'pages'.
165 // The kernel uses this array to keep track of physical pages: for
166 // each physical page, there is a corresponding struct PageInfo in this
167 // array. 'npages' is the number of physical pages in memory. Use memset
168 // to initialize all fields of each struct PageInfo to 0.
169 // Your code goes here:
170
171 pages = (struct PageInfo *)boot_alloc(npages * sizeof(struct PageInfo));
172
173 size_t iterator;
174
175 for(iterator=0;iterator<npages;iterator++) {
176 memset(&pages[iterator].pp_link,0,sizeof(uint16_t));
177 memset(&pages[iterator].pp_ref,0,sizeof(uint16_t));
178 }
179
180 //////////////////////////////////////////////////////////////////////
181 // Make 'envs' point to an array of size 'NENV' of 'struct Env'.
182 // LAB 3: Your code here.
183
184 envs = (struct Env *)boot_alloc(NENV * sizeof(struct Env));
185
186
187 //////////////////////////////////////////////////////////////////////
188 // Now that we've allocated the initial kernel data structures, we set
189 // up the list of free physical pages. Once we've done so, all further
190 // memory management will go through the page_* functions. In
191 // particular, we can now map memory using boot_map_region
192 // or page_insert
193 page_init();
194
195 check_page_free_list(1);
196 check_page_alloc();
197 check_page();
198
199 //////////////////////////////////////////////////////////////////////
200 // Now we set up virtual memory
201
202 //////////////////////////////////////////////////////////////////////
203 // Map 'pages' read-only by the user at linear address UPAGES
204 // Permissions:
205 // - the new image at UPAGES -- kernel R, user R
206 // (ie. perm = PTE_U | PTE_P)
207 // - pages itself -- kernel RW, user NONE
208 // Your code goes here:
209
210 boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U | PTE_P);
211
212
213
214
215 //////////////////////////////////////////////////////////////////////
216 // Map the 'envs' array read-only by the user at linear address UENVS
217 // (ie. perm = PTE_U | PTE_P).
218 // Permissions:
219 // - the new image at UENVS -- kernel R, user R
220 // - envs itself -- kernel RW, user NONE
221 // LAB 3: Your code here.
222
223 boot_map_region(kern_pgdir, UENVS, PTSIZE, PADDR(envs), PTE_U | PTE_P);
224
225
226
227 //////////////////////////////////////////////////////////////////////
228 // Use the physical memory that 'bootstack' refers to as the kernel
229 // stack. The kernel stack grows down from virtual address KSTACKTOP.
230 // We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP)
231 // to be the kernel stack, but break this into two pieces:
232 // * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory
233 // * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if
234 // the kernel overflows its stack, it will fault rather than
235 // overwrite memory. Known as a "guard page".
236 // Permissions: kernel RW, user NONE
237 // Your code goes here:
238
239 boot_map_region(kern_pgdir, KSTACKTOP-KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W);
240
241
242
243 //////////////////////////////////////////////////////////////////////
244 // Map all of physical memory at KERNBASE.
245 // Ie. the VA range [KERNBASE, 2^32) should map to
246 // the PA range [0, 2^32 - KERNBASE)
247 // We might not have 2^32 - KERNBASE bytes of physical memory, but
248 // we just set up the mapping anyway.
249 // Permissions: kernel RW, user NONE
250 // Your code goes here:
251
252 boot_map_region(kern_pgdir, KERNBASE, -KERNBASE, 0, PTE_W);
253
254
255
256
257 // Initialize the SMP-related parts of the memory map
258 mem_init_mp();
259
260 // Check that the initial page directory has been set up correctly.
261 check_kern_pgdir();
262
263 // Switch from the minimal entry page directory to the full kern_pgdir
264 // page table we just created. Our instruction pointer should be
265 // somewhere between KERNBASE and KERNBASE+4MB right now, which is
266 // mapped the same way by both page tables.
267 //
268 // If the machine reboots at this point, you've probably set up your
269 // kern_pgdir wrong.
270 lcr3(PADDR(kern_pgdir));
271
272 check_page_free_list(0);
273
274 // entry.S set the really important flags in cr0 (including enabling
275 // paging). Here we configure the rest of the flags that we care about.
276 cr0 = rcr0();
277 cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP;
278 cr0 &= ~(CR0_TS|CR0_EM);
279 lcr0(cr0);
280
281 // Some more checks, only possible after kern_pgdir is installed.
282 check_page_installed_pgdir();
283}
284
285// Modify mappings in kern_pgdir to support SMP
286// - Map the per-CPU stacks in the region [KSTACKTOP-PTSIZE, KSTACKTOP)
287//
288static void
289mem_init_mp(void)
290{
291 // Map per-CPU stacks starting at KSTACKTOP, for up to 'NCPU' CPUs.
292 //
293 // For CPU i, use the physical memory that 'percpu_kstacks[i]' refers
294 // to as its kernel stack. CPU i's kernel stack grows down from virtual
295 // address kstacktop_i = KSTACKTOP - i * (KSTKSIZE + KSTKGAP), and is
296 // divided into two pieces, just like the single stack you set up in
297 // mem_init:
298 // * [kstacktop_i - KSTKSIZE, kstacktop_i)
299 // -- backed by physical memory
300 // * [kstacktop_i - (KSTKSIZE + KSTKGAP), kstacktop_i - KSTKSIZE)
301 // -- not backed; so if the kernel overflows its stack,
302 // it will fault rather than overwrite another CPU's stack.
303 // Known as a "guard page".
304 // Permissions: kernel RW, user NONE
305 //
306 // LAB 4: Your code here:
307
308
309 for (int i = 0; i < NCPU; ++i) {
310 boot_map_region(kern_pgdir,KSTACKTOP - KSTKSIZE - i * (KSTKSIZE + KSTKGAP),KSTKSIZE,PADDR(percpu_kstacks[i]), PTE_W);
311 }
312
313
314
315
316
317
318}
319
320// --------------------------------------------------------------
321// Tracking of physical pages.
322// The 'pages' array has one 'struct PageInfo' entry per physical page.
323// Pages are reference counted, and free pages are kept on a linked list.
324// --------------------------------------------------------------
325
326//
327// Initialize page structure and memory free list.
328// After this is done, NEVER use boot_alloc again. ONLY use the page
329// allocator functions below to allocate and deallocate physical
330// memory via the page_free_list.
331//
332void
333page_init(void)
334{
335 // LAB 4:
336 // Change your code to mark the physical page at MPENTRY_PADDR
337 // as in use
338
339 // The example code here marks all physical pages as free.
340 // However this is not truly the case. What memory is free?
341 // 1) Mark physical page 0 as in use.
342 // This way we preserve the real-mode IDT and BIOS structures
343 // in case we ever need them. (Currently we don't, but...)
344 // 2) The rest of base memory, [PGSIZE, npages_basemem * PGSIZE)
345 // is free.
346 // 3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM), which must
347 // never be allocated.
348 // 4) Then extended memory [EXTPHYSMEM, ...).
349 // Some of it is in use, some is free. Where is the kernel
350 // in physical memory? Which pages are already in use for
351 // page tables and other data structures?
352 //
353 // Change the code to reflect this.
354 // NB: DO NOT actually touch the physical memory corresponding to
355 // free pages!
356
357 size_t i;
358 for (i = 1; i < npages_basemem; i++) {
359 if(page2pa(&pages[i])==MPENTRY_PADDR)
360 continue;
361 pages[i].pp_ref = 0;
362 pages[i].pp_link = page_free_list;
363 page_free_list = &pages[i];
364 }
365
366 int param = (PADDR((char*)pages) + (sizeof(struct PageInfo) * npages)); // FA za zoznamom PI's
367 int rounded = (int)ROUNDUP(param, PGSIZE); // adresa prveho ramca za zoznamom
368 int med = rounded/PGSIZE; // dostaneme pocet ramcov
369 //int med = (int)ROUNDUP(((char*)envs) + (sizeof(struct Env) * NENV) - 0xf0000000, PGSIZE)/PGSIZE;
370 for (i = med; i < npages; i++) {
371 if(page2pa(&pages[i])==MPENTRY_PADDR)
372 continue;
373 pages[i].pp_ref = 0;
374 pages[i].pp_link = page_free_list;
375 page_free_list = &pages[i];
376 }
377}
378
379//
380// Allocates a physical page. If (alloc_flags & ALLOC_ZERO), fills the entire
381// returned physical page with '\0' bytes. Does NOT increment the reference
382// count of the page - the caller must do these if necessary (either explicitly
383// or via page_insert).
384//
385// Be sure to set the pp_link field of the allocated page to NULL so
386// page_free can check for double-free bugs.
387//
388// Returns NULL if out of free memory.
389//
390// Hint: use page2kva and memset
391struct PageInfo *
392page_alloc(int alloc_flags)
393{
394 // Fill this function in
395 if (page_free_list) {
396 struct PageInfo *ret = page_free_list; // ulozime si prvy prvok zo zoznamu volnych ramcov na dalsie spracovanie
397
398 page_free_list = page_free_list->pp_link; // posunie pointer na zaciatok listu na dalsi prvok
399 ret->pp_link = NULL;
400 if (alloc_flags & ALLOC_ZERO) {
401 memset(page2kva(ret), '\0', PGSIZE);
402 } // page2kva Returns the starting kernel virtual address corresponding to an element of pages[]-zeby adresu stranky ?
403 // viem obist page2kva? vynasobit zaciatok listu PGSIZE a potom pricitat 0xF0000000 ? pojde to?
404
405 return ret;
406 }
407 return NULL;
408}
409
410//
411// Return a page to the free list.
412// (This function should only be called when pp->pp_ref reaches 0.)
413//
414void
415page_free(struct PageInfo *pp)
416{
417 // Fill this function in
418 // Hint: You may want to panic if pp->pp_ref is nonzero or
419 // pp->pp_link is not NULL.
420
421 if((pp->pp_ref!=0)) {
422 panic("Page free failed,ref != 0");
423 //pp->pp_link = NULL;
424
425 }
426
427 if((pp->pp_link!=NULL)) {
428 panic("Page free failed,link != NULL"); // spadne to na
429 }
430
431 pp->pp_link = page_free_list; // link ukazuje na zoznam volnych
432 page_free_list = pp; // page_free_list v tomto momente nie je prvy, ale druhy prvok... preto musime
433 // nastavit zaciatok listu (momentalne pp) do page_free_list
434}
435
436//
437// Decrement the reference count on a page,
438// freeing it if there are no more refs.
439//
440void
441page_decref(struct PageInfo* pp)
442{
443 if (--pp->pp_ref == 0)
444 page_free(pp);
445}
446
447// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
448// a pointer to the page table entry (PTE) for linear address 'va'.
449// This requires walking the two-level page table structure.
450//
451// The relevant page table page might not exist yet.
452// If this is true, and create == false, then pgdir_walk returns NULL.
453// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
454// - If the allocation fails, pgdir_walk returns NULL.
455// - Otherwise, the new page's reference count is incremented,
456// the page is cleared,
457// and pgdir_walk returns a pointer into the new page table page.
458//
459// Hint 1: you can turn a PageInfo * into the physical address of the
460// page it refers to with page2pa() from kern/pmap.h.
461//
462// Hint 2: the x86 MMU checks permission bits in both the page directory
463// and the page table, so it's safe to leave permissions in the page
464// directory more permissive than strictly necessary.
465//
466// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
467// table and page directory entries.
468//
469pte_t *
470pgdir_walk(pde_t *pgdir, const void *va, int create)
471{
472 pte_t *zac_tab_va;
473 pte_t *druha_tab_va;
474
475 //pte_t druha_tab_va =(pte_t*)zac_tab_va + PTX(va);
476 //pte_t *pte_a = &((pte_t*)KADDR(PTE_ADDR(prvy_pte_a)))+PTX(va); //[PTX(va)] malo by tu byt odkazanie na druhu tabulku
477
478 if(pgdir[PDX(va)] & PTE_P){
479 zac_tab_va = KADDR(PTE_ADDR(pgdir[PDX(va)]));
480 druha_tab_va =((pte_t*)zac_tab_va )+ PTX(va);
481 return druha_tab_va;
482 }
483 else {
484 if(create)
485 {
486 struct PageInfo *pgi=page_alloc(ALLOC_ZERO);
487 if(pgi==NULL) return NULL;
488
489 pgi->pp_ref++;
490 pgdir[PDX(va)] = page2pa(pgi) | PTE_P | PTE_U | PTE_W;//nastavime permiss v pgdir
491 zac_tab_va = KADDR(PTE_ADDR(pgdir[PDX(va)]));
492 druha_tab_va =((pte_t*)zac_tab_va )+ PTX(va);
493 return druha_tab_va;
494
495 }
496 else return NULL;
497 }
498}
499
500//
501// Map [va, va+size) of virtual address space to physical [pa, pa+size)
502// in the page table rooted at pgdir. Size is a multiple of PGSIZE, and
503// va and pa are both page-aligned.
504// Use permission bits perm|PTE_P for the entries.
505//
506// This function is only intended to set up the ``static'' mappings
507// above UTOP. As such, it should *not* change the pp_ref field on the
508// mapped pages.
509//
510// Hint: the TA solution uses pgdir_walk
511static void
512boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
513{
514 // Fill this function in
515 int page_count = size/PGSIZE;
516 for (int i = 0; i < page_count; i++) {
517 pte_t* next = pgdir_walk(pgdir, (void*)va, 1);
518 if (next != NULL) {
519 *next = pa | perm | PTE_P;
520 pa = pa + PGSIZE;
521 va = va + PGSIZE;
522 }
523 else panic("boot_map_region sa dojebal");
524 }
525}
526
527//
528// Map the physical page 'pp' at virtual address 'va'.
529// The permissions (the low 12 bits) of the page table entry
530// should be set to 'perm|PTE_P'.
531//
532// Requirements
533// - If there is already a page mapped at 'va', it should be page_remove()d.
534// - If necessary, on demand, a page table should be allocated and inserted
535// into 'pgdir'.
536// - pp->pp_ref should be incremented if the insertion succeeds.
537// - The TLB must be invalidated if a page was formerly present at 'va'.
538//
539// Corner-case hint: Make sure to consider what happens when the same
540// pp is re-inserted at the same virtual address in the same pgdir.
541// However, try not to distinguish this case in your code, as this
542// frequently leads to subtle bugs; there's an elegant way to handle
543// everything in one code path.
544//
545// RETURNS:
546// 0 on success
547// -E_NO_MEM, if page table couldn't be allocated
548//
549// Hint: The TA solution is implemented using pgdir_walk, page_remove,
550// and page2pa.
551//
552int
553page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
554{
555 pte_t* new = pgdir_walk(pgdir,va,1);
556 if(new == NULL) // ak sa nepodarilo vytvorit (nie je pamat)
557 return -E_NO_MEM;
558
559 pp->pp_ref++;
560 if (*new & PTE_P) { // ak existuje tak zmaze
561 page_remove(pgdir,va);
562 }
563 //pgdir[PDX(va)]=(pte_t*)(pa2page(new) | perm | PTE_P);
564 *new = page2pa(pp) | perm | PTE_P;
565 return 0;
566}
567
568//
569// Return the page mapped at virtual address 'va'.
570// If pte_store is not zero, then we store in it the address
571// of the pte for this page. This is used by page_remove and
572// can be used to verify page permissions for syscall arguments,
573// but should not be used by most callers.
574//
575// Return NULL if there is no page mapped at va.
576//
577// Hint: the TA solution uses pgdir_walk and pa2page.
578//
579struct PageInfo *
580page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
581{
582 pte_t* pte_pa = pgdir_walk(pgdir,va,0);
583 if(pte_pa == NULL || !(*pte_pa & PTE_P))
584 return NULL;
585 if(*pte_store != 0)
586 *pte_store = pte_pa;
587 return pa2page(PTE_ADDR(*pte_pa));
588}
589
590//
591// Unmaps the physical page at virtual address 'va'.
592// If there is no physical page at that address, silently does nothing.
593//
594// Details:
595// - The ref count on the physical page should decrement.
596// - The physical page should be freed if the refcount reaches 0.
597// - The pg table entry corresponding to 'va' should be set to 0.
598// (if such a PTE exists)
599// - The TLB must be invalidated if you remove an entry from
600// the page table.
601//
602// Hint: The TA solution is implemented using page_lookup,
603// tlb_invalidate, and page_decref.
604//
605void
606page_remove(pde_t *pgdir, void *va)
607{
608 pte_t *pte_store;
609 struct PageInfo *stranka = page_lookup(pgdir, va, &pte_store);
610 if(stranka == NULL) {
611 return;
612 } //stranka neexistuje
613 //funkcia je void,pojde to ?
614
615 //stranka existuje
616 page_decref(stranka); //moze zavolat page free
617 //pte_t* polozka = (pte_t*)page2pa(stranka);
618 *pte_store = 0;
619 tlb_invalidate(pgdir,va);
620
621}
622
623//
624// Invalidate a TLB entry, but only if the page tables being
625// edited are the ones currently in use by the processor.
626//
627void
628tlb_invalidate(pde_t *pgdir, void *va)
629{
630 // Flush the entry only if we're modifying the current address space.
631 if (!curenv || curenv->env_pgdir == pgdir)
632 invlpg(va);
633}
634
635//
636// Reserve size bytes in the MMIO region and map [pa,pa+size) at this
637// location. Return the base of the reserved region. size does *not*
638// have to be multiple of PGSIZE.
639//
640void *
641mmio_map_region(physaddr_t pa, size_t size)
642{
643 // Where to start the next region. Initially, this is the
644 // beginning of the MMIO region. Because this is static, its
645 // value will be preserved between calls to mmio_map_region
646 // (just like nextfree in boot_alloc).
647 static uintptr_t base = MMIOBASE;
648
649 // Reserve size bytes of virtual memory starting at base and
650 // map physical pages [pa,pa+size) to virtual addresses
651 // [base,base+size). Since this is device memory and not
652 // regular DRAM, you'll have to tell the CPU that it isn't
653 // safe to cache access to this memory. Luckily, the page
654 // tables provide bits for this purpose; simply create the
655 // mapping with PTE_PCD|PTE_PWT (cache-disable and
656 // write-through) in addition to PTE_W. (If you're interested
657 // in more details on this, see section 10.5 of IA32 volume
658 // 3A.)
659 //
660 // Be sure to round size up to a multiple of PGSIZE and to
661 // handle if this reservation would overflow MMIOLIM (it's
662 // okay to simply panic if this happens).
663 //
664 // Hint: The staff solution uses boot_map_region.
665 //
666
667 size=ROUNDUP(size,PGSIZE);
668 if(base+size >= MMIOLIM)
669 panic("mmiOregion");
670
671 boot_map_region(kern_pgdir,base,size,pa,PTE_PCD|PTE_PWT|PTE_W );
672 uintptr_t tmp = base;
673 base += size;
674 return (void*)tmp;
675
676
677
678
679
680
681 // Your code here:
682 //panic("mmio_map_region not implemented");
683}
684
685static uintptr_t user_mem_check_addr;
686
687//
688// Check that an environment is allowed to access the range of memory
689// [va, va+len) with permissions 'perm | PTE_P'.
690// Normally 'perm' will contain PTE_U at least, but this is not required.
691// 'va' and 'len' need not be page-aligned; you must test every page that
692// contains any of that range. You will test either 'len/PGSIZE',
693// 'len/PGSIZE + 1', or 'len/PGSIZE + 2' pages.
694//
695// A user program can access a virtual address if (1) the address is below
696// ULIM, and (2) the page table gives it permission. These are exactly
697// the tests you should implement here.
698//
699// If there is an error, set the 'user_mem_check_addr' variable to the first
700// erroneous virtual address.
701//
702// Returns 0 if the user program can access this range of addresses,
703// and -E_FAULT otherwise.
704//
705int
706user_mem_check(struct Env *env, const void *va, size_t len, int perm)
707{
708 // LAB 3: Your code here.
709
710 uint32_t start = (uint32_t)ROUNDDOWN(va,PGSIZE);
711 uint32_t end = (uint32_t)ROUNDUP(va+len,PGSIZE);
712
713 while (start < end) {
714
715 pte_t *temp=pgdir_walk(env->env_pgdir, (void*)start, 0);
716 if ((start>=ULIM) || !temp || !(*temp & PTE_P) || ((*temp & perm) != perm))//(start >= ULIM || !temp|| !(*temp | perm | PTE_P)) {
717 {if (start<(uint32_t)va){
718
719 user_mem_check_addr=(uint32_t)va;
720
721 }
722 else{
723 user_mem_check_addr=start;
724
725 }
726 return -E_FAULT;
727 }
728 start += PGSIZE;
729 }
730
731 return 0;
732}
733
734//
735// Checks that environment 'env' is allowed to access the range
736// of memory [va, va+len) with permissions 'perm | PTE_U | PTE_P'.
737// If it can, then the function simply returns.
738// If it cannot, 'env' is destroyed and, if env is the current
739// environment, this function will not return.
740//
741void
742user_mem_assert(struct Env *env, const void *va, size_t len, int perm)
743{
744 if (user_mem_check(env, va, len, perm | PTE_U) < 0) {
745 cprintf("[%08x] user_mem_check assertion failure for "
746 "va %08x\n", env->env_id, user_mem_check_addr);
747 env_destroy(env); // may not return
748 }
749}
750
751
752// --------------------------------------------------------------
753// Checking functions.
754// --------------------------------------------------------------
755
756//
757// Check that the pages on the page_free_list are reasonable.
758//
759static void
760check_page_free_list(bool only_low_memory)
761{
762 struct PageInfo *pp;
763 unsigned pdx_limit = only_low_memory ? 1 : NPDENTRIES;
764 int nfree_basemem = 0, nfree_extmem = 0;
765 char *first_free_page;
766
767 if (!page_free_list)
768 panic("'page_free_list' is a null pointer!");
769
770 if (only_low_memory) {
771 // Move pages with lower addresses first in the free
772 // list, since entry_pgdir does not map all pages.
773 struct PageInfo *pp1, *pp2;
774 struct PageInfo **tp[2] = { &pp1, &pp2 };
775 for (pp = page_free_list; pp; pp = pp->pp_link) {
776 int pagetype = PDX(page2pa(pp)) >= pdx_limit;
777 *tp[pagetype] = pp;
778 tp[pagetype] = &pp->pp_link;
779 }
780 *tp[1] = 0;
781 *tp[0] = pp2;
782 page_free_list = pp1;
783 }
784
785 // if there's a page that shouldn't be on the free list,
786 // try to make sure it eventually causes trouble.
787 for (pp = page_free_list; pp; pp = pp->pp_link)
788 if (PDX(page2pa(pp)) < pdx_limit)
789 memset(page2kva(pp), 0x97, 128);
790
791 first_free_page = (char *) boot_alloc(0);
792 for (pp = page_free_list; pp; pp = pp->pp_link) {
793 // check that we didn't corrupt the free list itself
794 assert(pp >= pages);
795 assert(pp < pages + npages);
796 assert(((char *) pp - (char *) pages) % sizeof(*pp) == 0);
797
798 // check a few pages that shouldn't be on the free list
799 assert(page2pa(pp) != 0);
800 assert(page2pa(pp) != IOPHYSMEM);
801 assert(page2pa(pp) != EXTPHYSMEM - PGSIZE);
802 assert(page2pa(pp) != EXTPHYSMEM);
803 assert(page2pa(pp) < EXTPHYSMEM || (char *) page2kva(pp) >= first_free_page);
804 // (new test for lab 4)
805 assert(page2pa(pp) != MPENTRY_PADDR);
806
807 if (page2pa(pp) < EXTPHYSMEM)
808 ++nfree_basemem;
809 else
810 ++nfree_extmem;
811 }
812
813 assert(nfree_basemem > 0);
814 assert(nfree_extmem > 0);
815
816 cprintf("check_page_free_list() succeeded!\n");
817}
818
819//
820// Check the physical page allocator (page_alloc(), page_free(),
821// and page_init()).
822//
823static void
824check_page_alloc(void)
825{
826 struct PageInfo *pp, *pp0, *pp1, *pp2;
827 int nfree;
828 struct PageInfo *fl;
829 char *c;
830 int i;
831
832 if (!pages)
833 panic("'pages' is a null pointer!");
834
835 // check number of free pages
836 for (pp = page_free_list, nfree = 0; pp; pp = pp->pp_link)
837 ++nfree;
838
839 // should be able to allocate three pages
840 pp0 = pp1 = pp2 = 0;
841 assert((pp0 = page_alloc(0)));
842 assert((pp1 = page_alloc(0)));
843 assert((pp2 = page_alloc(0)));
844
845 assert(pp0);
846 assert(pp1 && pp1 != pp0);
847 assert(pp2 && pp2 != pp1 && pp2 != pp0);
848 assert(page2pa(pp0) < npages*PGSIZE);
849 assert(page2pa(pp1) < npages*PGSIZE);
850 assert(page2pa(pp2) < npages*PGSIZE);
851
852 // temporarily steal the rest of the free pages
853 fl = page_free_list;
854 page_free_list = 0;
855
856 // should be no free memory
857 assert(!page_alloc(0));
858
859 // free and re-allocate?
860 page_free(pp0);
861 page_free(pp1);
862 page_free(pp2);
863 pp0 = pp1 = pp2 = 0;
864 assert((pp0 = page_alloc(0)));
865 assert((pp1 = page_alloc(0)));
866 assert((pp2 = page_alloc(0)));
867 assert(pp0);
868 assert(pp1 && pp1 != pp0);
869 assert(pp2 && pp2 != pp1 && pp2 != pp0);
870 assert(!page_alloc(0));
871
872 // test flags
873 memset(page2kva(pp0), 1, PGSIZE);
874 page_free(pp0);
875 assert((pp = page_alloc(ALLOC_ZERO)));
876 assert(pp && pp0 == pp);
877 c = page2kva(pp);
878 for (i = 0; i < PGSIZE; i++)
879 assert(c[i] == 0);
880
881 // give free list back
882 page_free_list = fl;
883
884 // free the pages we took
885 page_free(pp0);
886 page_free(pp1);
887 page_free(pp2);
888
889 // number of free pages should be the same
890 for (pp = page_free_list; pp; pp = pp->pp_link)
891 --nfree;
892 assert(nfree == 0);
893
894 cprintf("check_page_alloc() succeeded!\n");
895}
896
897//
898// Checks that the kernel part of virtual address space
899// has been setup roughly correctly (by mem_init()).
900//
901// This function doesn't test every corner case,
902// but it is a pretty good sanity check.
903//
904
905static void
906check_kern_pgdir(void)
907{
908 uint32_t i, n;
909 pde_t *pgdir;
910
911 pgdir = kern_pgdir;
912
913 // check pages array
914 n = ROUNDUP(npages*sizeof(struct PageInfo), PGSIZE);
915 for (i = 0; i < n; i += PGSIZE)
916 assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);
917
918 // check envs array (new test for lab 3)
919 n = ROUNDUP(NENV*sizeof(struct Env), PGSIZE);
920 for (i = 0; i < n; i += PGSIZE)
921 assert(check_va2pa(pgdir, UENVS + i) == PADDR(envs) + i);
922
923 // check phys mem
924 for (i = 0; i < npages * PGSIZE; i += PGSIZE)
925 assert(check_va2pa(pgdir, KERNBASE + i) == i);
926
927 // check kernel stack
928 // (updated in lab 4 to check per-CPU kernel stacks)
929 for (n = 0; n < NCPU; n++) {
930 uint32_t base = KSTACKTOP - (KSTKSIZE + KSTKGAP) * (n + 1);
931 for (i = 0; i < KSTKSIZE; i += PGSIZE)
932 assert(check_va2pa(pgdir, base + KSTKGAP + i)
933 == PADDR(percpu_kstacks[n]) + i);
934 for (i = 0; i < KSTKGAP; i += PGSIZE)
935 assert(check_va2pa(pgdir, base + i) == ~0);
936 }
937
938 // check PDE permissions
939 for (i = 0; i < NPDENTRIES; i++) {
940 switch (i) {
941 case PDX(UVPT):
942 case PDX(KSTACKTOP-1):
943 case PDX(UPAGES):
944 case PDX(UENVS):
945 case PDX(MMIOBASE):
946 assert(pgdir[i] & PTE_P);
947 break;
948 default:
949 if (i >= PDX(KERNBASE)) {
950 assert(pgdir[i] & PTE_P);
951 assert(pgdir[i] & PTE_W);
952 } else
953 assert(pgdir[i] == 0);
954 break;
955 }
956 }
957 cprintf("check_kern_pgdir() succeeded!\n");
958}
959
960// This function returns the physical address of the page containing 'va',
961// defined by the page directory 'pgdir'. The hardware normally performs
962// this functionality for us! We define our own version to help check
963// the check_kern_pgdir() function; it shouldn't be used elsewhere.
964
965static physaddr_t
966check_va2pa(pde_t *pgdir, uintptr_t va)
967{
968 pte_t *p;
969
970 pgdir = &pgdir[PDX(va)];
971 if (!(*pgdir & PTE_P))
972 return ~0;
973 p = (pte_t*) KADDR(PTE_ADDR(*pgdir));
974 if (!(p[PTX(va)] & PTE_P))
975 return ~0;
976 return PTE_ADDR(p[PTX(va)]);
977}
978
979
980// check page_insert, page_remove, &c
981static void
982check_page(void)
983{
984 struct PageInfo *pp, *pp0, *pp1, *pp2;
985 struct PageInfo *fl;
986 pte_t *ptep, *ptep1;
987 void *va;
988 uintptr_t mm1, mm2;
989 int i;
990 extern pde_t entry_pgdir[];
991
992 // should be able to allocate three pages
993 pp0 = pp1 = pp2 = 0;
994 assert((pp0 = page_alloc(0)));
995 assert((pp1 = page_alloc(0)));
996 assert((pp2 = page_alloc(0)));
997
998 assert(pp0);
999 assert(pp1 && pp1 != pp0);
1000 assert(pp2 && pp2 != pp1 && pp2 != pp0);
1001
1002 // temporarily steal the rest of the free pages
1003 fl = page_free_list;
1004 page_free_list = 0;
1005
1006 // should be no free memory
1007 assert(!page_alloc(0));
1008
1009 // there is no page allocated at address 0
1010 assert(page_lookup(kern_pgdir, (void *) 0x0, &ptep) == NULL);
1011
1012 // there is no free memory, so we can't allocate a page table
1013 assert(page_insert(kern_pgdir, pp1, 0x0, PTE_W) < 0);
1014
1015 // free pp0 and try again: pp0 should be used for page table
1016 page_free(pp0);
1017 assert(page_insert(kern_pgdir, pp1, 0x0, PTE_W) == 0);
1018 assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));
1019 assert(check_va2pa(kern_pgdir, 0x0) == page2pa(pp1));
1020 assert(pp1->pp_ref == 1);
1021 assert(pp0->pp_ref == 1);
1022
1023 // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
1024 assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
1025 assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp2));
1026 assert(pp2->pp_ref == 1);
1027
1028 // should be no free memory
1029 assert(!page_alloc(0));
1030
1031 // should be able to map pp2 at PGSIZE because it's already there
1032 assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
1033 assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp2));
1034 assert(pp2->pp_ref == 1);
1035
1036 // pp2 should NOT be on the free list
1037 // could happen in ref counts are handled sloppily in page_insert
1038 assert(!page_alloc(0));
1039
1040 // check that pgdir_walk returns a pointer to the pte
1041 ptep = (pte_t *) KADDR(PTE_ADDR(kern_pgdir[PDX(PGSIZE)]));
1042 assert(pgdir_walk(kern_pgdir, (void*)PGSIZE, 0) == ptep+PTX(PGSIZE));
1043
1044 // should be able to change permissions too.
1045 assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W|PTE_U) == 0);
1046 assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp2));
1047 assert(pp2->pp_ref == 1);
1048 assert(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U);
1049 assert(kern_pgdir[0] & PTE_U);
1050
1051 // should be able to remap with fewer permissions
1052 assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
1053 assert(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_W);
1054 assert(!(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U));
1055
1056 // should not be able to map at PTSIZE because need free page for page table
1057 assert(page_insert(kern_pgdir, pp0, (void*) PTSIZE, PTE_W) < 0);
1058
1059 // insert pp1 at PGSIZE (replacing pp2)
1060 assert(page_insert(kern_pgdir, pp1, (void*) PGSIZE, PTE_W) == 0);
1061 assert(!(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U));
1062
1063 // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
1064 assert(check_va2pa(kern_pgdir, 0) == page2pa(pp1));
1065 assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp1));
1066 // ... and ref counts should reflect this
1067 assert(pp1->pp_ref == 2);
1068 assert(pp2->pp_ref == 0);
1069
1070 // pp2 should be returned by page_alloc
1071 assert((pp = page_alloc(0)) && pp == pp2);
1072
1073 // unmapping pp1 at 0 should keep pp1 at PGSIZE
1074 page_remove(kern_pgdir, 0x0);
1075 assert(check_va2pa(kern_pgdir, 0x0) == ~0);
1076 assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp1));
1077 assert(pp1->pp_ref == 1);
1078 assert(pp2->pp_ref == 0);
1079
1080 // test re-inserting pp1 at PGSIZE
1081 assert(page_insert(kern_pgdir, pp1, (void*) PGSIZE, 0) == 0);
1082 assert(pp1->pp_ref);
1083 assert(pp1->pp_link == NULL);
1084
1085 // unmapping pp1 at PGSIZE should free it
1086 page_remove(kern_pgdir, (void*) PGSIZE);
1087 assert(check_va2pa(kern_pgdir, 0x0) == ~0);
1088 assert(check_va2pa(kern_pgdir, PGSIZE) == ~0);
1089 assert(pp1->pp_ref == 0);
1090 assert(pp2->pp_ref == 0);
1091
1092 // so it should be returned by page_alloc
1093 assert((pp = page_alloc(0)) && pp == pp1);
1094
1095 // should be no free memory
1096 assert(!page_alloc(0));
1097
1098 // forcibly take pp0 back
1099 assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));
1100 kern_pgdir[0] = 0;
1101 assert(pp0->pp_ref == 1);
1102 pp0->pp_ref = 0;
1103
1104 // check pointer arithmetic in pgdir_walk
1105 page_free(pp0);
1106 va = (void*)(PGSIZE * NPDENTRIES + PGSIZE);
1107 ptep = pgdir_walk(kern_pgdir, va, 1);
1108 ptep1 = (pte_t *) KADDR(PTE_ADDR(kern_pgdir[PDX(va)]));
1109 assert(ptep == ptep1 + PTX(va));
1110 kern_pgdir[PDX(va)] = 0;
1111 pp0->pp_ref = 0;
1112
1113 // check that new page tables get cleared
1114 memset(page2kva(pp0), 0xFF, PGSIZE);
1115 page_free(pp0);
1116 pgdir_walk(kern_pgdir, 0x0, 1);
1117 ptep = (pte_t *) page2kva(pp0);
1118 for(i=0; i<NPTENTRIES; i++)
1119 assert((ptep[i] & PTE_P) == 0);
1120 kern_pgdir[0] = 0;
1121 pp0->pp_ref = 0;
1122
1123 // give free list back
1124 page_free_list = fl;
1125
1126 // free the pages we took
1127 page_free(pp0);
1128 page_free(pp1);
1129 page_free(pp2);
1130
1131 // test mmio_map_region
1132 mm1 = (uintptr_t) mmio_map_region(0, 4097);
1133 mm2 = (uintptr_t) mmio_map_region(0, 4096);
1134 // check that they're in the right region
1135 assert(mm1 >= MMIOBASE && mm1 + 8096 < MMIOLIM);
1136 assert(mm2 >= MMIOBASE && mm2 + 8096 < MMIOLIM);
1137 // check that they're page-aligned
1138 assert(mm1 % PGSIZE == 0 && mm2 % PGSIZE == 0);
1139 // check that they don't overlap
1140 assert(mm1 + 8096 <= mm2);
1141 // check page mappings
1142 assert(check_va2pa(kern_pgdir, mm1) == 0);
1143 assert(check_va2pa(kern_pgdir, mm1+PGSIZE) == PGSIZE);
1144 assert(check_va2pa(kern_pgdir, mm2) == 0);
1145 assert(check_va2pa(kern_pgdir, mm2+PGSIZE) == ~0);
1146 // check permissions
1147 assert(*pgdir_walk(kern_pgdir, (void*) mm1, 0) & (PTE_W|PTE_PWT|PTE_PCD));
1148 assert(!(*pgdir_walk(kern_pgdir, (void*) mm1, 0) & PTE_U));
1149 // clear the mappings
1150 *pgdir_walk(kern_pgdir, (void*) mm1, 0) = 0;
1151 *pgdir_walk(kern_pgdir, (void*) mm1 + PGSIZE, 0) = 0;
1152 *pgdir_walk(kern_pgdir, (void*) mm2, 0) = 0;
1153
1154 cprintf("check_page() succeeded!\n");
1155}
1156
1157// check page_insert, page_remove, &c, with an installed kern_pgdir
1158static void
1159check_page_installed_pgdir(void)
1160{
1161 struct PageInfo *pp, *pp0, *pp1, *pp2;
1162 struct PageInfo *fl;
1163 pte_t *ptep, *ptep1;
1164 uintptr_t va;
1165 int i;
1166
1167 // check that we can read and write installed pages
1168 pp1 = pp2 = 0;
1169 assert((pp0 = page_alloc(0)));
1170 assert((pp1 = page_alloc(0)));
1171 assert((pp2 = page_alloc(0)));
1172 page_free(pp0);
1173 memset(page2kva(pp1), 1, PGSIZE);
1174 memset(page2kva(pp2), 2, PGSIZE);
1175 page_insert(kern_pgdir, pp1, (void*) PGSIZE, PTE_W);
1176 assert(pp1->pp_ref == 1);
1177 assert(*(uint32_t *)PGSIZE == 0x01010101U);
1178 page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W);
1179 assert(*(uint32_t *)PGSIZE == 0x02020202U);
1180 assert(pp2->pp_ref == 1);
1181 assert(pp1->pp_ref == 0);
1182 *(uint32_t *)PGSIZE = 0x03030303U;
1183 assert(*(uint32_t *)page2kva(pp2) == 0x03030303U);
1184 page_remove(kern_pgdir, (void*) PGSIZE);
1185 assert(pp2->pp_ref == 0);
1186
1187 // forcibly take pp0 back
1188 assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));
1189 kern_pgdir[0] = 0;
1190 assert(pp0->pp_ref == 1);
1191 pp0->pp_ref = 0;
1192
1193 // free the pages we took
1194 page_free(pp0);
1195
1196 cprintf("check_page_installed_pgdir() succeeded!\n");
1197}