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