1 #include "types.h" 2 #include "defs.h" 3 #include "param.h" 4 #include "memlayout.h" 5 #include "mmu.h" 6 #include "proc.h" 7 #include "x86.h" 8 9 static void startothers(void); 10 static void mpmain(void) __attribute__((noreturn)); 11 extern pde_t *kpgdir; 12 extern char end[]; // first address after kernel loaded from ELF file 13 14 // Bootstrap processor starts running C code here. 15 // Allocate a real stack and switch to it, first 16 // doing some setup required for memory allocator to work. 17 int 18 main(void) 19 { 20 kinit1(end, P2V(4*1024*1024)); // phys page allocator 21 kvmalloc(); // kernel page table 22 mpinit(); // detect other processors 23 lapicinit(); // interrupt controller 24 seginit(); // segment descriptors 25 picinit(); // another interrupt controller 26 ioapicinit(); // another interrupt controller 27 consoleinit(); // console hardware 28 uartinit(); // serial port 29 pinit(); // process table 30 tvinit(); // trap vectors 31 binit(); // buffer cache 32 fileinit(); // file table 33 ideinit(); // disk 34 if(!ismp) 35 timerinit(); // uniprocessor timer 36 startothers(); // start other processors 37 kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() 38 userinit(); // first user process 39 mpmain(); // finish this processor's setup 40 } 41 42 // Other CPUs jump here from entryother.S. 43 static void 44 mpenter(void) 45 { 46 switchkvm(); 47 seginit(); 48 lapicinit(); 49 mpmain(); 50 } 51 52 // Common CPU setup code. 53 static void 54 mpmain(void) 55 { 56 cprintf("cpu%d: starting %d\n", cpuid(), cpuid()); 57 idtinit(); // load idt register 58 xchg(&(mycpu()->started), 1); // tell startothers() we're up 59 scheduler(); // start running processes 60 } 61 62 pde_t entrypgdir[]; // For entry.S 63 64 // Start the non-boot (AP) processors. 65 static void 66 startothers(void) 67 { 68 extern uchar _binary_entryother_start[], _binary_entryother_size[]; 69 uchar *code; 70 struct cpu *c; 71 char *stack; 72 73 // Write entry code to unused memory at 0x7000. 74 // The linker has placed the image of entryother.S in 75 // _binary_entryother_start. 76 code = P2V(0x7000); 77 memmove(code, _binary_entryother_start, (uint)_binary_entryother_size); 78 79 for(c = cpus; c < cpus+ncpu; c++){ 80 if(c == mycpu()) // We've started already. 81 continue; 82 83 // Tell entryother.S what stack to use, where to enter, and what 84 // pgdir to use. We cannot use kpgdir yet, because the AP processor 85 // is running in low memory, so we use entrypgdir for the APs too. 86 stack = kalloc(); 87 *(void**)(code-4) = stack + KSTACKSIZE; 88 *(void**)(code-8) = mpenter; 89 *(int**)(code-12) = (void *) V2P(entrypgdir); 90 91 lapicstartap(c->apicid, V2P(code)); 92 93 // wait for cpu to finish mpmain() 94 while(c->started == 0) 95 ; 96 } 97 } 98 99 // The boot page table used in entry.S and entryother.S. 100 // Page directories (and page tables) must start on page boundaries, 101 // hence the __aligned__ attribute. 102 // PTE_PS in a page directory entry enables 4Mbyte pages. 103 104 __attribute__((__aligned__(PGSIZE))) 105 pde_t entrypgdir[NPDENTRIES] = { 106 // Map VA's [0, 4MB) to PA's [0, 4MB) 107 [0] = (0) | PTE_P | PTE_W | PTE_PS, 108 // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) 109 [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, 110 }; 111 112 //PAGEBREAK! 113 // Blank page. 114 //PAGEBREAK! 115