f58e7c0b8e5cca2dd403696c48bf6b010ff17913
[akaros.git] / kern / arch / x86 / smp_boot.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  */
6
7 #include <arch/x86.h>
8 #include <arch/arch.h>
9 #include <smp.h>
10 #include <arch/console.h>
11 #include <arch/apic.h>
12 #include <arch/perfmon.h>
13 #include <time.h>
14
15 #include <bitmask.h>
16 #include <atomic.h>
17 #include <error.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <assert.h>
21 #include <pmap.h>
22 #include <env.h>
23 #include <trap.h>
24 #include <kmalloc.h>
25 #include <cpu_feat.h>
26 #include <arch/fsgsbase.h>
27
28 #include "vmm/vmm.h"
29
30 extern handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
31 int x86_num_cores_booted = 1;
32 uintptr_t smp_stack_top;
33 barrier_t generic_barrier;
34
35 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
36         INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CORES);
37
38 #define INIT_HANDLER_WRAPPER(v)                                     \
39 {                                                                   \
40         handler_wrappers[(v)].vector = 0xe##v;                          \
41         handler_wrappers[(v)].cpu_list = &f##v##_cpu_list;              \
42         handler_wrappers[(v)].cpu_list->mask.size = num_cores;          \
43 }
44
45 DECLARE_HANDLER_CHECKLISTS(0);
46 DECLARE_HANDLER_CHECKLISTS(1);
47 DECLARE_HANDLER_CHECKLISTS(2);
48 DECLARE_HANDLER_CHECKLISTS(3);
49 DECLARE_HANDLER_CHECKLISTS(4);
50
51 static void init_smp_call_function(void)
52 {
53         INIT_HANDLER_WRAPPER(0);
54         INIT_HANDLER_WRAPPER(1);
55         INIT_HANDLER_WRAPPER(2);
56         INIT_HANDLER_WRAPPER(3);
57         INIT_HANDLER_WRAPPER(4);
58 }
59
60 /******************************************************************************/
61
62 bool core_id_ready = FALSE;
63
64 static void setup_rdtscp(int coreid)
65 {
66         uint32_t edx;
67         int rdtscp_ecx;
68         /* TODO: have some sort of 'cpu info structure' with flags */
69         cpuid(0x80000001, 0x0, 0, 0, 0, &edx);
70         if (edx & (1 << 27)) {
71                 write_msr(MSR_TSC_AUX, coreid);
72                 /* Busted versions of qemu bug out here (32 bit) */
73                 asm volatile ("rdtscp" : "=c"(rdtscp_ecx) : : "eax", "edx");
74                 if (!coreid && (read_msr(MSR_TSC_AUX) != rdtscp_ecx))
75                         printk("\nBroken rdtscp detected, don't trust it for pcoreid!\n\n");
76         }
77 }
78
79 /* TODO: consider merging __arch_pcpu with parts of this (sync with RISCV) */
80 void smp_final_core_init(void)
81 {
82         /* Set the coreid in pcpui for fast access to it through TLS. */
83         int coreid = get_os_coreid(hw_core_id());
84         struct per_cpu_info *pcpui = &per_cpu_info[coreid];
85         pcpui->coreid = coreid;
86         write_msr(MSR_GS_BASE, (uintptr_t)pcpui);       /* our cr4 isn't set yet */
87         write_msr(MSR_KERN_GS_BASE, (uint64_t)pcpui);
88         /* don't need this for the kernel anymore, but userspace can still use it */
89         setup_rdtscp(coreid);
90         /* After this point, all cores have set up their segmentation and whatnot to
91          * be able to do a proper core_id(). */
92         waiton_barrier(&generic_barrier);
93         if (coreid == 0)
94                 core_id_ready = TRUE;
95         /* being paranoid with this, it's all a bit ugly */
96         waiton_barrier(&generic_barrier);
97         setup_default_mtrrs(&generic_barrier);
98         smp_percpu_init();
99         waiton_barrier(&generic_barrier);
100 }
101
102 // this needs to be set in smp_entry too...
103 #define trampoline_pg 0x00001000UL
104 extern char smp_entry[];
105 extern char smp_entry_end[];
106 extern char smp_boot_lock[];
107 extern char smp_semaphore[];
108
109 static inline uint16_t *get_smp_semaphore()
110 {
111         return (uint16_t *)(smp_semaphore - smp_entry + trampoline_pg);
112 }
113
114 static void __spin_bootlock_raw(void)
115 {
116         uint16_t *bootlock = (uint16_t*)(smp_boot_lock - smp_entry + trampoline_pg);
117         /* Same lock code as in smp_entry */
118         asm volatile ("movw $1, %%ax;   "
119                                   "1:               "
120                       "xchgw %%ax, %0;  "
121                       "test %%ax, %%ax; "
122                       "jne 1b;" : : "m"(*bootlock) : "eax", "cc", "memory");
123 }
124
125 void smp_boot(void)
126 {
127         struct per_cpu_info *pcpui0 = &per_cpu_info[0];
128         page_t *smp_stack;
129
130         // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
131         // page1 (2nd page) is reserved, hardcoded in pmap.c
132         memset(KADDR(trampoline_pg), 0, PGSIZE);
133         memcpy(KADDR(trampoline_pg), (void *)smp_entry,
134            smp_entry_end - smp_entry);
135
136         /* Make sure the trampoline page is mapped.  64 bit already has the tramp pg
137          * mapped (1 GB of lowmem), so this is a nop. */
138
139         // Allocate a stack for the cores starting up.  One for all, must share
140         if (kpage_alloc(&smp_stack))
141                 panic("No memory for SMP boot stack!");
142         smp_stack_top = (uintptr_t)(page2kva(smp_stack) + PGSIZE);
143
144         /* During SMP boot, core_id_early() returns 0, so all of the cores, which
145          * grab locks concurrently, share the same pcpui and thus the same
146          * lock_depth.  We need to disable checking until core_id works properly. */
147         pcpui0->__lock_checking_enabled = 0;
148         // Start the IPI process (INIT, wait, SIPI, wait, SIPI, wait)
149         send_init_ipi();
150         // SDM 3A is a little wonky wrt the proper delays.  These are my best guess.
151         udelay(10000);
152         // first SIPI
153         send_startup_ipi(0x01);
154         /* BOCHS does not like this second SIPI.
155         // second SIPI
156         udelay(200);
157         send_startup_ipi(0x01);
158         */
159         udelay(500000);
160
161         // Each core will also increment smp_semaphore, and decrement when it is done,
162         // all in smp_entry.  It's purpose is to keep Core0 from competing for the
163         // smp_boot_lock.  So long as one AP increments the sem before the final
164         // LAPIC timer goes off, all available cores will be initialized.
165         while (*get_smp_semaphore())
166                 cpu_relax();
167
168         // From here on, no other cores are coming up.  Grab the lock to ensure it.
169         // Another core could be in it's prelock phase and be trying to grab the lock
170         // forever....
171         // The lock exists on the trampoline, so it can be grabbed right away in
172         // real mode.  If core0 wins the race and blocks other CPUs from coming up
173         // it can crash the machine if the other cores are allowed to proceed with
174         // booting.  Specifically, it's when they turn on paging and have that temp
175         // mapping pulled out from under them.  Now, if a core loses, it will spin
176         // on the trampoline (which we must be careful to not deallocate)
177         __spin_bootlock_raw();
178         printk("Number of Cores Detected: %d\n", x86_num_cores_booted);
179 #ifdef CONFIG_DISABLE_SMT
180         assert(!(num_cores % 2));
181         printk("Using only %d Idlecores (SMT Disabled)\n", num_cores >> 1);
182 #endif /* CONFIG_DISABLE_SMT */
183
184         /* cleans up the trampoline page, and any other low boot mem mappings */
185         x86_cleanup_bootmem();
186         /* trampoline_pg had a refcount of 2 earlier, so we need to dec once more to free it
187          * but only if all cores are in (or we reset / reinit those that failed) */
188         if (x86_num_cores_booted == num_cores) {
189                 page_decref(pa2page(trampoline_pg));
190         } else {
191                 warn("ACPI/MP found %d cores, smp_boot initialized %d, using %d\n",
192                      num_cores, x86_num_cores_booted, x86_num_cores_booted);
193                 num_cores = x86_num_cores_booted;
194         }
195         // Dealloc the temp shared stack
196         page_decref(smp_stack);
197
198         // Set up the generic remote function call facility
199         init_smp_call_function();
200
201         /* Final core initialization */
202         init_barrier(&generic_barrier, num_cores);
203         /* This will break the cores out of their hlt in smp_entry.S */
204         send_broadcast_ipi(I_POKE_CORE);
205         smp_final_core_init();  /* need to init ourselves as well */
206 }
207
208 /* This is called from smp_entry by each core to finish the core bootstrapping.
209  * There is a spinlock around this entire function in smp_entry, for a few
210  * reasons, the most important being that all cores use the same stack when
211  * entering here.
212  *
213  * Do not use per_cpu_info in here.  Do whatever you need in smp_percpu_init().
214  */
215 uintptr_t smp_main(void)
216 {
217         /*
218         // Print some diagnostics.  Uncomment if there're issues.
219         cprintf("Good morning Vietnam!\n");
220         cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
221         cprintf("This core's Current APIC ID: 0x%08x\n", lapic_get_id());
222         if (read_msr(IA32_APIC_BASE) & 0x00000100)
223                 cprintf("I am the Boot Strap Processor\n");
224         else
225                 cprintf("I am an Application Processor\n");
226         cprintf("Num_Cores: %d\n\n", num_cores);
227         */
228
229         // Get a per-core kernel stack
230         uintptr_t my_stack_top = get_kstack();
231
232         /* This blob is the GDT, the GDT PD, and the TSS. */
233         unsigned int blob_size = sizeof(segdesc_t) * SEG_COUNT +
234                                  sizeof(pseudodesc_t) + sizeof(taskstate_t);
235         /* TODO: don't use kmalloc - might have issues in the future */
236         void *gdt_etc = kmalloc(blob_size, 0);          /* we'll never free this btw */
237         taskstate_t *my_ts = gdt_etc;
238         pseudodesc_t *my_gdt_pd = (void*)my_ts + sizeof(taskstate_t);
239         segdesc_t *my_gdt = (void*)my_gdt_pd + sizeof(pseudodesc_t);
240         /* This is a bit ghetto: we need to communicate our GDT and TSS's location
241          * to smp_percpu_init(), but we can't trust our coreid (since they haven't
242          * been remapped yet (so we can't write it directly to per_cpu_info)).  So
243          * we use the bottom of the stack page... */
244         *kstack_bottom_addr(my_stack_top) = (uintptr_t)gdt_etc;
245
246         // Build and load the gdt / gdt_pd
247         memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
248         *my_gdt_pd = (pseudodesc_t) {
249                 sizeof(segdesc_t)*SEG_COUNT - 1, (uintptr_t) my_gdt };
250         asm volatile("lgdt %0" : : "m"(*my_gdt_pd));
251
252         /* Set up our kernel stack when changing rings */
253         x86_set_stacktop_tss(my_ts, my_stack_top);
254         // Initialize the TSS field of my_gdt.
255         syssegdesc_t *ts_slot = (syssegdesc_t*)&my_gdt[GD_TSS >> 3];
256         *ts_slot = (syssegdesc_t)SEG_SYS_SMALL(STS_T32A, (uintptr_t)my_ts,
257                                                sizeof(taskstate_t), 0);
258         // Load the TSS
259         ltr(GD_TSS);
260
261         // Loads the same IDT used by the other cores
262         asm volatile("lidt %0" : : "m"(idt_pd));
263
264         apiconline();
265
266
267         return my_stack_top; // will be loaded in smp_entry.S
268 }
269
270 /* Perform any initialization needed by per_cpu_info.  Make sure every core
271  * calls this at some point in the smp_boot process.  If you don't smp_boot, you
272  * must still call this for core 0.  This must NOT be called from smp_main,
273  * since it relies on the kernel stack pointer to find the gdt.  Be careful not
274  * to call it on too deep of a stack frame. */
275 void __arch_pcpu_init(uint32_t coreid)
276 {
277         uintptr_t *my_stack_bot;
278         struct per_cpu_info *pcpui = &per_cpu_info[coreid];
279         uint32_t eax, edx;
280
281         /* Flushes any potentially old mappings from smp_boot() (note the page table
282          * removal) */
283         tlbflush();
284
285         if (cpu_has_feat(CPU_FEAT_X86_FSGSBASE))
286                 lcr4(rcr4() | CR4_FSGSBASE);
287
288         /*
289          * Enable SSE instructions.
290          * CR4.OSFXSR enables SSE and ensures that MXCSR/XMM gets saved with FXSAVE
291          * CR4.OSXSAVE enables XSAVE instructions. Only set if XSAVEOPT supported.
292          * CR4.OSXMME indicates OS support for software exception handlers for
293          * SIMD floating-point exceptions (turn it on to get #XM exceptions
294          * in the event of a SIMD error instead of #UD exceptions).
295          */
296         lcr4(rcr4() | CR4_OSFXSR | CR4_OSXMME);
297
298         if (cpu_has_feat(CPU_FEAT_X86_XSAVEOPT)) {
299                 // You MUST set CR4.OSXSAVE before loading xcr0
300                 lcr4(rcr4() | CR4_OSXSAVE);
301                 // Set xcr0 to the Akaros-wide default
302                 lxcr0(x86_default_xcr0);
303         }
304
305         // Initialize fpu and extended state by restoring our default XSAVE area.
306         init_fp_state();
307
308         /* core 0 sets up via the global gdt symbol */
309         if (!coreid) {
310                 pcpui->tss = &ts;
311                 pcpui->gdt = gdt;
312         } else {
313                 my_stack_bot = kstack_bottom_addr(ROUNDUP(read_sp() - 1, PGSIZE));
314                 pcpui->tss = (taskstate_t*)(*my_stack_bot);
315                 pcpui->gdt = (segdesc_t*)(*my_stack_bot +
316                                           sizeof(taskstate_t) + sizeof(pseudodesc_t));
317         }
318         assert(read_gsbase() == (uintptr_t)pcpui);
319         assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
320         /* Don't try setting up til after setting GS */
321         x86_sysenter_init(x86_get_stacktop_tss(pcpui->tss));
322         /* need to init perfctr before potentially using it in timer handler */
323         perfmon_pcpu_init();
324         vmm_pcpu_init();
325         lcr4(rcr4() & ~CR4_TSD);
326 }