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