PCI device locking and synchronization
[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 #ifdef __SHARC__
8 #pragma nosharc
9 #define SINIT(x) x
10 #endif
11
12 #include <arch/x86.h>
13 #include <arch/arch.h>
14 #include <smp.h>
15 #include <arch/console.h>
16 #include <arch/apic.h>
17 #include <arch/perfmon.h>
18 #include <time.h>
19
20 #include <bitmask.h>
21 #include <atomic.h>
22 #include <error.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <pmap.h>
27 #include <env.h>
28 #include <trap.h>
29 #include <kmalloc.h>
30
31 extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
32 volatile uint32_t num_cpus = 0xee;
33 uintptr_t RO smp_stack_top;
34 barrier_t generic_barrier;
35
36 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
37         INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CPUS);
38
39 #define INIT_HANDLER_WRAPPER(v)                                     \
40 {                                                                   \
41         handler_wrappers[(v)].vector = 0xf##v;                          \
42         handler_wrappers[(v)].cpu_list = &f##v##_cpu_list;              \
43         handler_wrappers[(v)].cpu_list->mask.size = num_cpus;           \
44 }
45
46 DECLARE_HANDLER_CHECKLISTS(0);
47 DECLARE_HANDLER_CHECKLISTS(1);
48 DECLARE_HANDLER_CHECKLISTS(2);
49 DECLARE_HANDLER_CHECKLISTS(3);
50 DECLARE_HANDLER_CHECKLISTS(4);
51
52 static void init_smp_call_function(void)
53 {
54         INIT_HANDLER_WRAPPER(0);
55         INIT_HANDLER_WRAPPER(1);
56         INIT_HANDLER_WRAPPER(2);
57         INIT_HANDLER_WRAPPER(3);
58         INIT_HANDLER_WRAPPER(4);
59 }
60
61 /******************************************************************************/
62
63 void smp_final_core_init(void)
64 {
65         /* It is possible that the non-0 cores will wake up before the broadcast
66          * ipi.  this can be due to spurious IRQs or some such.  anyone other than
67          * core 0 that comes in here will wait til core 0 has set everything up */
68         static bool wait = TRUE;
69         if (get_os_coreid(hw_core_id()) == 0)
70                 wait = FALSE;
71         while (wait)
72                 cpu_relax();
73 #ifdef CONFIG_FAST_COREID
74         /* Need to bootstrap the rdtscp MSR with our OS coreid */
75         int coreid = get_os_coreid(hw_core_id());
76         write_msr(MSR_TSC_AUX, coreid);
77
78         /* Busted versions of qemu bug out here (32 bit) */
79         int rdtscp_ecx;
80         asm volatile ("rdtscp" : "=c"(rdtscp_ecx) : : "eax", "edx");
81         if (read_msr(MSR_TSC_AUX) != rdtscp_ecx) {
82                 printk("Broken rdtscp detected!  Rebuild without CONFIG_FAST_COREID\n");
83                 if (coreid)
84                         while(1);
85                 /* note this panic may think it is not core 0, and core 0 might not have
86                  * an issue (seems random) */
87                 panic("");
88         }
89 #endif
90         setup_default_mtrrs(&generic_barrier);
91         smp_percpu_init();
92         waiton_barrier(&generic_barrier);
93 }
94
95 // this needs to be set in smp_entry too...
96 #define trampoline_pg 0x00001000UL
97 extern char (SNT SREADONLY smp_entry)[];
98 extern char (SNT SREADONLY smp_entry_end)[];
99 extern char (SNT SREADONLY smp_boot_lock)[];
100 extern char (SNT SREADONLY smp_semaphore)[];
101
102 static inline uint16_t *get_smp_semaphore()
103 {
104         return (uint16_t *)(smp_semaphore - smp_entry + trampoline_pg);
105 }
106
107 static void __spin_bootlock_raw(void)
108 {
109         uint16_t *bootlock = (uint16_t*)(smp_boot_lock - smp_entry + trampoline_pg);
110         /* Same lock code as in smp_entry */
111         asm volatile ("movw $1, %%ax;   "
112                                   "1:               "
113                       "xchgw %%ax, %0;  "
114                       "test %%ax, %%ax; "
115                       "jne 1b;" : : "m"(*bootlock) : "eax", "cc", "memory");
116 }
117
118 /* hw_coreid_lookup will get packed, but keep it's hw values.  
119  * os_coreid_lookup will remain sparse, but it's values will be consecutive.
120  * for both arrays, -1 means an empty slot.  hw_step tracks the next valid entry
121  * in hw_coreid_lookup, jumping over gaps of -1's. */
122 static void smp_remap_coreids(void)
123 {
124         for (int i = 0, hw_step = 0; i < num_cpus; i++, hw_step++) {
125                 if (hw_coreid_lookup[i] == -1) {
126                         while (hw_coreid_lookup[hw_step] == -1) {
127                                 hw_step++;
128                                 if (hw_step == MAX_NUM_CPUS)
129                                         panic("Mismatch in num_cpus and hw_step");
130                         }
131                         hw_coreid_lookup[i] = hw_coreid_lookup[hw_step];
132                         hw_coreid_lookup[hw_step] = -1;
133                         os_coreid_lookup[hw_step] = i;
134                 }
135         }
136 }
137
138 void smp_boot(void)
139 {
140         /* set core0's mappings */
141         assert(lapic_get_id() == 0);
142         os_coreid_lookup[0] = 0;
143         hw_coreid_lookup[0] = 0;
144
145         page_t *smp_stack;
146         // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
147         // page1 (2nd page) is reserved, hardcoded in pmap.c
148         memset(KADDR(trampoline_pg), 0, PGSIZE);
149         memcpy(KADDR(trampoline_pg), (void *COUNT(PGSIZE))TC(smp_entry),
150            smp_entry_end - smp_entry);
151
152         /* 64 bit already has the tramp pg mapped (1 GB of lowmem)  */
153 #ifndef CONFIG_X86_64
154         // This mapping allows access to the trampoline with paging on and off
155         // via trampoline_pg
156         page_insert(boot_pgdir, pa2page(trampoline_pg), (void*SNT)trampoline_pg, PTE_W);
157 #endif
158
159         // Allocate a stack for the cores starting up.  One for all, must share
160         if (kpage_alloc(&smp_stack))
161                 panic("No memory for SMP boot stack!");
162         smp_stack_top = SINIT((uintptr_t)(page2kva(smp_stack) + PGSIZE));
163
164         // Start the IPI process (INIT, wait, SIPI, wait, SIPI, wait)
165         send_init_ipi();
166         // SDM 3A is a little wonky wrt the proper delays.  These are my best guess.
167         udelay(10000);
168         // first SIPI
169         send_startup_ipi(0x01);
170         /* BOCHS does not like this second SIPI.
171         // second SIPI
172         udelay(200);
173         send_startup_ipi(0x01);
174         */
175         udelay(500000);
176
177         // Each core will also increment smp_semaphore, and decrement when it is done,
178         // all in smp_entry.  It's purpose is to keep Core0 from competing for the
179         // smp_boot_lock.  So long as one AP increments the sem before the final
180         // LAPIC timer goes off, all available cores will be initialized.
181         while (*get_smp_semaphore())
182                 cpu_relax();
183
184         // From here on, no other cores are coming up.  Grab the lock to ensure it.
185         // Another core could be in it's prelock phase and be trying to grab the lock
186         // forever....
187         // The lock exists on the trampoline, so it can be grabbed right away in
188         // real mode.  If core0 wins the race and blocks other CPUs from coming up
189         // it can crash the machine if the other cores are allowed to proceed with
190         // booting.  Specifically, it's when they turn on paging and have that temp
191         // mapping pulled out from under them.  Now, if a core loses, it will spin
192         // on the trampoline (which we must be careful to not deallocate)
193         __spin_bootlock_raw();
194         printk("Number of Cores Detected: %d\n", num_cpus);
195 #ifdef CONFIG_DISABLE_SMT
196         assert(!(num_cpus % 2));
197         printk("Using only %d Idlecores (SMT Disabled)\n", num_cpus >> 1);
198 #endif /* CONFIG_DISABLE_SMT */
199         smp_remap_coreids();
200
201         /* cleans up the trampoline page, and any other low boot mem mappings */
202         x86_cleanup_bootmem();
203         // It had a refcount of 2 earlier, so we need to dec once more to free it
204         // but only if all cores are in (or we reset / reinit those that failed)
205         // TODO after we parse ACPI tables
206         if (num_cpus == 8) // TODO - ghetto coded for our 8 way SMPs
207                 page_decref(pa2page(trampoline_pg));
208         // Dealloc the temp shared stack
209         page_decref(smp_stack);
210
211         // Set up the generic remote function call facility
212         init_smp_call_function();
213
214         /* Final core initialization */
215         init_barrier(&generic_barrier, num_cpus);
216         /* This will break the cores out of their hlt in smp_entry.S */
217         send_broadcast_ipi(254);
218         smp_final_core_init();  /* need to init ourselves as well */
219 }
220
221 /* This is called from smp_entry by each core to finish the core bootstrapping.
222  * There is a spinlock around this entire function in smp_entry, for a few
223  * reasons, the most important being that all cores use the same stack when
224  * entering here.
225  *
226  * Do not use per_cpu_info in here.  Do whatever you need in smp_percpu_init().
227  */
228 uintptr_t smp_main(void)
229 {
230         /*
231         // Print some diagnostics.  Uncomment if there're issues.
232         cprintf("Good morning Vietnam!\n");
233         cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
234         cprintf("This core's Current APIC ID: 0x%08x\n", lapic_get_id());
235         if (read_msr(IA32_APIC_BASE) & 0x00000100)
236                 cprintf("I am the Boot Strap Processor\n");
237         else
238                 cprintf("I am an Application Processor\n");
239         cprintf("Num_Cpus: %d\n\n", num_cpus);
240         */
241         /* set up initial mappings.  core0 will adjust it later */
242         unsigned long my_hw_id = lapic_get_id();
243         os_coreid_lookup[my_hw_id] = my_hw_id;
244         hw_coreid_lookup[my_hw_id] = my_hw_id;
245
246         // Get a per-core kernel stack
247         uintptr_t my_stack_top = get_kstack();
248
249         /* This blob is the GDT, the GDT PD, and the TSS. */
250         unsigned int blob_size = sizeof(segdesc_t) * SEG_COUNT +
251                                  sizeof(pseudodesc_t) + sizeof(taskstate_t);
252         /* TODO: don't use kmalloc - might have issues in the future */
253         void *gdt_etc = kmalloc(blob_size, 0);          /* we'll never free this btw */
254         taskstate_t *my_ts = gdt_etc;
255         pseudodesc_t *my_gdt_pd = (void*)my_ts + sizeof(taskstate_t);
256         segdesc_t *my_gdt = (void*)my_gdt_pd + sizeof(pseudodesc_t);
257         /* This is a bit ghetto: we need to communicate our GDT and TSS's location
258          * to smp_percpu_init(), but we can't trust our coreid (since they haven't
259          * been remapped yet (so we can't write it directly to per_cpu_info)).  So
260          * we use the bottom of the stack page... */
261         *kstack_bottom_addr(my_stack_top) = (uintptr_t)gdt_etc;
262
263         // Build and load the gdt / gdt_pd
264         memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
265         *my_gdt_pd = (pseudodesc_t) {
266                 sizeof(segdesc_t)*SEG_COUNT - 1, (uintptr_t) my_gdt };
267         asm volatile("lgdt %0" : : "m"(*my_gdt_pd));
268
269         /* Set up our kernel stack when changing rings */
270         x86_set_stacktop_tss(my_ts, my_stack_top);
271         // Initialize the TSS field of my_gdt.
272         syssegdesc_t *ts_slot = (syssegdesc_t*)&my_gdt[GD_TSS >> 3];
273         *ts_slot = (syssegdesc_t)SEG_SYS_SMALL(STS_T32A, (uintptr_t)my_ts,
274                                                sizeof(taskstate_t), 0);
275         // Load the TSS
276         ltr(GD_TSS);
277
278         // Loads the same IDT used by the other cores
279         asm volatile("lidt %0" : : "m"(idt_pd));
280
281 #ifdef CONFIG_ENABLE_MPTABLES
282         apiconline();
283 #else
284         // APIC setup
285         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
286         write_mmreg32(LAPIC_LVT_LINT0, 0x700);
287         // mask it to shut it up for now.  Doesn't seem to matter yet, since both
288         // KVM and Bochs seem to only route the PIC to core0.
289         mask_lapic_lvt(LAPIC_LVT_LINT0);
290         // and then turn it on
291         lapic_enable();
292 #endif
293
294         // set a default logical id for now
295         lapic_set_logid(lapic_get_id());
296
297         return my_stack_top; // will be loaded in smp_entry.S
298 }
299
300 /* Perform any initialization needed by per_cpu_info.  Make sure every core
301  * calls this at some point in the smp_boot process.  If you don't smp_boot, you
302  * must still call this for core 0.  This must NOT be called from smp_main,
303  * since it relies on the kernel stack pointer to find the gdt.  Be careful not
304  * to call it on too deep of a stack frame. */
305 void __arch_pcpu_init(uint32_t coreid)
306 {
307         uintptr_t *my_stack_bot;
308         struct per_cpu_info *pcpui = &per_cpu_info[coreid];
309
310         /* Flushes any potentially old mappings from smp_boot() (note the page table
311          * removal) */
312         tlbflush();
313         /* Ensure the FPU units are initialized */
314         asm volatile ("fninit");
315
316         /* Enable SSE instructions.  We might have to do more, like masking certain
317          * flags or exceptions in the MXCSR, or at least handle the SIMD exceptions.
318          * We don't do it for FP yet either, so YMMV. */
319         lcr4(rcr4() | CR4_OSFXSR | CR4_OSXMME);
320
321         /* core 0 sets up via the global gdt symbol */
322         if (!coreid) {
323                 pcpui->tss = &ts;
324                 pcpui->gdt = gdt;
325         } else {
326                 my_stack_bot = kstack_bottom_addr(ROUNDUP(read_sp() - 1, PGSIZE));
327                 pcpui->tss = (taskstate_t*)(*my_stack_bot);
328                 pcpui->gdt = (segdesc_t*)(*my_stack_bot +
329                                           sizeof(taskstate_t) + sizeof(pseudodesc_t));
330         }
331 #ifdef CONFIG_X86_64
332         /* Core 0 set up the base MSRs in entry64 */
333         if (!coreid) {
334                 assert(read_msr(MSR_GS_BASE) == (uint64_t)pcpui);
335                 assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
336         } else {
337                 write_msr(MSR_GS_BASE, (uint64_t)pcpui);
338                 write_msr(MSR_KERN_GS_BASE, (uint64_t)pcpui);
339         }
340 #endif
341         /* Don't try setting up til after setting GS */
342         x86_sysenter_init(x86_get_stacktop_tss(pcpui->tss));
343         /* need to init perfctr before potentiall using it in timer handler */
344         perfmon_init();
345 }