// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! /*stone's solution for lab2*/ size_t i; for (i = 1; i < npages_basemem; i++){ pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } //use boot_alloc(0) to get next free page for (i = (PADDR(boot_alloc(0)) / PGSIZE); i < npages; i++){ pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } chunk_list = NULL; }
// map physcical memory [0,PGSIZE*npages] to [KERNBASE,KERNBASE+PGSIZE*npages] ,in case // one physical memory can't find its virtual address static void boot_phys_map() { uintptr_t sp=KERNBASE+0X400000; int i,j; pte_t* pgtable; pde_t* entry_pgdir=(pde_t*)(rcr3()+KERNBASE); int npts= (npages / 1024)+1; int actual_top=KERNBASE+npages*PGSIZE; for(i=0; i<npts && sp<actual_top; i++){ pgtable=boot_alloc(PGSIZE); memset(pgtable, 0, PGSIZE); entry_pgdir[PDX(sp)]=((int)pgtable-KERNBASE) | PTE_P | PTE_U | PTE_W; // cprintf("the entry_pgdir'%dth pde is %x\n ",PDX(sp),(int)entry_pgdir[PDX(sp)]); for(j=0;j<1024 && sp<actual_top;j++){ pgtable[j]=((uint32_t)sp-KERNBASE) | PTE_P | PTE_U | PTE_W; sp+=PGSIZE; } } }
static void * segkmem_alloc_vn(vmem_t *vmp, size_t size, int vmflag, struct vnode *vp) { void *addr; segkmem_gc_list_t *gcp, **prev_gcpp; ASSERT(vp != NULL); if (kvseg.s_base == NULL) { #ifndef __sparc if (bootops->bsys_alloc == NULL) halt("Memory allocation between bop_alloc() and " "kmem_alloc().\n"); #endif /* * There's not a lot of memory to go around during boot, * so recycle it if we can. */ for (prev_gcpp = &segkmem_gc_list; (gcp = *prev_gcpp) != NULL; prev_gcpp = &gcp->gc_next) { if (gcp->gc_arena == vmp && gcp->gc_size == size) { *prev_gcpp = gcp->gc_next; return (gcp); } } addr = vmem_alloc(vmp, size, vmflag | VM_PANIC); if (boot_alloc(addr, size, BO_NO_ALIGN) != addr) panic("segkmem_alloc: boot_alloc failed"); return (addr); } return (segkmem_xalloc(vmp, NULL, size, vmflag, 0, segkmem_page_create, vp)); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! size_t i; page_free_list = 0; extern char end[]; // Magic pointer to end of kernel data uint32_t free_pages = 0; for (i = npages-1; i + 1 > 0; i--) { pages[i].pp_ref = 0; // Base memory pages other than 0 are free: add them to the free list if ((i < npages_basemem) && (i != 0)) { // pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; free_pages++; } // Skip the IO hole // Some of extended memory is free: focus our attention there if (i >= (EXTPHYSMEM / PGSIZE)) { // The kernel isn't free! if (i < (PADDR(ROUNDUP((char *) end, PGSIZE)) / PGSIZE)) { continue; } // We've allocated some number of pages using boot alloc... if (i < ((size_t) PADDR(boot_alloc(0))) / PGSIZE) { continue; } // Otherwise, the memory is free XXX What about the kernel stack? //pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; free_pages++; } } //cprintf("Reserved up to %x for kernel\n", ROUNDUP((char *) end, PGSIZE)); //cprintf("Finished page_init. %d free pages remain.\n", free_page_count()); }
// // Check that the pages on the page_free_list are reasonable. // static void check_page_free_list(bool only_low_memory) { struct Page *pp; unsigned pdx_limit = only_low_memory ? 1 : NPDENTRIES; int nfree_basemem = 0, nfree_extmem = 0; char *first_free_page; if (!page_free_list) panic("'page_free_list' is a null pointer!"); if (only_low_memory) { // Move pages with lower addresses first in the free // list, since entry_pgdir does not map all pages. struct Page *pp1, *pp2; struct Page **tp[2] = { &pp1, &pp2 }; for (pp = page_free_list; pp; pp = pp->pp_link) { int pagetype = PDX(page2pa(pp)) >= pdx_limit; *tp[pagetype] = pp; tp[pagetype] = &pp->pp_link; } *tp[1] = 0; *tp[0] = pp2; page_free_list = pp1; } // if there's a page that shouldn't be on the free list, // try to make sure it eventually causes trouble. for (pp = page_free_list; pp; pp = pp->pp_link) if (PDX(page2pa(pp)) < pdx_limit) memset(page2kva(pp), 0x97, 128); first_free_page = (char *) boot_alloc(0); for (pp = page_free_list; pp; pp = pp->pp_link) { // check that we didn't corrupt the free list itself assert(pp >= pages); assert(pp < pages + npages); assert(((char *) pp - (char *) pages) % sizeof(*pp) == 0); // check a few pages that shouldn't be on the free list assert(page2pa(pp) != 0); assert(page2pa(pp) != IOPHYSMEM); assert(page2pa(pp) != EXTPHYSMEM - PGSIZE); assert(page2pa(pp) != EXTPHYSMEM); assert(page2pa(pp) < EXTPHYSMEM || (char *) page2kva(pp) >= first_free_page); // (new test for lab 4) assert(page2pa(pp) != MPENTRY_PADDR); if (page2pa(pp) < EXTPHYSMEM) ++nfree_basemem; else ++nfree_extmem; } assert(nfree_basemem > 0); assert(nfree_extmem > 0); cprintf("check_page_free_list() succeeded!\n"); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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 of 384K [IOPHYSMEM starts at 640k, EXTPHYSMEM starts at 1MB), 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! size_t i,j; struct PageInfo *tail; //Initially setting all pages as used. for(i=0;i<npages;i++){ pages[i].pp_ref=1; pages[i].pp_link=0; } //setting phsyical page 0 in use //pages[0].pp_ref=1; //pages[0].pp_link=&pages[ROUNDUP(EXTPHYSMEM,PGSIZE)/PGSIZE]; //Mark Pages 1 to IOPHYSMEM as free page_free_list = 0; for (i = 1; i < npages_basemem ; ++i) { pages[i].pp_ref = 0; pages[i].pp_link =0; if(!page_free_list) page_free_list=&pages[i]; else{ //cprintf("page: %d and page-1: %d\n",i,i-1); pages[i-1].pp_link=&pages[i]; } } tail=&pages[i-1]; // Map rest of free memory for(j=((ROUNDUP(PADDR(boot_alloc(0)),PGSIZE)/PGSIZE)+1);j<npages;++j){ //cprintf(" print j %d and j-1 %d \n",j,j-1 ); pages[j].pp_ref = 0; pages[j].pp_link =0; tail->pp_link=&pages[j]; tail=&pages[j]; } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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! size_t i; for (i = 0; i < npages; i++) { if (i == 0 || i == MPENTRY_PADDR / PGSIZE) { // This is case 1 or // This is the multiprocessor case pages[i].pp_ref = 1; } else if (i >= 1 && i < npages_basemem) { // This is case 2 pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } else if (i >= IOPHYSMEM / PGSIZE && i < EXTPHYSMEM / PGSIZE) { // This is case 3 pages[i].pp_ref = 1; } else if (i >= EXTPHYSMEM / PGSIZE && i < PADDR(boot_alloc(0)) / PGSIZE) { // This is case 4 pages[i].pp_ref = 1; } else { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } } }
void initialize_vm_64(void){ uint64_t* pml4e; pages = boot_alloc(npages*sizeof(struct PageStruct)); procs = boot_alloc(NPROCS*sizeof(struct ProcStruct)); proc_free_list = procs; pml4e = boot_alloc(PGSIZE); boot_pml4e = pml4e; boot_cr3 = (physaddr_t*)PADDR(pml4e); kmemset(boot_pml4e,0,PGSIZE); initialize_page_lists(); printf("Total free=%d",free_pages); // while(i--); if( map_vm_pm(boot_pml4e, (uint64_t)PHYSBASE,PADDR(PHYSBASE),(uint64_t)(boot_alloc(0)-PHYSBASE),PTE_P|PTE_W)==-1) while(1); if( map_vm_pm(boot_pml4e, (uint64_t)KERNBASE+PGSIZE,0x1000,0x7000000-0x1000,PTE_P|PTE_W)==-1)//KERNELSTACK =tss.rspp0 while(1); if( map_vm_pm(boot_pml4e, (uint64_t)VIDEO_START,PADDR(VIDEO_START),10*0x1000,PTE_P|PTE_W)==-1) while(1); printf("TotalFREE=%d",free_pages); lcr3(boot_cr3); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! uint32_t num_alloc = ((uint32_t)boot_alloc(0)-KERNBASE)/PGSIZE; uint32_t num_io_pages = (EXTPHYSMEM - IOPHYSMEM)/PGSIZE; page_free_list = NULL; size_t i; for(i = 0; i < npages; ++i) { if((i == 0)|| // io hole ( i >= npages_basemem && i<npages_basemem+num_io_pages )|| // alloc by kernel, kernel alloc pages and kern_pgdir on stack // num_alloc isn't all pages used, it is just memory used by kernel ( i >= npages_basemem+num_io_pages && i < npages_basemem+num_io_pages+num_alloc )) { pages[0].pp_ref = 1; }else { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! int i; physaddr_t firstFreePhysAddr=(physaddr_t)PADDR(boot_alloc(0)); page_free_list=NULL; for (i = npages-1; i >= 0; i--) { physaddr_t pagePhysAddr=(physaddr_t)PGADDR(0,i,0); if(pagePhysAddr==0|| (pagePhysAddr>=IOPHYSMEM&&pagePhysAddr<firstFreePhysAddr)) { 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]; } } }
/** * @brief Initialize the array of physical pages and memory free list. * * The 'pages' array has one 'page_t' entry per physical page. * Pages are reference counted, and free pages are kept on a linked list. */ void page_init(void) { /* * First, make 'pages' point to an array of size 'npages' of * type 'page_t'. * The kernel uses this structure to keep track of physical pages; * 'npages' equals the number of physical pages in memory. * round up to the nearest page */ pages = (page_t*)boot_alloc(npages*sizeof(page_t), PGSIZE); memset(pages, 0, npages*sizeof(page_t)); /* * Then initilaize everything so pages can start to be alloced and freed * from the memory free list */ page_alloc_init(); static_assert(PROCINFO_NUM_PAGES <= PTSIZE); static_assert(PROCDATA_NUM_PAGES <= PTSIZE); }
// // Check that the pages on the page_free_list are reasonable. // static void check_page_free_list(bool only_low_memory) { struct Page *pp; unsigned pdx_limit = only_low_memory ? 4 : NPDENTRIES; int nfree_basemem = 0, nfree_extmem = 0; char *first_free_page; if (!page_free_list) panic("'page_free_list' is a null pointer!"); // if there's a page that shouldn't be on the free list, // try to make sure it eventually causes trouble. for (pp = page_free_list; pp; pp = pp->pp_link) if (PDX(page2pa(pp)) < pdx_limit) memset(page2kva(pp), 0x97, 128); first_free_page = (char *) boot_alloc(0); for (pp = page_free_list; pp; pp = pp->pp_link) { // check that we didn't corrupt the free list itself assert(pp >= pages); assert(pp < pages + npages); assert(((char *) pp - (char *) pages) % sizeof(*pp) == 0); // check a few pages that shouldn't be on the free list assert(page2pa(pp) != 0); assert(page2pa(pp) != IOPHYSMEM); assert(page2pa(pp) != EXTPHYSMEM - PGSIZE); assert(page2pa(pp) != EXTPHYSMEM); assert(page2pa(pp) < EXTPHYSMEM || page2kva(pp) >= first_free_page); if (page2pa(pp) < EXTPHYSMEM) ++nfree_basemem; else ++nfree_extmem; } assert(nfree_basemem > 0); assert(nfree_extmem > 0); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! size_t i; //start i from 1 as 0 in use //Sets [PGSIZE, npages_basemem * PGSIZE) as free. for (i = 1; i < npages_basemem; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } //boot_alloc(0) gives the address of the next free page,after the kernel strucutres //cprintf("&&&**** %x %x %x, %x\n", boot_alloc(0), PADDR(boot_alloc(0)), PGNUM(boot_alloc(0)), PGNUM(PADDR(boot_alloc(0)))); for (i = PGNUM(PADDR(boot_alloc(0))); i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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! size_t i; extern char end[]; uint32_t upp = PADDR(boot_alloc(0)); cprintf("end: %x npages: %d sizeof struct Page: %x PGSIZE: %x IOPHYSMEM: %x\n",end,npages,sizeof(struct Page),PGSIZE,IOPHYSMEM); for (i = 0; i < npages; i++) { if (i == 0) continue; if ((i >= PGNUM(IOPHYSMEM) && i < PGNUM(upp)) || i==MPENTRY_PADDR/PGSIZE) continue; pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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! int i; int st = PTX(IOPHYSMEM); int en = (int)PTX(PADDR(boot_alloc(0))); page_free_list = NULL; for (i = 1; i < npages; i++) { if (st <= i && i< en) continue; if (i == PTX(MPENTRY_PADDR)) continue; pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; //page is in use if pp_link == NULL } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! size_t i; uint32_t nextfree = (uint32_t)boot_alloc(0); pages[0].pp_ref = 1; debug(DEBUG_INFO, "NPAGES: %d NPAGES_BASE_MEM: %d\n", npages, npages_basemem); for (i = 1; i < npages; i++) { if ((i >= (IOPHYSMEM / PGSIZE)) && (i < ((nextfree - KERNBASE)/ PGSIZE))) { 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]; } } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! /* size_t i; for (i = 0; i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } */ size_t i; void * free_vaddress; physaddr_t free_paddress; // page 0 pages[0].pp_ref = 0; pages[0].pp_link = NULL; // base memory for (i = 1; i < npages_basemem; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } // IO hole assert (IOPHYSMEM % PGSIZE == 0 && EXTPHYSMEM % PGSIZE == 0); assert (npages_basemem * PGSIZE == IOPHYSMEM); for (i = npages_basemem; i < EXTPHYSMEM / PGSIZE; i++) { pages[i].pp_ref = 0; pages[i].pp_link = NULL; } // extended memory free_vaddress = boot_alloc(0); free_paddress = PADDR(free_vaddress); assert(free_paddress > EXTPHYSMEM && free_paddress % PGSIZE == 0 && free_paddress < npages * PGSIZE && free_paddress/PGSIZE < npages); for (i = EXTPHYSMEM / PGSIZE; i < free_paddress / PGSIZE; i++) { pages[i].pp_ref = 0; pages[i].pp_link = NULL; } for (i = free_paddress / PGSIZE; i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
// Set up a two-level page table: // kern_pgdir is its linear (virtual) address of the root // // This function only sets up the kernel part of the address space // (ie. addresses >= UTOP). The user part of the address space // will be setup later. // // From UTOP to ULIM, the user is allowed to read but not write. // Above ULIM the user cannot read or write. void mem_init(void) { uint32_t cr0; size_t n; // Find out how much memory the machine has (npages & npages_basemem). i386_detect_memory(); ////////////////////////////////////////////////////////////////////// // create initial page directory. kern_pgdir = (pde_t *) boot_alloc(PGSIZE); memset(kern_pgdir, 0, PGSIZE); ////////////////////////////////////////////////////////////////////// // 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 Page'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 Page in this // array. 'npages' is the number of physical pages in memory. // Your code goes here: pages = boot_alloc(npages*sizeof(* pages)); ////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. envs = boot_alloc(NENV * sizeof(* envs)); ////////////////////////////////////////////////////////////////////// // 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(); ////////////////////////////////////////////////////////////////////// // Now we set up virtual memory ////////////////////////////////////////////////////////////////////// // Map 'pages' read-only by the user at linear address UPAGES // Permissions: // - the new image at UPAGES -- kernel R, user R // (ie. perm = PTE_U | PTE_P) // - pages itself -- kernel RW, user NONE // Your code goes here: boot_map_region( kern_pgdir, (uintptr_t) UPAGES, npages*(sizeof(* pages)), PADDR(pages), PTE_U | PTE_P); boot_map_region( kern_pgdir, (uintptr_t) pages, npages*(sizeof(* pages)), PADDR(pages), PTE_W | PTE_P); ////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS // (ie. perm = PTE_U | PTE_P). // Permissions: // - the new image at UENVS -- kernel R, user R // - envs itself -- kernel RW, user NONE // LAB 3: Your code here. boot_map_region( kern_pgdir, (uintptr_t) UENVS, npages*(sizeof(* envs)), PADDR(envs), PTE_U | PTE_P); boot_map_region( kern_pgdir, (uintptr_t) envs, npages*(sizeof(* envs)), PADDR(envs), PTE_W | PTE_P); ////////////////////////////////////////////////////////////////////// // Use the physical memory that 'bootstack' refers to as the kernel // stack. The kernel stack grows down from virtual address KSTACKTOP. // We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP) // to be the kernel stack, but break this into two pieces: // * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory // * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if // the kernel overflows its stack, it will fault rather than // overwrite memory. Known as a "guard page". // Permissions: kernel RW, user NONE // Your code goes here: boot_map_region( kern_pgdir, KSTACKTOP-KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W | PTE_P ); ////////////////////////////////////////////////////////////////////// // Map all of physical memory at KERNBASE. // Ie. the VA range [KERNBASE, 2^32) should map to // the PA range [0, 2^32 - KERNBASE) // We might not have 2^32 - KERNBASE bytes of physical memory, but // we just set up the mapping anyway. // Permissions: kernel RW, user NONE // Your code goes here: boot_map_region( kern_pgdir, (uintptr_t) KERNBASE, 0xFFFFFFFF, 0, PTE_W | PTE_P); // Initialize the SMP-related parts of the memory map mem_init_mp(); // Check that the initial page directory has been set up correctly. check_kern_pgdir(); // Switch from the minimal entry page directory to the full kern_pgdir // page table we just created. Our instruction pointer should be // somewhere between KERNBASE and KERNBASE+4MB right now, which is // mapped the same way by both page tables. // // If the machine reboots at this point, you've probably set up your // kern_pgdir wrong. lcr3(PADDR(kern_pgdir)); check_page_free_list(0); // entry.S set the really important flags in cr0 (including enabling // paging). Here we configure the rest of the flags that we care about. cr0 = rcr0(); cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP; cr0 &= ~(CR0_TS|CR0_EM); lcr0(cr0); // Some more checks, only possible after kern_pgdir is installed. check_page_installed_pgdir(); }
static int libexec_alloc_vm_ondemand(struct exec_info *execi, off_t vaddr, size_t len) { boot_alloc(execi, vaddr, len, 0); return OK; }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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! //page_free_list = NULL; /* size_t i; for (i = 0; i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } */ /* ** preserve IO hole + kern_pgdir + pages: ** [IOPHYSMEM, EXTPHYSMEM) + ** [EXTPHYSMEM, EXTPHYSMEM + PGSIZE) + ** [EXTPHYSMEM + PGSIZE, EXTPHYSMEM + PGSIZE + npages * sizeof(struct pageInfo)) */ size_t lower_idx = PGNUM(IOPHYSMEM); //volatile size_t upper_num = PGNUM( (ROUNDUP( EXTPHYSMEM + PGSIZE + npages * sizeof(struct PageInfo), PGSIZE ))); size_t upper_idx = PGNUM(PADDR(boot_alloc(0))); size_t mpentry_idx = PGNUM(MPENTRY_PADDR); assert(lower_idx < npages); assert(upper_idx < npages); size_t i; for(i = 0; i < npages; i++){ //pages[i].pp_ref = 0; /* preserve the real-mode IDT and BIOS structures */ if(i == 0) { continue; } if(i == mpentry_idx) { continue; } if(i >= lower_idx && i < upper_idx) { continue; } /* insert into page_free_list */ pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
static int libexec_alloc_vm_prealloc(struct exec_info *execi, off_t vaddr, size_t len) { boot_alloc(execi, vaddr, len, MF_PREALLOC); return OK; }
page_list_t* colored_page_free_list = NULL; spinlock_t colored_page_free_list_lock = SPINLOCK_INITIALIZER_IRQSAVE; /* * Initialize the memory free lists. * After this point, ONLY use the functions below * to allocate and deallocate physical memory via the * page_free_lists. */ void page_alloc_init(struct multiboot_info *mbi) { init_once_racy(return); size_t list_size = llc_cache->num_colors*sizeof(page_list_t);; page_list_t* lists = (page_list_t*)boot_alloc(list_size, PGSIZE); size_t num_colors = llc_cache->num_colors; for (size_t i = 0; i < num_colors; i++) BSD_LIST_INIT(&lists[i]); uintptr_t first_free_page = ROUNDUP(boot_freemem, PGSIZE); uintptr_t first_invalid_page = LA2PPN(boot_freelimit); assert(first_invalid_page == max_nr_pages); // mark kernel pages as in-use for (uintptr_t page = 0; page < first_free_page; page++) page_setref(&pages[page], 1); // append other pages to the free lists for (uintptr_t page = first_free_page; page < first_invalid_page; page++)
// Set up a two-level page table: // kern_pgdir is its linear (virtual) address of the root // Then turn on paging. Then effectively turn off segmentation. // (i.e., the segment base addrs are set to zero). // // This function only sets up the kernel part of the address space // (ie. addresses >= UTOP). The user part of the address space // will be setup later. // // From UTOP to ULIM, the user is allowed to read but not write. // Above ULIM the user cannot read or write. void mem_init(void) { uint32_t cr0; size_t n; // Ensure user & kernel struct Pages agree. static_assert(sizeof(struct Page) == sizeof(struct UserPage)); // 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"); ////////////////////////////////////////////////////////////////////// // create initial page directory. kern_pgdir = (pde_t *) boot_alloc(PGSIZE); memset(kern_pgdir, 0, PGSIZE); ////////////////////////////////////////////////////////////////////// // 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 Page'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 Page in this // array. 'npages' is the number of physical pages in memory. pages = (Page *) boot_alloc(npages * sizeof(struct Page)); ////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. envs = (Env *) boot_alloc(NENV * sizeof(struct Env)); ////////////////////////////////////////////////////////////////////// // 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 page_map_segment // or page_insert page_init(); check_page_free_list(true); check_page_alloc(); check_page(); ////////////////////////////////////////////////////////////////////// // Now we set up virtual memory ////////////////////////////////////////////////////////////////////// // Use the physical memory that 'entry_stack' refers to as the kernel // stack. The kernel stack grows down from virtual address KSTACKTOP. // We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP) // to be the kernel stack, but break this into two pieces: // * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory // * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if // the kernel overflows its stack, it will fault rather than // overwrite memory. Known as a "guard page". // Permissions: kernel RW, user NONE Page *pp = pa2page((physaddr_t)entry_stack-KERNBASE); for (uintptr_t ptr = KSTACKTOP-KSTKSIZE; ptr < KSTACKTOP; ptr += PGSIZE) { if (page_insert(kern_pgdir, pp, ptr, PTE_W | PTE_P) < 0) panic("Couldn't create page table entries for stack.\n"); pp++; } ////////////////////////////////////////////////////////////////////// // Map all of physical memory at KERNBASE. // Ie. the VA range [KERNBASE, 2^32) should map to // the PA range [0, 2^32 - KERNBASE) // We might not have 2^32 - KERNBASE bytes of physical memory, but // we just set up the mapping anyway. // Permissions: kernel RW, user NONE page_map_segment(kern_pgdir, KERNBASE, 0xFFFFFFFF-KERNBASE, 0x0, PTE_W | PTE_P); //print_page_table(kern_pgdir, false, false); ////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS. // Permissions: kernel R, user R // (That's the UENVS version; 'envs' itself is kernel RW, user NONE.) // LAB 3: Your code here. page_map_segment(kern_pgdir, (uintptr_t) UENVS, ROUNDUP(NENV*sizeof(struct Env), PGSIZE), PADDR(envs), PTE_U | PTE_P); ////////////////////////////////////////////////////////////////////// // Map 'pages' read-only by the user at linear address UPAGES. // Permissions: kernel R, user R // (That's the UPAGES version; 'pages' itself is kernel RW, user NONE.) // LAB 3: Your code here. page_map_segment(kern_pgdir, UPAGES, ROUNDUP(npages*sizeof(struct Page), PGSIZE), PADDR(pages), PTE_U | PTE_P); // Check that the initial page directory has been set up correctly. check_kern_pgdir(); // Switch from the minimal entry page directory to the full kern_pgdir // page table we just created. Our instruction pointer should be // somewhere between KERNBASE and KERNBASE+4MB right now, which is // mapped the same way by both page tables. // // If the machine reboots at this point, you've probably set up your // kern_pgdir wrong. lcr3(PADDR(kern_pgdir)); // entry.S set the really important flags in cr0 (including enabling // paging). Here we configure the rest of the flags we need. cr0 = rcr0(); cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_MP; cr0 &= ~(CR0_TS|CR0_EM); lcr0(cr0); // Some more checks, only possible after kern_pgdir is installed. check_page_installed_pgdir(); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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! // Remember: Pages allocated at boot time using pmap.c's // boot_alloc do not have valid reference count fields. // So don't add them to free list, but don't bother setting // pp_ref either. uint32_t i = 0; page_free_list = NULL; // Start w/ empty free list // Mark physical page 0 as in use pages[0].pp_ref = 1; i += 1; // Mark rest of base memory free for (; i < npages_basemem; i++) { // Don't add page at MPENTRY_PADDR which has AP bootstrap code if (i == MPENTRY_PADDR/PGSIZE) { continue; } pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } // Base memory must end at I/O hole assert(npages_basemem * PGSIZE == IOPHYSMEM); // Mark I/O hole as *used* as well for (; i < EXTPHYSMEM/PGSIZE; i++) { pages[i].pp_ref = 1; } // Mark initial extended memory w/ kernel & kernal datastructures // as used. for (; i < PADDR(boot_alloc(0))/PGSIZE ; i++) { pages[i].pp_ref = 1; } // Mark all other physical pages as free for (; i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use struct PageInfo *temp,*temp1,*temp2,*temp3, *mpentry; page_free_list = pages; // 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! size_t i, range; for (i = 0; i < npages-1; i++) { pages[i].pp_ref = 0; pages[i].pp_link = &pages[i+1]; } pages[npages-1].pp_ref = 0; pages[npages-1].pp_link = NULL; page_free_list = pages; // marking page 0 as busy. case 1 page_free_list->pp_ref = 1; temp = page_free_list; page_free_list = temp->pp_link; temp->pp_link=NULL; //marking MPENTRY_PADDR as busy page. This page is present in basemem pages mpentry = pa2page(MPENTRY_PADDR); (mpentry-1)->pp_link = mpentry->pp_link; mpentry->pp_link = NULL; mpentry->pp_ref = 1; //case 2 temp = page_free_list + npages_basemem-2; //temp is last free block in base memory temp1 = temp->pp_link; //case 3 range = (EXTPHYSMEM - IOPHYSMEM) / (PGSIZE); for(i=0;i<range-1;i++) { temp2=temp1->pp_link; temp1->pp_link = NULL; temp1->pp_ref = 1; temp1 = temp2; } temp2 = temp1->pp_link; temp1->pp_link = NULL; temp1->pp_ref = 1; temp1 = temp2; //case 4 range = ((uint32_t) boot_alloc(0) - (uint32_t)KADDR(EXTPHYSMEM))/ (PGSIZE); for(i=0;i<range-1;i++) { temp2=temp1->pp_link; temp1->pp_link = NULL; temp1->pp_ref = 1; temp1 = temp2; } temp2 = temp1->pp_link; temp1->pp_link = NULL; temp1->pp_ref = 1; temp1 = temp2; temp->pp_link = temp1; }
void up_allocate_heap(void **heap_start, size_t *heap_size) { void *boot_freemem = boot_alloc(0, sizeof(int)); *heap_start = boot_freemem; *heap_size = KERNBASE + kmem_size - (uint32_t)boot_freemem; }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // 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! size_t s=0,e=0; int i; page_free_list=0; //cprintf("pages=%x\n",(uint32_t )pages); // 1) correspond to 1) above ,set the first element 's ret to 1; pages[0].pp_ref=1; // 2) correspond to 2) above //cprintf("npages=%u\n",npages); s = PGSIZE / PGSIZE; e = MPENTRY_PADDR /PGSIZE-1; _page_init(s,e); // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use pages[MPENTRY_PADDR / PGSIZE].pp_ref=1; s = MPENTRY_PADDR / PGSIZE + 1; e = npages_basemem-1; _page_init(s,e); // 3) correspond to 3) above s = IOPHYSMEM / PGSIZE; e = EXTPHYSMEM / PGSIZE - 1; for(i=s; i<=e; i++) pages[i].pp_ref=1; // 4) correspond to 4) above,the low 4MB memory has been used to map // virtual address [KERNBASE,KERNBASE+0X400000] by entry.s, kernal and some // important struct such as pages and kern_pgdir is in this region.On the other // side, the rest of free space of we can't get unitl syetem runing ,so we mark // space [0x100000,0x400000] is not free ,just skip it s=EXTPHYSMEM / PGSIZE; e=((int)boot_alloc(0)-KERNBASE) / PGSIZE - 1; // cprintf("1.boot_alloc(0)=%x\n",boot_alloc(0)); for(i=s; i<=e; i++) pages[i].pp_ref=1; // 5) the part no used above s=( (int)boot_alloc(0)-KERNBASE) / PGSIZE ; e=npages-1; //cprintf("2.boot_alloc(0)=%x\n",boot_alloc(0)); _page_init(s,e); }
// // Initialize page structure and memory free list. // After this is done, NEVER use boot_alloc again. ONLY use the page // allocator functions below to allocate and deallocate physical // memory via the page_free_list. // void page_init(void) { // LAB 4: // Change your code to mark the physical page at MPENTRY_PADDR // as in use // 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? pages[0].pp_ref = 1; pages[1].pp_link = page_free_list; size_t i; for (i = 1; i < MPENTRY_PADDR/PGSIZE; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } pages[i].pp_ref = 1; pages[1].pp_link = NULL; for (i = MPENTRY_PADDR/PGSIZE+1; i < npages_basemem; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } for( i=IOPHYSMEM/PGSIZE; i < EXTPHYSMEM/PGSIZE; i++) { pages[i].pp_ref = 1; pages[i].pp_link = 0; } for( i; i < PADDR((void *) KERNBASE)/PGSIZE; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } uint32_t free_start = ((uint32_t) PADDR(boot_alloc(0)))/PGSIZE; for( i; i < free_start; i++) { pages[i].pp_ref = 1; pages[i].pp_link = 0; } for(i; i < npages; i++) { pages[i].pp_ref = 0; pages[i].pp_link = page_free_list; page_free_list = &pages[i]; } }
// Set up a four-level page table: // boot_pml4e is its linear (virtual) address of the root // // This function only sets up the kernel part of the address space // (ie. addresses >= UTOP). The user part of the address space // will be setup later. // // From UTOP to ULIM, the user is allowed to read but not write. // Above ULIM the user cannot read or write. void x64_vm_init(void) { pml4e_t* pml4e; uint32_t cr0; int i; size_t n; int r; struct Env *env; i386_detect_memory(); //panic("i386_vm_init: This function is not finished\n"); ////////////////////////////////////////////////////////////////////// // create initial page directory. ///panic("x64_vm_init: this function is not finished\n"); pml4e = boot_alloc(PGSIZE); memset(pml4e, 0, PGSIZE); boot_pml4e = pml4e; boot_cr3 = PADDR(pml4e); ////////////////////////////////////////////////////////////////////// // Allocate an array of npage 'struct Page'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 Page in this // array. 'npage' is the number of physical pages in memory. // User-level programs will get read-only access to the array as well. // Your code goes here: pages = boot_alloc(npages * sizeof(struct Page)); ////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. envs = boot_alloc(NENV * sizeof(struct Env)); ////////////////////////////////////////////////////////////////////// // 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_segment or page_insert page_init(); check_page_free_list(1); check_page_alloc(); page_check(); ////////////////////////////////////////////////////////////////////// // Now we set up virtual memory ////////////////////////////////////////////////////////////////////// // Map 'pages' read-only by the user at linear address UPAGES // Permissions: // - the new image at UPAGES -- kernel R, user R // (ie. perm = PTE_U | PTE_P) // - pages itself -- kernel RW, user NONE // Your code goes here: ////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS // (ie. perm = PTE_U | PTE_P). // Permissions: // - the new image at UENVS -- kernel R, user R // - envs itself -- kernel RW, user NONE // LAB 3: Your code here. boot_map_segment(boot_pml4e, UPAGES, ROUNDUP(npages*sizeof(struct Page), PGSIZE), PADDR(pages), PTE_U | PTE_P); boot_map_segment(boot_pml4e, (uintptr_t)pages, ROUNDUP(npages *sizeof(struct Page), PGSIZE), PADDR(pages), PTE_P | PTE_W); boot_map_segment(boot_pml4e, UENVS, ROUNDUP(NENV*sizeof(struct Env), PGSIZE), PADDR(envs), PTE_U | PTE_P); boot_map_segment(boot_pml4e, (uintptr_t)envs, ROUNDUP(NENV *sizeof(struct Env), PGSIZE), PADDR(envs), PTE_P | PTE_W); ////////////////////////////////////////////////////////////////////// // Use the physical memory that 'bootstack' refers to as the kernel // stack. The kernel stack grows down from virtual address KSTACKTOP. // We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP) // to be the kernel stack, but break this into two pieces: // * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory // * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if // the kernel overflows its stack, it will fault rather than // overwrite memory. Known as a "guard page". // Permissions: kernel RW, user NONE // Your code goes here: boot_map_segment(boot_pml4e, KSTACKTOP-KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_P | PTE_W); /////////////////////////////////////////////////////////////////////// // Map all of physical memory at KERNBASE. // Ie. the VA range [KERNBASE, 2^32) should map to // the PA range [0, 2^32 - KERNBASE) // We might not have 2^32 - KERNBASE bytes of physical memory, but // we just set up the mapping anyway. // Permissions: kernel RW, user NONE // Your code goes here: boot_map_segment(boot_pml4e, KERNBASE, ~(uint32_t)0 - KERNBASE + 1, 0, PTE_P | PTE_W); // Check that the initial page directory has been set up correctly. // Initialize the SMP-related parts of the memory map mem_init_mp(); check_boot_pml4e(boot_pml4e); ////////////////////////////////////////////////////////////////////// // Permissions: kernel RW, user NONE pdpe_t *pdpe = KADDR(PTE_ADDR(pml4e[0])); pde_t *pgdir = KADDR(PTE_ADDR(pdpe[3])); lcr3(boot_cr3); check_page_free_list(0); }