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 13 // Bootstrap processor starts running C code here. 14 // Allocate a real stack and switch to it, first 15 // doing some setup required for memory allocator to work. 16 int 17 main(void) 18 { 19 kvmalloc(); // kernel page table 20 mpinit(); // collect info about this machine 21 lapicinit(mpbcpu()); 22 seginit(); // set up segments 23 cprintf("\ncpu%d: starting xv6\n\n", cpu->id); 24 picinit(); // interrupt controller 25 ioapicinit(); // another interrupt controller 26 consoleinit(); // I/O devices & their interrupts 27 uartinit(); // serial port 28 pinit(); // process table 29 tvinit(); // trap vectors 30 binit(); // buffer cache 31 fileinit(); // file table 32 iinit(); // inode cache 33 ideinit(); // disk 34 if(!ismp) 35 timerinit(); // uniprocessor timer 36 startothers(); // start other processors (must come before kinit; must use enter_alloc) 37 kinit(); // initialize memory allocator 38 userinit(); // first user process (must come after kinit) 39 // Finish setting up this processor in mpmain. 40 mpmain(); 41 } 42 43 // Other CPUs jump here from entryother.S. 44 static void 45 mpenter(void) 46 { 47 switchkvm(); 48 seginit(); 49 lapicinit(cpunum()); 50 mpmain(); 51 } 52 53 // Common CPU setup code. 54 static void 55 mpmain(void) 56 { 57 cprintf("cpu%d: starting\n", cpu->id); 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 enterpgdir[]; // 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, the address of mpenter and pgdir; 85 // We cannot use kpgdir yet, because the AP processor is running in low 86 // memory, so we use enterpgdir for the APs too. kalloc can return addresses 87 // above 4Mbyte (the machine may have much more physical memory than 4Mbyte), which 88 // aren't mapped by enterpgdir, so we must allocate a stack using enter_alloc(); 89 // This introduces the constraint that xv6 cannot use kalloc until after these 90 // last enter_alloc invocations. 91 stack = enter_alloc(); 92 *(void**)(code-4) = stack + KSTACKSIZE; 93 *(void**)(code-8) = mpenter; 94 *(int**)(code-12) = (void *) v2p(enterpgdir); 95 96 lapicstartap(c->id, v2p(code)); 97 98 // wait for cpu to finish mpmain() 99 while(c->started == 0) 100 ; 101 } 102 } 103 104 // Boot page table used in entry.S and entryother.S. 105 // Page directories (and page tables), must start on a page boundary, 106 // hence the "__aligned__" attribute. 107 // Use PTE_PS in page directory entry to enable 4Mbyte pages. 108 __attribute__((__aligned__(PGSIZE))) 109 pde_t enterpgdir[NPDENTRIES] = { 110 // Map VA's [0, 4MB) to PA's [0, 4MB) 111 [0] = (0) + PTE_P + PTE_W + PTE_PS, 112 // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) 113 [KERNBASE>>PDXSHIFT] = (0) + PTE_P + PTE_W + PTE_PS, 114 }; 115 116 //PAGEBREAK! 117 // Blank page. 118 119