void i386_init(void) { extern char edata[], end[]; // Before doing anything else, complete the ELF loading process. // Clear the uninitialized global data (BSS) section of our program. // This ensures that all static/global variables start out zero. memset(edata, 0, end - edata); // Initialize the console. // Can't call cprintf until after we do this! cons_init(); cprintf("6828 decimal is %o octal!\n", 6828); //check page_alloc() this is a test,not my code check_page_alloc(); // Test the stack backtrace function (lab 1 only) test_backtrace(5); // Drop into the kernel monitor. while (1) monitor(NULL); }
// 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(); }
// 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); }
// 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(); }