xref: /xv6-public/main.c (revision a7c03bd9)
155e95b16Srtm #include "types.h"
2558ab49fSrsc #include "defs.h"
355e95b16Srtm #include "param.h"
49aa0337dSFrans Kaashoek #include "memlayout.h"
555e95b16Srtm #include "mmu.h"
655e95b16Srtm #include "proc.h"
755e95b16Srtm #include "x86.h"
855e95b16Srtm 
9a4b213cfSFrans Kaashoek static void startothers(void);
10832af025SFrans Kaashoek static void mpmain(void)  __attribute__((noreturn));
11bd71a450SFrans Kaashoek extern pde_t *kpgdir;
12c092540eSRobert Morris extern char end[]; // first address after kernel loaded from ELF file
139aa0337dSFrans Kaashoek 
148e1d1ec9Skaashoek // Bootstrap processor starts running C code here.
15faad047aSRobert Morris // Allocate a real stack and switch to it, first
16faad047aSRobert Morris // doing some setup required for memory allocator to work.
1719b42cc0Srsc int
1819b42cc0Srsc main(void)
1955e95b16Srtm {
20c092540eSRobert Morris   kinit1(end, P2V(4*1024*1024)); // phys page allocator
2166ba8079SFrans Kaashoek   kvmalloc();      // kernel page table
22c779cc2bSRobert Morris   mpinit();        // detect other processors
23c779cc2bSRobert Morris   lapicinit();     // interrupt controller
24c779cc2bSRobert Morris   seginit();       // segment descriptors
2548755214SRuss Cox   cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
26c779cc2bSRobert Morris   picinit();       // another interrupt controller
27faad047aSRobert Morris   ioapicinit();    // another interrupt controller
28c779cc2bSRobert Morris   consoleinit();   // console hardware
29faad047aSRobert Morris   uartinit();      // serial port
3019333efbSrsc   pinit();         // process table
31b61c2547Srtm   tvinit();        // trap vectors
3219333efbSrsc   binit();         // buffer cache
33eaea18cbSrsc   fileinit();      // file table
3421575761Srsc   ideinit();       // disk
35b63bb0fdSrsc   if(!ismp)
3621575761Srsc     timerinit();   // uniprocessor timer
37c092540eSRobert Morris   startothers();   // start other processors
38c092540eSRobert Morris   kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
39c092540eSRobert Morris   userinit();      // first user process
40c779cc2bSRobert Morris   mpmain();        // finish this processor's setup
4155e95b16Srtm }
42df5cc916Srtm 
43c60a3551SFrans Kaashoek // Other CPUs jump here from entryother.S.
44c1b100e9Srsc static void
45a4b213cfSFrans Kaashoek mpenter(void)
469aa0337dSFrans Kaashoek {
47bd71a450SFrans Kaashoek   switchkvm();
489aa0337dSFrans Kaashoek   seginit();
4970c55557SFrans Kaashoek   lapicinit();
509aa0337dSFrans Kaashoek   mpmain();
519aa0337dSFrans Kaashoek }
529aa0337dSFrans Kaashoek 
539aa0337dSFrans Kaashoek // Common CPU setup code.
549aa0337dSFrans Kaashoek static void
55b74f4b57Srsc mpmain(void)
56b74f4b57Srsc {
572cf6b32dSRobert Morris   cprintf("cpu%d: starting\n", cpu->id);
581afc9d3fSRobert Morris   idtinit();       // load idt register
59a4b213cfSFrans Kaashoek   xchg(&cpu->started, 1); // tell startothers() we're up
601afc9d3fSRobert Morris   scheduler();     // start running processes
61b74f4b57Srsc }
62b74f4b57Srsc 
635e083578SRobert Morris pde_t entrypgdir[];  // For entry.S
64bd71a450SFrans Kaashoek 
65a4b213cfSFrans Kaashoek // Start the non-boot (AP) processors.
669e82bfb0Srsc static void
67a4b213cfSFrans Kaashoek startothers(void)
6899b11b6cSrsc {
69c60a3551SFrans Kaashoek   extern uchar _binary_entryother_start[], _binary_entryother_size[];
7099b11b6cSrsc   uchar *code;
7199b11b6cSrsc   struct cpu *c;
72ab08960fSrsc   char *stack;
7399b11b6cSrsc 
74a4b213cfSFrans Kaashoek   // Write entry code to unused memory at 0x7000.
75c60a3551SFrans Kaashoek   // The linker has placed the image of entryother.S in
76c60a3551SFrans Kaashoek   // _binary_entryother_start.
77*a7c03bd9SRobert Morris   code = P2V(0x7000);
78c60a3551SFrans Kaashoek   memmove(code, _binary_entryother_start, (uint)_binary_entryother_size);
791afc9d3fSRobert Morris 
8099b11b6cSrsc   for(c = cpus; c < cpus+ncpu; c++){
8148755214SRuss Cox     if(c == cpus+cpunum())  // We've started already.
8299b11b6cSrsc       continue;
8399b11b6cSrsc 
84e25b74caSFrans Kaashoek     // Tell entryother.S what stack to use, where to enter, and what
85e25b74caSFrans Kaashoek     // pgdir to use. We cannot use kpgdir yet, because the AP processor
86e25b74caSFrans Kaashoek     // is running in low  memory, so we use entrypgdir for the APs too.
87c092540eSRobert Morris     stack = kalloc();
88ab08960fSrsc     *(void**)(code-4) = stack + KSTACKSIZE;
89a4b213cfSFrans Kaashoek     *(void**)(code-8) = mpenter;
90*a7c03bd9SRobert Morris     *(int**)(code-12) = (void *) V2P(entrypgdir);
91faad047aSRobert Morris 
92*a7c03bd9SRobert Morris     lapicstartap(c->id, V2P(code));
9399b11b6cSrsc 
94bd71a450SFrans Kaashoek     // wait for cpu to finish mpmain()
95a4b213cfSFrans Kaashoek     while(c->started == 0)
9699b11b6cSrsc       ;
9799b11b6cSrsc   }
9899b11b6cSrsc }
99cf4b1ad9SRuss Cox 
1003431cd49SRobert Morris // The boot page table used in entry.S and entryother.S.
1013431cd49SRobert Morris // Page directories (and page tables) must start on page boundaries,
1023431cd49SRobert Morris // hence the __aligned__ attribute.
1033431cd49SRobert Morris // PTE_PS in a page directory entry enables 4Mbyte pages.
1043431cd49SRobert Morris 
10566ba8079SFrans Kaashoek __attribute__((__aligned__(PGSIZE)))
1065e083578SRobert Morris pde_t entrypgdir[NPDENTRIES] = {
10766ba8079SFrans Kaashoek   // Map VA's [0, 4MB) to PA's [0, 4MB)
1081e6f0146SAustin Clements   [0] = (0) | PTE_P | PTE_W | PTE_PS,
10966ba8079SFrans Kaashoek   // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
1101e6f0146SAustin Clements   [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS,
11166ba8079SFrans Kaashoek };
11266ba8079SFrans Kaashoek 
113cf4b1ad9SRuss Cox //PAGEBREAK!
114cf4b1ad9SRuss Cox // Blank page.
11574c77da6SFrans Kaashoek //PAGEBREAK!
11674c77da6SFrans Kaashoek // Blank page.
11774c77da6SFrans Kaashoek //PAGEBREAK!
11874c77da6SFrans Kaashoek // Blank page.
119