Moved some functions into kern/testing
[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 #include <inc/atomic.h>
14
15 #include <kern/monitor.h>
16 #include <kern/console.h>
17 #include <kern/pmap.h>
18 #include <kern/kclock.h>
19 #include <kern/env.h>
20 #include <kern/trap.h>
21 #include <kern/apic.h>
22 #include <kern/testing.h>
23
24 volatile uint32_t waiting = 1;
25 volatile uint8_t num_cpus = 0xee;
26 uintptr_t smp_stack_top;
27 volatile uint32_t smp_boot_lock = 0;
28
29 static void print_cpuinfo(void);
30 void smp_boot(void);
31 static void smp_boot_handler(struct Trapframe *tf);
32
33 void kernel_init(multiboot_info_t *mboot_info)
34 {
35         extern char (BND(__this, end) edata)[], (SNT end)[];
36
37         // Before doing anything else, complete the ELF loading process.
38         // Clear the uninitialized global data (BSS) section of our program.
39         // This ensures that all static/global variables start out zero.
40         memset(edata, 0, end - edata);
41
42         // Initialize the console.
43         // Can't call cprintf until after we do this!
44         cons_init();
45
46         print_cpuinfo();
47
48         i386_detect_memory();
49         i386_vm_init();
50         page_init();
51         page_check();
52
53         env_init();
54         idt_init();
55
56         // this returns when all other cores are done and ready to receive IPIs
57         smp_boot();
58
59         //ENV_CREATE(user_faultread);
60         //ENV_CREATE(user_faultreadkernel);
61         //ENV_CREATE(user_faultwrite);
62         //ENV_CREATE(user_faultwritekernel);
63         //ENV_CREATE(user_breakpoint);
64         //ENV_CREATE(user_badsegment);
65         //ENV_CREATE(user_divzero);
66         //ENV_CREATE(user_buggyhello);
67         ENV_CREATE(user_hello);
68         //ENV_CREATE(user_evilhello);
69
70         // We only have one user environment for now, so just run it.
71         env_run(&envs[0]);
72 }
73
74 void smp_boot(void)
75 {
76         struct Page* smp_stack;
77         extern isr_t interrupt_handlers[];
78         // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
79         // page1 (2nd page) is reserved, hardcoded in pmap.c
80         extern smp_entry(), smp_entry_end();
81         memset(KADDR(0x00001000), 0, PGSIZE);           
82         memcpy(KADDR(0x00001000), &smp_entry, &smp_entry_end - &smp_entry);             
83
84         // This mapping allows access with paging on and off
85         page_insert(boot_pgdir, pa2page(0x00001000), (void*)0x00001000, PTE_W);
86
87         // Allocate a stack for the cores starting up.  One for all, must share
88         if (page_alloc(&smp_stack))
89                 panic("No memory for SMP boot stack!");
90         smp_stack_top = (uintptr_t)(page2kva(smp_stack) + PGSIZE);
91
92         // set up the local APIC timer to fire 0xf0 once.  hardcoded to break
93         // out of the spinloop on waiting.  really just want to wait a little
94         lapic_set_timer(0x0000ffff, 0xf0, 0);
95         // set the function handler to respond to this
96         register_interrupt_handler(interrupt_handlers, 0xf0, smp_boot_handler);
97         // Start the IPI process (INIT, wait, SIPI)
98         send_init_ipi();
99         enable_interrupts(); // LAPIC timer will fire, extINTs are blocked at LINT0 now
100         while (waiting); // gets released in smp_boot_handler
101
102         // Since we don't know how many CPUs are out there (need to parse tables)
103         // we'll wait for a little bit, using the timer as above.  each core will
104         // also increment waiting, and decrement when it is done, all in smp_entry.
105         // core0 uses the timer for its decrement to signal "waiting a while".  
106         // Replace this shit when we parse the ACPI/MP tables (TODO)
107         waiting = 1;
108         send_startup_ipi(0x01); // can also send another one if all don't report in
109         // If this timer isn't long enough, then we could beat an AP past the
110         // waiting loop and compete for the lock.
111         lapic_set_timer(0x00ffffff, 0xf0, 0);
112         while(waiting); // want other cores to do stuff for now
113         // From here on, no other cores are coming up.  Grab the lock to ensure it.
114         spin_lock(&smp_boot_lock);
115         cprintf("Num_Cpus Detected: %d\n", num_cpus);
116
117         // Deregister smp_boot_handler
118         register_interrupt_handler(interrupt_handlers, 0xf0, 0);
119         // Remove the mapping of the page used by the trampoline
120         page_remove(boot_pgdir, (void*)0x00001000);
121         // It had a refcount of 2 earlier, so we need to dec once more to free it
122         page_decref(pa2page(0x00001000));
123         // Dealloc the temp shared stack
124         page_decref(smp_stack);
125
126         // Should probably flush everyone's TLB at this point, to get rid of 
127         // temp mappings that were removed.  TODO
128 }
129
130 /* Breaks us out of the waiting loop in smp_boot */
131 void smp_boot_handler(struct Trapframe *tf)
132 {
133         extern volatile uint32_t waiting;
134         {HANDLER_ATOMIC atomic_dec(&waiting); }
135 }
136
137 /* 
138  * This is called from smp_entry by each core to finish the core bootstrapping.
139  * There is a spinlock around this entire function in smp_entry, for a few reasons,
140  * the most important being that all cores use the same stack when entering here.
141  */
142 uint32_t smp_main(void)
143 {
144         /*
145         // Print some diagnostics.  Uncomment if there're issues.
146         cprintf("Good morning Vietnam!\n");
147         cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
148         cprintf("This core's Current APIC ID: 0x%08x\n", lapic_get_id());
149         if (read_msr(IA32_APIC_BASE) & 0x00000100)
150                 cprintf("I am the Boot Strap Processor\n");
151         else
152                 cprintf("I am an Application Processor\n");
153         cprintf("Num_Cpus: %d\n\n", num_cpus);
154         */
155         
156         // Get a per-core kernel stack
157         struct Page* my_stack;
158         if (page_alloc(&my_stack))
159                 panic("Unable to alloc a per-core stack!");
160         memset(page2kva(my_stack), 0, PGSIZE);
161
162         // Set up a gdt / gdt_pd for this core, stored at the top of the stack
163         // This is necessary, eagle-eyed readers know why
164         // GDT should be 4-byte aligned.  TS isn't aligned.  Not sure if it matters.
165         struct Pseudodesc* my_gdt_pd = page2kva(my_stack) + PGSIZE - 
166                 sizeof(struct Pseudodesc) - sizeof(struct Segdesc)*SEG_COUNT;
167         struct Segdesc* my_gdt = page2kva(my_stack) + PGSIZE - 
168                 sizeof(struct Segdesc)*SEG_COUNT;
169         // TS also needs to be permanent
170         struct Taskstate* my_ts = page2kva(my_stack) + PGSIZE - 
171                 sizeof(struct Pseudodesc) - sizeof(struct Segdesc)*SEG_COUNT - 
172                 sizeof(struct Taskstate);
173         // Usable portion of the KSTACK grows down from here
174         // Won't actually start using this stack til our first interrupt
175         // (issues with changing the stack pointer and then trying to "return")
176         uintptr_t my_stack_top = (uintptr_t)my_ts;
177
178         // Build and load the gdt / gdt_pd
179         memcpy(my_gdt, gdt, sizeof(struct Segdesc)*SEG_COUNT);
180         *my_gdt_pd = (struct Pseudodesc) { 
181                 sizeof(struct Segdesc)*SEG_COUNT - 1, (uintptr_t) my_gdt };
182         asm volatile("lgdt %0" : : "m"(*my_gdt_pd));
183
184         // Need to set the TSS so we know where to trap on this core
185         my_ts->ts_esp0 = my_stack_top;
186         my_ts->ts_ss0 = GD_KD;
187         // Initialize the TSS field of my_gdt.
188         my_gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (my_ts), sizeof(struct Taskstate), 0);
189         my_gdt[GD_TSS >> 3].sd_s = 0;
190         // Load the TSS
191         ltr(GD_TSS);
192
193         // Loads the same IDT used by the other cores
194         asm volatile("lidt idt_pd");
195
196         // APIC setup
197         lapic_enable();
198         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
199         write_mmreg32(LAPIC_LVT_LINT0, 0x700); 
200         // mask it to shut it up for now.  Doesn't seem to matter yet, since both
201         // KVM and Bochs seem to only route the PIC to core0.
202         mask_lapic_lvt(LAPIC_LVT_LINT0);
203
204         // set a default logical id for now
205         lapic_set_logid(lapic_get_id());
206
207         return my_stack_top; // will be loaded in smp_entry.S
208 }
209
210 /*
211  * Variable panicstr contains argument to first call to panic; used as flag
212  * to indicate that the kernel has already called panic.
213  */
214 static const char *NTS panicstr;
215
216 /*
217  * Panic is called on unresolvable fatal errors.
218  * It prints "panic: mesg", and then enters the kernel monitor.
219  */
220 void _panic(const char *file, int line, const char *fmt,...)
221 {
222         va_list ap;
223
224         if (panicstr)
225                 goto dead;
226         panicstr = fmt;
227
228         va_start(ap, fmt);
229         cprintf("kernel panic at %s:%d: ", file, line);
230         vcprintf(fmt, ap);
231         cprintf("\n");
232         va_end(ap);
233
234 dead:
235         /* break into the kernel monitor */
236         while (1)
237                 monitor(NULL);
238 }
239
240 /* like panic, but don't */
241 void _warn(const char *file, int line, const char *fmt,...) 
242 {
243         va_list ap;
244
245         va_start(ap, fmt);
246         cprintf("kernel warning at %s:%d: ", file, line);
247         vcprintf(fmt, ap);
248         cprintf("\n");
249         va_end(ap);
250 }
251
252 static void print_cpuinfo(void) {
253         uint32_t eax, ebx, ecx, edx;
254         uint32_t model, family;
255         uint64_t msr_val;
256         char vendor_id[13];
257
258         asm volatile ("cpuid;"
259                   "movl    %%ebx, (%2);"
260                   "movl    %%edx, 4(%2);"
261                   "movl    %%ecx, 8(%2);"
262                       : "=a"(eax) 
263                                   : "a"(0), "D"(vendor_id)
264                       : "%ebx", "%ecx", "%edx");
265
266         vendor_id[12] = '\0';
267         cprintf("Vendor ID: %s\n", vendor_id);
268         cprintf("Largest Standard Function Number Supported: %d\n", eax);
269         cpuid(0x80000000, &eax, 0, 0, 0);
270         cprintf("Largest Extended Function Number Supported: 0x%08x\n", eax);
271         cpuid(1, &eax, &ebx, &ecx, &edx);
272         family = ((eax & 0x0FF00000) >> 20) + ((eax & 0x00000F00) >> 8);
273         model = ((eax & 0x000F0000) >> 12) + ((eax & 0x000000F0) >> 4);
274         cprintf("Family: %d\n", family);
275         cprintf("Model: %d\n", model);
276         cprintf("Stepping: %d\n", eax & 0x0000000F);
277         // eventually can fill this out with SDM Vol3B App B info, or 
278         // better yet with stepping info.  or cpuid 8000_000{2,3,4}
279         switch ( family << 8 | model ) {
280                 case(0x060f):
281                         cprintf("Processor: Core 2 Duo or Similar\n");
282                         break;
283                 default:
284                         cprintf("Unknown or non-Intel CPU\n");
285         }
286         if (!(edx & 0x00000010))
287                 panic("MSRs not supported!");
288         if (!(edx & 0x00001000))
289                 panic("MTRRs not supported!");
290         if (!(edx & 0x00000100))
291                 panic("Local APIC Not Detected!");
292         if (ecx & 0x00200000)
293                 cprintf("x2APIC Detected\n");
294         else
295                 cprintf("x2APIC Not Detected\n");
296         cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
297         cprintf("Physical Address Bits: %d\n", eax & 0x000000FF);
298         cprintf("Cores per Die: %d\n", (ecx & 0x000000FF) + 1);
299     cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
300         msr_val = read_msr(IA32_APIC_BASE);
301         if (msr_val & MSR_APIC_ENABLE)
302                 cprintf("Local APIC Enabled\n");
303         else
304                 cprintf("Local APIC Disabled\n");
305         if (msr_val & 0x00000100)
306                 cprintf("I am the Boot Strap Processor\n");
307         else
308                 cprintf("I am an Application Processor\n");
309 }