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
9static void startothers(void);
10static void mpmain(void) __attribute__((noreturn));
11extern pde_t *kpgdir;
12extern 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.
17int
18main(void)
19{
20 kinit1(end, P2V(4*1024*1024)); // phys page allocator
21 kvmalloc(); // kernel page table
22 mpinit(); // detect other processors
23 lapicinit(); // interrupt controller
24 seginit(); // segment descriptors
25 picinit(); // disable pic
26 ioapicinit(); // another interrupt controller
27 consoleinit(); // console hardware
28 uartinit(); // serial port
29 pinit(); // process table
30 tvinit(); // trap vectors
31 binit(); // buffer cache
32 fileinit(); // file table
33 ideinit(); // disk
34 startothers(); // start other processors
35 kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
36 userinit(); // first user process
37 mpmain(); // finish this processor's setup
38}
39
40// Other CPUs jump here from entryother.S.
41static void
42mpenter(void)
43{
44 switchkvm();
45 seginit();
46 lapicinit();
47 mpmain();
48}
49
50// Common CPU setup code.
51static void
52mpmain(void)
53{
54 cprintf("cpu%d: starting %d\n", cpuid(), cpuid());
55 idtinit(); // load idt register
56 xchg(&(mycpu()->started), 1); // tell startothers() we're up
57 scheduler(); // start running processes
58}
59
60pde_t entrypgdir[]; // For entry.S
61
62// Start the non-boot (AP) processors.
63static void
64startothers(void)
65{
66 extern uchar _binary_entryother_start[], _binary_entryother_size[];
67 uchar *code;
68 struct cpu *c;
69 char *stack;
70
71 // Write entry code to unused memory at 0x7000.
72 // The linker has placed the image of entryother.S in
73 // _binary_entryother_start.
74 code = P2V(0x7000);
75 memmove(code, _binary_entryother_start, (uint)_binary_entryother_size);
76
77 for(c = cpus; c < cpus+ncpu; c++){
78 if(c == mycpu()) // We've started already.
79 continue;
80
81 // Tell entryother.S what stack to use, where to enter, and what
82 // pgdir to use. We cannot use kpgdir yet, because the AP processor
83 // is running in low memory, so we use entrypgdir for the APs too.
84 stack = kalloc();
85 *(void**)(code-4) = stack + KSTACKSIZE;
86 *(void(**)(void))(code-8) = mpenter;
87 *(int**)(code-12) = (void *) V2P(entrypgdir);
88
89 lapicstartap(c->apicid, V2P(code));
90
91 // wait for cpu to finish mpmain()
92 while(c->started == 0)
93 ;
94 }
95}
96
97// The boot page table used in entry.S and entryother.S.
98// Page directories (and page tables) must start on page boundaries,
99// hence the __aligned__ attribute.
100// PTE_PS in a page directory entry enables 4Mbyte pages.
101
102__attribute__((__aligned__(PGSIZE)))
103pde_t entrypgdir[NPDENTRIES] = {
104 // Map VA's [0, 4MB) to PA's [0, 4MB)
105 [0] = (0) | PTE_P | PTE_W | PTE_PS,
106 // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
107 [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS,
108};
109
110//PAGEBREAK!
111// Blank page.
112//PAGEBREAK!
113// Blank page.
114//PAGEBREAK!
115// Blank page.
116
117