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