155e95b16Srtm #include "types.h" 2558ab49fSrsc #include "defs.h" 355e95b16Srtm #include "param.h" 49aa0337dSFrans Kaashoek #include "memlayout.h" 555e95b16Srtm #include "mmu.h" 655e95b16Srtm #include "proc.h" 755e95b16Srtm #include "x86.h" 855e95b16Srtm 9a4b213cfSFrans Kaashoek static void startothers(void); 10832af025SFrans Kaashoek static void mpmain(void) __attribute__((noreturn)); 11bd71a450SFrans Kaashoek extern pde_t *kpgdir; 12c092540eSRobert Morris extern char end[]; // first address after kernel loaded from ELF file 139aa0337dSFrans Kaashoek 148e1d1ec9Skaashoek // Bootstrap processor starts running C code here. 15faad047aSRobert Morris // Allocate a real stack and switch to it, first 16faad047aSRobert Morris // doing some setup required for memory allocator to work. 1719b42cc0Srsc int 1819b42cc0Srsc main(void) 1955e95b16Srtm { 20c092540eSRobert Morris kinit1(end, P2V(4*1024*1024)); // phys page allocator 2166ba8079SFrans Kaashoek kvmalloc(); // kernel page table 22c779cc2bSRobert Morris mpinit(); // detect other processors 23c779cc2bSRobert Morris lapicinit(); // interrupt controller 24c779cc2bSRobert Morris seginit(); // segment descriptors 2548755214SRuss Cox cprintf("\ncpu%d: starting xv6\n\n", cpu->id); 26c779cc2bSRobert Morris picinit(); // another interrupt controller 27faad047aSRobert Morris ioapicinit(); // another interrupt controller 28c779cc2bSRobert Morris consoleinit(); // console hardware 29faad047aSRobert Morris uartinit(); // serial port 3019333efbSrsc pinit(); // process table 31b61c2547Srtm tvinit(); // trap vectors 3219333efbSrsc binit(); // buffer cache 33eaea18cbSrsc fileinit(); // file table 3421575761Srsc ideinit(); // disk 35b63bb0fdSrsc if(!ismp) 3621575761Srsc timerinit(); // uniprocessor timer 37c092540eSRobert Morris startothers(); // start other processors 38c092540eSRobert Morris kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() 39c092540eSRobert Morris userinit(); // first user process 40c779cc2bSRobert Morris mpmain(); // finish this processor's setup 4155e95b16Srtm } 42df5cc916Srtm 43c60a3551SFrans Kaashoek // Other CPUs jump here from entryother.S. 44c1b100e9Srsc static void 45a4b213cfSFrans Kaashoek mpenter(void) 469aa0337dSFrans Kaashoek { 47bd71a450SFrans Kaashoek switchkvm(); 489aa0337dSFrans Kaashoek seginit(); 4970c55557SFrans Kaashoek lapicinit(); 509aa0337dSFrans Kaashoek mpmain(); 519aa0337dSFrans Kaashoek } 529aa0337dSFrans Kaashoek 539aa0337dSFrans Kaashoek // Common CPU setup code. 549aa0337dSFrans Kaashoek static void 55b74f4b57Srsc mpmain(void) 56b74f4b57Srsc { 572cf6b32dSRobert Morris cprintf("cpu%d: starting\n", cpu->id); 581afc9d3fSRobert Morris idtinit(); // load idt register 59a4b213cfSFrans Kaashoek xchg(&cpu->started, 1); // tell startothers() we're up 601afc9d3fSRobert Morris scheduler(); // start running processes 61b74f4b57Srsc } 62b74f4b57Srsc 635e083578SRobert Morris pde_t entrypgdir[]; // For entry.S 64bd71a450SFrans Kaashoek 65a4b213cfSFrans Kaashoek // Start the non-boot (AP) processors. 669e82bfb0Srsc static void 67a4b213cfSFrans Kaashoek startothers(void) 6899b11b6cSrsc { 69c60a3551SFrans Kaashoek extern uchar _binary_entryother_start[], _binary_entryother_size[]; 7099b11b6cSrsc uchar *code; 7199b11b6cSrsc struct cpu *c; 72ab08960fSrsc char *stack; 7399b11b6cSrsc 74a4b213cfSFrans Kaashoek // Write entry code to unused memory at 0x7000. 75c60a3551SFrans Kaashoek // The linker has placed the image of entryother.S in 76c60a3551SFrans Kaashoek // _binary_entryother_start. 77*a7c03bd9SRobert Morris code = P2V(0x7000); 78c60a3551SFrans Kaashoek memmove(code, _binary_entryother_start, (uint)_binary_entryother_size); 791afc9d3fSRobert Morris 8099b11b6cSrsc for(c = cpus; c < cpus+ncpu; c++){ 8148755214SRuss Cox if(c == cpus+cpunum()) // We've started already. 8299b11b6cSrsc continue; 8399b11b6cSrsc 84e25b74caSFrans Kaashoek // Tell entryother.S what stack to use, where to enter, and what 85e25b74caSFrans Kaashoek // pgdir to use. We cannot use kpgdir yet, because the AP processor 86e25b74caSFrans Kaashoek // is running in low memory, so we use entrypgdir for the APs too. 87c092540eSRobert Morris stack = kalloc(); 88ab08960fSrsc *(void**)(code-4) = stack + KSTACKSIZE; 89a4b213cfSFrans Kaashoek *(void**)(code-8) = mpenter; 90*a7c03bd9SRobert Morris *(int**)(code-12) = (void *) V2P(entrypgdir); 91faad047aSRobert Morris 92*a7c03bd9SRobert Morris lapicstartap(c->id, V2P(code)); 9399b11b6cSrsc 94bd71a450SFrans Kaashoek // wait for cpu to finish mpmain() 95a4b213cfSFrans Kaashoek while(c->started == 0) 9699b11b6cSrsc ; 9799b11b6cSrsc } 9899b11b6cSrsc } 99cf4b1ad9SRuss Cox 1003431cd49SRobert Morris // The boot page table used in entry.S and entryother.S. 1013431cd49SRobert Morris // Page directories (and page tables) must start on page boundaries, 1023431cd49SRobert Morris // hence the __aligned__ attribute. 1033431cd49SRobert Morris // PTE_PS in a page directory entry enables 4Mbyte pages. 1043431cd49SRobert Morris 10566ba8079SFrans Kaashoek __attribute__((__aligned__(PGSIZE))) 1065e083578SRobert Morris pde_t entrypgdir[NPDENTRIES] = { 10766ba8079SFrans Kaashoek // Map VA's [0, 4MB) to PA's [0, 4MB) 1081e6f0146SAustin Clements [0] = (0) | PTE_P | PTE_W | PTE_PS, 10966ba8079SFrans Kaashoek // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) 1101e6f0146SAustin Clements [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, 11166ba8079SFrans Kaashoek }; 11266ba8079SFrans Kaashoek 113cf4b1ad9SRuss Cox //PAGEBREAK! 114cf4b1ad9SRuss Cox // Blank page. 11574c77da6SFrans Kaashoek //PAGEBREAK! 11674c77da6SFrans Kaashoek // Blank page. 11774c77da6SFrans Kaashoek //PAGEBREAK! 11874c77da6SFrans Kaashoek // Blank page. 119