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); // Lab 2 memory management initialization functions i386_detect_memory(); i386_vm_init(); page_init(); page_check(); // Drop into the kernel monitor. while (1) monitor(NULL); }
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("\n*** Welcome to Jake, The Java Kernel! ***"); cprintf("\nCopyright (C) 2011. Enterprise Java Systems.\n\n"); /* test the stack backtrace function */ test_backtrace(5); /* memory setup */ i386_detect_memory(); i386_vm_init(); /* drop into the kernel monitor */ while (1) monitor(NULL); }
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); // Lab 2 memory management initialization functions i386_detect_memory(); i386_vm_init(); page_init(); page_check(); // Lab 3 user environment initialization functions env_init(); idt_init(); // Lab 4 multitasking initialization functions pic_init(); kclock_init(); // Should always have an idle process as first one. ENV_CREATE(user_idle); // Start fs. ENV_CREATE(fs_fs); ENV_CREATE(user_icode); #if defined(TEST) // Don't touch -- used by grading script! ENV_CREATE2(TEST, TESTSIZE) #else // Touch all you want. // ENV_CREATE(user_icode); // ENV_CREATE(user_pipereadeof); // ENV_CREATE(user_pipewriteeof); // ENV_CREATE(user_testpipe); // ENV_CREATE(user_primespipe); // ENV_CREATE(user_testpiperace); // ENV_CREATE(user_testpiperace2); // ENV_CREATE(user_testfdsharing); #endif // TEST* // Should not be necessary - drain keyboard because interrupt has given up. kbd_intr(); // Schedule and run the first user environment! sched_yield(); }
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); // Lab 2 memory management initialization functions i386_detect_memory(); i386_vm_init(); // Lab 3 user environment initialization functions env_init(); idt_init(); // Lab 4 multitasking initialization functions pic_init(); kclock_init(); time_init(); pci_init(); // Should always have an idle process as first one. ENV_CREATE(user_idle); // Start fs. ENV_CREATE(fs_fs); #if !defined(TEST_NO_NS) // Start ns. ENV_CREATE(net_ns); #endif #if defined(TEST) // Don't touch -- used by grading script! ENV_CREATE2(TEST, TESTSIZE); #else // Touch all you want. // ENV_CREATE(net_testoutput); // ENV_CREATE(user_echosrv); // ENV_CREATE(user_httpd); // ENV_CREATE(user_writemotd); // ENV_CREATE(user_testfile); ENV_CREATE(user_icode); // ENV_CREATE(user_primes); #endif // TEST* // Schedule and run the first user environment! sched_yield(); }
// 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(); }
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(); #if defined(LAB1_ONLY) cprintf("6828 decimal is %o octal!\n", 6828); /* ----- Exercise 8 of Lab 1 -----*/ int x=1,y=3,z=4; cprintf("x %d, y %x, z %d\n", x, y, z); unsigned int i = 0x00646c72; cprintf("H%x Wo%s\n", 57616, &i); // Shows He110 World, while the demical 0d57616 = 0xe110 // 'r' = 0x72, 'l' = 0x6c, 'd' = 0x64, '\0' = 0x00 which indicates the end of the string // If the x86 is big-endian, 57616 -> 4321, 0x00646c72 -> 0x726c6400 // Test the stack backtrace function (lab 1 only) test_backtrace(5); #endif // Lab 2 memory management initialization functions i386_detect_memory(); i386_vm_init(); // Lab 3 user environment initialization functions env_init(); idt_init(); // Lab 4 multitasking initialization functions pic_init(); kclock_init(); time_init(); pci_init(); // Should always have an idle process as first one. ENV_CREATE(user_idle); // 0 // Start fs ENV_CREATE(fs_fs); // 1 // Start ns. ENV_CREATE(net_ns); // 2 // Start init #if defined(TEST) // Don't touch -- used by grading script! ENV_CREATE2(TEST, TESTSIZE); #else // Touch all you want. // ENV_CREATE(user_echosrv); // ENV_CREATE(user_httpd); // ENV_CREATE(user_testtime); #endif // TEST* // Schedule and run the first user environment! sched_yield(); }
// 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); }
void i386_init(uint32_t memsize) { extern char etext[],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. /* * From http://en.wikipedia.org/wiki/.bss * In computer programming * .bss or bss (Block Started by Symbol) is used by many compilers and linkers * as the name of the data segment containing static variables * that are filled solely with zero-valued data initially * (i. e., when execution begins). * It is often referred to as the "bss section" or "bss segment". * The program loader initializes the memory allocated for the bss section * when it loads the program. */ 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); cprintf("etext:%08x,edata:%08x,end:%08x\n",etext,edata,end); // Lab 2 memory management initialization functions i386_detect_memory(memsize); i386_vm_init(); // Lab 3 user environment initialization functions env_init(); idt_init(); // Lab 4 multitasking initialization functions pic_init(); kclock_init(); // Should always have an idle process as first one. ENV_CREATE(user_idle); // Start fs. ENV_CREATE(fs_fs); // Start init #if defined(TEST) // Don't touch -- used by grading script! ENV_CREATE2(TEST, TESTSIZE); #else // Touch all you want. ENV_CREATE(user_fairness); //ENV_CREATE(user_pipereadeof); // ENV_CREATE(user_pipewriteeof); #endif // Should not be necessary - drain keyboard because interrupt has given up. kbd_intr(); //while(login() != 0) // continue; // Schedule and run the first user environment! sched_yield(); }
// 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(); }