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
main(void)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
254f14d8d1SFrans Kaashoek picinit(); // disable pic
26faad047aSRobert Morris ioapicinit(); // another interrupt controller
27c779cc2bSRobert Morris consoleinit(); // console hardware
28faad047aSRobert Morris uartinit(); // serial port
2919333efbSrsc pinit(); // process table
30b61c2547Srtm tvinit(); // trap vectors
3119333efbSrsc binit(); // buffer cache
32eaea18cbSrsc fileinit(); // file table
3321575761Srsc ideinit(); // disk
34c092540eSRobert Morris startothers(); // start other processors
35c092540eSRobert Morris kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
36c092540eSRobert Morris userinit(); // first user process
37c779cc2bSRobert Morris mpmain(); // finish this processor's setup
3855e95b16Srtm }
39df5cc916Srtm
40c60a3551SFrans Kaashoek // Other CPUs jump here from entryother.S.
41c1b100e9Srsc static void
mpenter(void)42a4b213cfSFrans Kaashoek mpenter(void)
439aa0337dSFrans Kaashoek {
44bd71a450SFrans Kaashoek switchkvm();
459aa0337dSFrans Kaashoek seginit();
4670c55557SFrans Kaashoek lapicinit();
479aa0337dSFrans Kaashoek mpmain();
489aa0337dSFrans Kaashoek }
499aa0337dSFrans Kaashoek
509aa0337dSFrans Kaashoek // Common CPU setup code.
519aa0337dSFrans Kaashoek static void
mpmain(void)52b74f4b57Srsc mpmain(void)
53b74f4b57Srsc {
54ed396c06SFrans Kaashoek cprintf("cpu%d: starting %d\n", cpuid(), cpuid());
551afc9d3fSRobert Morris idtinit(); // load idt register
56abf847a0SFrans Kaashoek xchg(&(mycpu()->started), 1); // tell startothers() we're up
571afc9d3fSRobert Morris scheduler(); // start running processes
58b74f4b57Srsc }
59b74f4b57Srsc
605e083578SRobert Morris pde_t entrypgdir[]; // For entry.S
61bd71a450SFrans Kaashoek
62a4b213cfSFrans Kaashoek // Start the non-boot (AP) processors.
639e82bfb0Srsc static void
startothers(void)64a4b213cfSFrans Kaashoek startothers(void)
6599b11b6cSrsc {
66c60a3551SFrans Kaashoek extern uchar _binary_entryother_start[], _binary_entryother_size[];
6799b11b6cSrsc uchar *code;
6899b11b6cSrsc struct cpu *c;
69ab08960fSrsc char *stack;
7099b11b6cSrsc
71a4b213cfSFrans Kaashoek // Write entry code to unused memory at 0x7000.
72c60a3551SFrans Kaashoek // The linker has placed the image of entryother.S in
73c60a3551SFrans Kaashoek // _binary_entryother_start.
74a7c03bd9SRobert Morris code = P2V(0x7000);
75c60a3551SFrans Kaashoek memmove(code, _binary_entryother_start, (uint)_binary_entryother_size);
761afc9d3fSRobert Morris
7799b11b6cSrsc for(c = cpus; c < cpus+ncpu; c++){
78abf847a0SFrans Kaashoek if(c == mycpu()) // We've started already.
7999b11b6cSrsc continue;
8099b11b6cSrsc
81e25b74caSFrans Kaashoek // Tell entryother.S what stack to use, where to enter, and what
82e25b74caSFrans Kaashoek // pgdir to use. We cannot use kpgdir yet, because the AP processor
83e25b74caSFrans Kaashoek // is running in low memory, so we use entrypgdir for the APs too.
84c092540eSRobert Morris stack = kalloc();
85ab08960fSrsc *(void**)(code-4) = stack + KSTACKSIZE;
86*96e4e2f4SFrans Kaashoek *(void(**)(void))(code-8) = mpenter;
87a7c03bd9SRobert Morris *(int**)(code-12) = (void *) V2P(entrypgdir);
88faad047aSRobert Morris
89ae15515dSFrans Kaashoek lapicstartap(c->apicid, V2P(code));
9099b11b6cSrsc
91bd71a450SFrans Kaashoek // wait for cpu to finish mpmain()
92a4b213cfSFrans Kaashoek while(c->started == 0)
9399b11b6cSrsc ;
9499b11b6cSrsc }
9599b11b6cSrsc }
96cf4b1ad9SRuss Cox
973431cd49SRobert Morris // The boot page table used in entry.S and entryother.S.
983431cd49SRobert Morris // Page directories (and page tables) must start on page boundaries,
993431cd49SRobert Morris // hence the __aligned__ attribute.
1003431cd49SRobert Morris // PTE_PS in a page directory entry enables 4Mbyte pages.
1013431cd49SRobert Morris
10266ba8079SFrans Kaashoek __attribute__((__aligned__(PGSIZE)))
1035e083578SRobert Morris pde_t entrypgdir[NPDENTRIES] = {
10466ba8079SFrans Kaashoek // Map VA's [0, 4MB) to PA's [0, 4MB)
1051e6f0146SAustin Clements [0] = (0) | PTE_P | PTE_W | PTE_PS,
10666ba8079SFrans Kaashoek // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
1071e6f0146SAustin Clements [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS,
10866ba8079SFrans Kaashoek };
10966ba8079SFrans Kaashoek
110cf4b1ad9SRuss Cox //PAGEBREAK!
111cf4b1ad9SRuss Cox // Blank page.
11274c77da6SFrans Kaashoek //PAGEBREAK!
1134638cabfSRobert Morris // Blank page.
1144638cabfSRobert Morris //PAGEBREAK!
1154638cabfSRobert Morris // Blank page.
1164638cabfSRobert Morris
117