SMP Booting, APIC, and IRQs
[akaros.git] / kern / init.c
1 /* See COPYRIGHT for copyright information. */
2
3 #ifdef __DEPUTY__
4 #pragma nodeputy
5 #endif
6
7 #include <inc/stdio.h>
8 #include <inc/string.h>
9 #include <inc/assert.h>
10 #include <inc/multiboot.h>
11 #include <inc/stab.h>
12 #include <inc/x86.h>
13
14 #include <kern/monitor.h>
15 #include <kern/console.h>
16 #include <kern/pmap.h>
17 #include <kern/kclock.h>
18 #include <kern/env.h>
19 #include <kern/trap.h>
20 #include <kern/apic.h>
21
22 volatile bool waiting = 1;
23 volatile uint8_t num_cpus = 0xee;
24 uintptr_t smp_stack_top;
25 volatile bool smp_boot_lock = 0;
26
27 static void print_cpuinfo(void);
28 void smp_boot(void);
29
30 void kernel_init(multiboot_info_t *mboot_info)
31 {
32         extern char (BND(__this, end) edata)[], (SNT end)[];
33
34         // Before doing anything else, complete the ELF loading process.
35         // Clear the uninitialized global data (BSS) section of our program.
36         // This ensures that all static/global variables start out zero.
37         memset(edata, 0, end - edata);
38
39         // Initialize the console.
40         // Can't call cprintf until after we do this!
41         cons_init();
42
43         print_cpuinfo();
44
45         // Lab 2 memory management initialization functions
46         i386_detect_memory();
47         i386_vm_init();
48         page_init();
49         page_check();
50
51         // Lab 3 user environment initialization functions
52         env_init();
53         idt_init();
54
55         // this returns when all other cores are done and ready to receive IPIs
56         smp_boot();
57
58         //ENV_CREATE(user_faultread);
59         //ENV_CREATE(user_faultreadkernel);
60         //ENV_CREATE(user_faultwrite);
61         //ENV_CREATE(user_faultwritekernel);
62         //ENV_CREATE(user_breakpoint);
63         //ENV_CREATE(user_badsegment);
64         //ENV_CREATE(user_divzero);
65         //ENV_CREATE(user_buggyhello);
66         ENV_CREATE(user_hello);
67         //ENV_CREATE(user_evilhello);
68
69         // We only have one user environment for now, so just run it.
70         env_run(&envs[0]);
71 }
72
73 void smp_boot(void)
74 {
75         struct Page* smp_stack;
76         // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
77         // page1 (2nd page) is reserved, hardcoded in pmap.c
78         extern smp_entry(), smp_entry_end();
79         memset(KADDR(0x00001000), 0, PGSIZE);           
80         memcpy(KADDR(0x00001000), &smp_entry, &smp_entry_end - &smp_entry);             
81
82         // This mapping allows access with paging on and off
83         page_insert(boot_pgdir, pa2page(0x00001000), (void*)0x00001000, PTE_W);
84
85         // Allocate a stack for the cores starting up.  One for all, must share
86         if (page_alloc(&smp_stack))
87                 panic("No memory for SMP boot stack!");
88         smp_stack_top = (uintptr_t)(page2kva(smp_stack) + PGSIZE - SIZEOF_STRUCT_TRAPFRAME);
89
90         // set up the local APIC timer to fire 0x21 once.  hardcoded to break
91         // out of the spinloop on waiting.  really just want to wait a little
92         lapic_set_timer(0xffffffff, 0x21, 0);
93         cprintf("Num_Cpus: %d\n", num_cpus);
94         send_init_ipi();
95         asm volatile("sti"); // LAPIC timer will fire, extINTs are blocked at LINT0 now
96         while (waiting); // gets set in the lapic timer
97         send_startup_ipi(0x01);
98         // replace this with something that checks to see if smp_entrys are done
99         while(1); // want other cores to do stuff for now
100         
101         // Remove the mapping of the page used by the trampoline
102         page_remove(boot_pgdir, (void*)0x00001000);
103         // It had a refcount of 2 earlier, so we need to dec once more to free it
104         // TODO - double check that
105         page_decref(pa2page(0x00001000));
106         // Dealloc the temp shared stack
107         page_decref(smp_stack);
108 }
109 /* 
110  * This is called from smp_entry by each core to finish the core bootstrapping.
111  * There is a spinlock around this entire function in smp_entry, for a few reasons,
112  * the most important being that all cores use the same stack when entering here.
113  */
114 void smp_main(void)
115 {
116         cprintf("Good morning Vietnam!\n");
117
118         enable_pse();
119     cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
120     cprintf("This core's Current APIC ID: 0x%08x\n", lapic_get_id());
121         
122         if (read_msr(IA32_APIC_BASE) & 0x00000100)
123                 cprintf("I am the Boot Strap Processor\n");
124         else
125                 cprintf("I am an Application Processor\n");
126         
127         // turn me on!
128         cprintf("Spurious Vector: 0x%08x\n", read_mmreg32(LAPIC_SPURIOUS));
129         cprintf("LINT0: 0x%08x\n", read_mmreg32(LAPIC_LVT_LINT0));
130         cprintf("LINT1: 0x%08x\n", read_mmreg32(LAPIC_LVT_LINT1));
131         cprintf("Num_Cpus: %d\n\n", num_cpus);
132 }
133
134 /*
135  * Variable panicstr contains argument to first call to panic; used as flag
136  * to indicate that the kernel has already called panic.
137  */
138 static const char *NTS panicstr;
139
140 /*
141  * Panic is called on unresolvable fatal errors.
142  * It prints "panic: mesg", and then enters the kernel monitor.
143  */
144 void _panic(const char *file, int line, const char *fmt,...)
145 {
146         va_list ap;
147
148         if (panicstr)
149                 goto dead;
150         panicstr = fmt;
151
152         va_start(ap, fmt);
153         cprintf("kernel panic at %s:%d: ", file, line);
154         vcprintf(fmt, ap);
155         cprintf("\n");
156         va_end(ap);
157
158 dead:
159         /* break into the kernel monitor */
160         while (1)
161                 monitor(NULL);
162 }
163
164 /* like panic, but don't */
165 void _warn(const char *file, int line, const char *fmt,...) 
166 {
167         va_list ap;
168
169         va_start(ap, fmt);
170         cprintf("kernel warning at %s:%d: ", file, line);
171         vcprintf(fmt, ap);
172         cprintf("\n");
173         va_end(ap);
174 }
175
176 static void print_cpuinfo(void) {
177         uint32_t eax, ebx, ecx, edx;
178         uint32_t model, family;
179         uint64_t msr_val;
180         char vendor_id[13];
181
182         asm volatile ("cpuid;"
183                   "movl    %%ebx, (%2);"
184                   "movl    %%edx, 4(%2);"
185                   "movl    %%ecx, 8(%2);"
186                       : "=a"(eax) 
187                                   : "a"(0), "D"(vendor_id)
188                       : "%ebx", "%ecx", "%edx");
189
190         vendor_id[12] = '\0';
191         cprintf("Vendor ID: %s\n", vendor_id);
192         cprintf("Largest Standard Function Number Supported: %d\n", eax);
193         cpuid(0x80000000, &eax, 0, 0, 0);
194         cprintf("Largest Extended Function Number Supported: 0x%08x\n", eax);
195         cpuid(1, &eax, &ebx, &ecx, &edx);
196         family = ((eax & 0x0FF00000) >> 20) + ((eax & 0x00000F00) >> 8);
197         model = ((eax & 0x000F0000) >> 12) + ((eax & 0x000000F0) >> 4);
198         cprintf("Family: %d\n", family);
199         cprintf("Model: %d\n", model);
200         cprintf("Stepping: %d\n", eax & 0x0000000F);
201         // eventually can fill this out with SDM Vol3B App B info, or 
202         // better yet with stepping info.  or cpuid 8000_000{2,3,4}
203         switch ( family << 8 | model ) {
204                 case(0x060f):
205                         cprintf("Processor: Core 2 Duo or Similar\n");
206                         break;
207                 default:
208                         cprintf("Unknown or non-Intel CPU\n");
209         }
210         if (!(edx & 0x00000010))
211                 panic("MSRs not supported!");
212         if (!(edx & 0x00001000))
213                 panic("MTRRs not supported!");
214         if (!(edx & 0x00000100))
215                 panic("Local APIC Not Detected!");
216         if (ecx & 0x00200000)
217                 cprintf("x2APIC Detected\n");
218         else
219                 cprintf("x2APIC Not Detected\n");
220         cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
221         cprintf("Physical Address Bits: %d\n", eax & 0x000000FF);
222         cprintf("Cores per Die: %d\n", (ecx & 0x000000FF) + 1);
223     cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
224         msr_val = read_msr(IA32_APIC_BASE);
225         if (msr_val & MSR_APIC_ENABLE)
226                 cprintf("Local APIC Enabled\n");
227         else
228                 cprintf("Local APIC Disabled\n");
229         if (msr_val & 0x00000100)
230                 cprintf("I am the Boot Strap Processor\n");
231         else
232                 cprintf("I am an Application Processor\n");
233 }