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