staticvoid * boot_alloc(uint32_t n) { staticchar *nextfree; // virtual address of next byte of free memory char *result;
// Initialize nextfree if this is the first time. // 'end' is a magic symbol automatically generated by the linker, // which points to the end of the kernel's bss segment: // the first virtual address that the linker did *not* assign // to any kernel code or global variables. if (!nextfree) { externchar end[]; nextfree = ROUNDUP((char *) end, PGSIZE); }
// Allocate a chunk large enough to hold 'n' bytes, then update // nextfree. Make sure nextfree is kept aligned // to a multiple of PGSIZE. // // LAB 2: Your code here. result = nextfree; nextfree += ROUNDUP(n, PGSIZE); return result; }
void mem_init(void) { uint32_t cr0; size_t n;
// Find out how much memory the machine has (npages & npages_basemem). i386_detect_memory();
// Remove this line when you're ready to test this function. // panic("mem_init: This function is not finished\n");
////////////////////////////////////////////////////////////////////// // Recursively insert PD in itself as a page table, to form // a virtual page table at virtual address UVPT. // (For now, you don't have understand the greater purpose of the // following line.)
// Permissions: kernel R, user R kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;
////////////////////////////////////////////////////////////////////// // Allocate an array of npages 'struct PageInfo's and store it in 'pages'. // The kernel uses this array to keep track of physical pages: for // each physical page, there is a corresponding struct PageInfo in this // array. 'npages' is the number of physical pages in memory. Use memset // to initialize all fields of each struct PageInfo to 0. // Your code goes here: pages = (struct PageInfo*)boot_alloc(npages * sizeof(struct PageInfo)); memset(pages,0,npages * sizeof(struct PageInfo)); ////////////////////////////////////////////////////////////////////// // Now that we've allocated the initial kernel data structures, we set // up the list of free physical pages. Once we've done so, all further // memory management will go through the page_* functions. In // particular, we can now map memory using boot_map_region // or page_insert page_init(); check_page_free_list(1); check_page_alloc(); check_page(); ... }
void page_init(void) { // The example code here marks all physical pages as free. // However this is not truly the case. What memory is free? // 1) Mark physical page 0 as in use. // This way we preserve the real-mode IDT and BIOS structures // in case we ever need them. (Currently we don't, but...) // 2) The rest of base memory, [PGSIZE, npages_basemem * PGSIZE) // is free. // 3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM), which must // never be allocated. // 4) Then extended memory [EXTPHYSMEM, ...). // Some of it is in use, some is free. Where is the kernel // in physical memory? Which pages are already in use for // page tables and other data structures? // // Change the code to reflect this. // NB: DO NOT actually touch the physical memory corresponding to // free pages! void * kern_used = boot_alloc(0); size_t i; for (i = 0; i < npages; i++) { if(i == 0){ pages[i].pp_ref = 1; pages[i].pp_link = NULL; }elseif(i < npages_basemem || i < IOPHYSMEM >> PGSHIFT){ pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; }elseif(i >= IOPHYSMEM >> PGSHIFT && i < EXTPHYSMEM >> PGSHIFT){ pages[i].pp_ref = 1; pages[i].pp_link = NULL; }elseif(i <= PADDR(kern_used) >> PGSHIFT){ pages[i].pp_ref = 1; pages[i].pp_link = NULL; }else{ pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } } }
struct PageInfo * page_alloc(int alloc_flags) { // Fill this function in if(page_free_list == NULL) returnNULL; structPageInfo *pp = page_free_list; if(alloc_flags & ALLOC_ZERO){ memset(page2kva(pp), 0, PGSIZE); } page_free_list = pp->pp_link; pp->pp_link = NULL;
return pp; }
void page_free(struct PageInfo *pp) { // Fill this function in // Hint: You may want to panic if pp->pp_ref is nonzero or // pp->pp_link is not NULL. if(pp->pp_ref != 0 || pp->pp_link != NULL){ panic("page ref is not null"); } pp->pp_link = page_free_list; page_free_list = pp; }
pte_t * pgdir_walk(pde_t *pgdir, constvoid *va, int create) { // Fill this function in uint32_t pde = pgdir[PDX(va)]; if(!(pde & PTE_P)){ if (!create)returnNULL; structPageInfo * page = page_alloc(ALLOC_ZERO); if(page == NULL){ returnNULL; } page->pp_ref++; pgdir[PDX(va)] = page2pa(page) | PTE_W | PTE_U | PTE_P; } pte_t * pte = (pte_t*)(KADDR(PTE_ADDR((pgdir[PDX(va)])))) + PTX(va);
return pte; }
staticvoid boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm) { // Fill this function in for(size_t i = 0;i < size;i+=PGSIZE){ pte_t * pte = pgdir_walk(pgdir,(void*)(va+i),1); *pte = (pa+i)|perm|PTE_P; } }
int page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm) { // Fill this function in pte_t * pte = pgdir_walk(pgdir,va,1); if(pte == NULL){ return -E_NO_MEM; } pp->pp_ref++; if((*pte) & PTE_P){ tlb_invalidate(pgdir,va); page_remove(pgdir,va); } *pte = (page2pa(pp) | perm | PTE_P); return0; }
What entries (rows) in the page directory have been filled in at this point? What addresses do they map and where do they point? In other words, fill out this table as much as possible: