xref: /xv6-public/main.c (revision 3431cd49)
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
2221575761Srsc   mpinit();        // collect info about this machine
2370c55557SFrans Kaashoek   lapicinit();
24faad047aSRobert Morris   seginit();       // set up segments
2548755214SRuss Cox   cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
26faad047aSRobert Morris   picinit();       // interrupt controller
27faad047aSRobert Morris   ioapicinit();    // another interrupt controller
28faad047aSRobert Morris   consoleinit();   // I/O devices & their interrupts
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
40ab08960fSrsc   // Finish setting up this processor in mpmain.
4147212719Srsc   mpmain();
4255e95b16Srtm }
43df5cc916Srtm 
44c60a3551SFrans Kaashoek // Other CPUs jump here from entryother.S.
45c1b100e9Srsc static void
46a4b213cfSFrans Kaashoek mpenter(void)
479aa0337dSFrans Kaashoek {
48bd71a450SFrans Kaashoek   switchkvm();
499aa0337dSFrans Kaashoek   seginit();
5070c55557SFrans Kaashoek   lapicinit();
519aa0337dSFrans Kaashoek   mpmain();
529aa0337dSFrans Kaashoek }
539aa0337dSFrans Kaashoek 
549aa0337dSFrans Kaashoek // Common CPU setup code.
559aa0337dSFrans Kaashoek static void
56b74f4b57Srsc mpmain(void)
57b74f4b57Srsc {
582cf6b32dSRobert Morris   cprintf("cpu%d: starting\n", cpu->id);
591afc9d3fSRobert Morris   idtinit();       // load idt register
60a4b213cfSFrans Kaashoek   xchg(&cpu->started, 1); // tell startothers() we're up
611afc9d3fSRobert Morris   scheduler();     // start running processes
62b74f4b57Srsc }
63b74f4b57Srsc 
645e083578SRobert Morris pde_t entrypgdir[];  // For entry.S
65bd71a450SFrans Kaashoek 
66a4b213cfSFrans Kaashoek // Start the non-boot (AP) processors.
679e82bfb0Srsc static void
68a4b213cfSFrans Kaashoek startothers(void)
6999b11b6cSrsc {
70c60a3551SFrans Kaashoek   extern uchar _binary_entryother_start[], _binary_entryother_size[];
7199b11b6cSrsc   uchar *code;
7299b11b6cSrsc   struct cpu *c;
73ab08960fSrsc   char *stack;
7499b11b6cSrsc 
75a4b213cfSFrans Kaashoek   // Write entry code to unused memory at 0x7000.
76c60a3551SFrans Kaashoek   // The linker has placed the image of entryother.S in
77c60a3551SFrans Kaashoek   // _binary_entryother_start.
789aa0337dSFrans Kaashoek   code = p2v(0x7000);
79c60a3551SFrans Kaashoek   memmove(code, _binary_entryother_start, (uint)_binary_entryother_size);
801afc9d3fSRobert Morris 
8199b11b6cSrsc   for(c = cpus; c < cpus+ncpu; c++){
8248755214SRuss Cox     if(c == cpus+cpunum())  // We've started already.
8399b11b6cSrsc       continue;
8499b11b6cSrsc 
85e25b74caSFrans Kaashoek     // Tell entryother.S what stack to use, where to enter, and what
86e25b74caSFrans Kaashoek     // pgdir to use. We cannot use kpgdir yet, because the AP processor
87e25b74caSFrans Kaashoek     // is running in low  memory, so we use entrypgdir for the APs too.
88c092540eSRobert Morris     stack = kalloc();
89ab08960fSrsc     *(void**)(code-4) = stack + KSTACKSIZE;
90a4b213cfSFrans Kaashoek     *(void**)(code-8) = mpenter;
915e083578SRobert Morris     *(int**)(code-12) = (void *) v2p(entrypgdir);
92faad047aSRobert Morris 
939aa0337dSFrans Kaashoek     lapicstartap(c->id, v2p(code));
9499b11b6cSrsc 
95bd71a450SFrans Kaashoek     // wait for cpu to finish mpmain()
96a4b213cfSFrans Kaashoek     while(c->started == 0)
9799b11b6cSrsc       ;
9899b11b6cSrsc   }
9999b11b6cSrsc }
100cf4b1ad9SRuss Cox 
101*3431cd49SRobert Morris // The boot page table used in entry.S and entryother.S.
102*3431cd49SRobert Morris // Page directories (and page tables) must start on page boundaries,
103*3431cd49SRobert Morris // hence the __aligned__ attribute.
104*3431cd49SRobert Morris // PTE_PS in a page directory entry enables 4Mbyte pages.
105*3431cd49SRobert Morris 
10666ba8079SFrans Kaashoek __attribute__((__aligned__(PGSIZE)))
1075e083578SRobert Morris pde_t entrypgdir[NPDENTRIES] = {
10866ba8079SFrans Kaashoek   // Map VA's [0, 4MB) to PA's [0, 4MB)
1091e6f0146SAustin Clements   [0] = (0) | PTE_P | PTE_W | PTE_PS,
11066ba8079SFrans Kaashoek   // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
1111e6f0146SAustin Clements   [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS,
11266ba8079SFrans Kaashoek };
11366ba8079SFrans Kaashoek 
114cf4b1ad9SRuss Cox //PAGEBREAK!
115cf4b1ad9SRuss Cox // Blank page.
11674c77da6SFrans Kaashoek //PAGEBREAK!
11774c77da6SFrans Kaashoek // Blank page.
11874c77da6SFrans Kaashoek //PAGEBREAK!
11974c77da6SFrans Kaashoek // Blank page.
120