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