Interrupt handlers and smp_calls take a void*
[akaros.git] / kern / smp.c
1 #ifdef __DEPUTY__
2 #pragma nodeputy
3 #endif
4
5 #include <inc/stdio.h>
6 #include <inc/string.h>
7 #include <inc/assert.h>
8 #include <inc/error.h>
9 #include <inc/x86.h>
10
11 #include <kern/smp.h>
12 #include <kern/console.h>
13 #include <kern/pmap.h>
14 #include <kern/env.h>
15 #include <kern/apic.h>
16 #include <kern/atomic.h>
17
18 volatile uint8_t num_cpus = 0xee;
19 uintptr_t smp_stack_top;
20 barrier_t generic_barrier;
21
22 /*************************** IPI Wrapper Stuff ********************************/
23 // checklists to protect the global interrupt_handlers for 0xf0, f1, f2, f3, f4
24 // need to be global, since there is no function that will always exist for them
25 handler_wrapper_t             handler_wrappers[NUM_HANDLER_WRAPPERS];
26 // tracks number of global waits on smp_calls, must be <= NUM_HANDLER_WRAPPERS
27 uint32_t outstanding_calls = 0; 
28
29 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
30         INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CPUS);
31
32 #define INIT_HANDLER_WRAPPER(v)                                     \
33 {                                                                   \
34         handler_wrappers[(v)].vector = 0xf##v;                          \
35         handler_wrappers[(v)].cpu_list = &f##v##_cpu_list;              \
36         handler_wrappers[(v)].cpu_list->mask.size = num_cpus;           \
37 }
38
39 DECLARE_HANDLER_CHECKLISTS(0);
40 DECLARE_HANDLER_CHECKLISTS(1);
41 DECLARE_HANDLER_CHECKLISTS(2);
42 DECLARE_HANDLER_CHECKLISTS(3);
43 DECLARE_HANDLER_CHECKLISTS(4);
44
45 static void init_smp_call_function(void)
46 {
47         INIT_HANDLER_WRAPPER(0);
48         INIT_HANDLER_WRAPPER(1);
49         INIT_HANDLER_WRAPPER(2);
50         INIT_HANDLER_WRAPPER(3);
51         INIT_HANDLER_WRAPPER(4);
52 }
53
54 /******************************************************************************/
55
56 static void smp_mtrr_handler(trapframe_t *tf, void* data)
57 {
58         // TODO - pass in the barrier via data, and not the global
59         setup_default_mtrrs(&generic_barrier);
60 }
61
62 void smp_boot(void)
63 {
64         // this needs to be set in smp_entry too...
65         #define trampoline_pg 0x00001000
66         page_t *smp_stack;
67         // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
68         // page1 (2nd page) is reserved, hardcoded in pmap.c
69         extern smp_entry(), smp_entry_end(), smp_boot_lock(), smp_semaphore();
70         memset(KADDR(trampoline_pg), 0, PGSIZE);
71         memcpy(KADDR(trampoline_pg), &smp_entry, &smp_entry_end - &smp_entry);
72
73         // This mapping allows access to the trampoline with paging on and off
74         // via trampoline_pg
75         page_insert(boot_pgdir, pa2page(trampoline_pg), (void*)trampoline_pg, PTE_W);
76
77         // Allocate a stack for the cores starting up.  One for all, must share
78         if (page_alloc(&smp_stack))
79                 panic("No memory for SMP boot stack!");
80         smp_stack_top = (uintptr_t)(page2kva(smp_stack) + PGSIZE);
81
82         // Start the IPI process (INIT, wait, SIPI, wait, SIPI, wait)
83         send_init_ipi();
84         // SDM 3A is a little wonky wrt the proper delays.  These are my best guess.
85         udelay(10000);
86         // first SIPI
87         send_startup_ipi(0x01);
88         /* BOCHS does not like this second SIPI.
89         // second SIPI
90         udelay(200);
91         send_startup_ipi(0x01);
92         */
93         udelay(100000);
94
95         // Each core will also increment smp_semaphore, and decrement when it is done,
96         // all in smp_entry.  It's purpose is to keep Core0 from competing for the
97         // smp_boot_lock.  So long as one AP increments the sem before the final
98         // LAPIC timer goes off, all available cores will be initialized.
99         while(*(volatile uint32_t*)(&smp_semaphore - &smp_entry + trampoline_pg));
100
101         // From here on, no other cores are coming up.  Grab the lock to ensure it.
102         // Another core could be in it's prelock phase and be trying to grab the lock
103         // forever....
104         // The lock exists on the trampoline, so it can be grabbed right away in
105         // real mode.  If core0 wins the race and blocks other CPUs from coming up
106         // it can crash the machine if the other cores are allowed to proceed with
107         // booting.  Specifically, it's when they turn on paging and have that temp
108         // mapping pulled out from under them.  Now, if a core loses, it will spin
109         // on the trampoline (which we must be careful to not deallocate)
110         spin_lock((uint32_t*)(&smp_boot_lock - &smp_entry + trampoline_pg));
111         cprintf("Num_Cpus Detected: %d\n", num_cpus);
112
113         // Remove the mapping of the page used by the trampoline
114         page_remove(boot_pgdir, (void*)trampoline_pg);
115         // It had a refcount of 2 earlier, so we need to dec once more to free it
116         // but only if all cores are in (or we reset / reinit those that failed)
117         // TODO after we parse ACPI tables
118         if (num_cpus == 8) // TODO - ghetto coded for our 8 way SMPs
119                 page_decref(pa2page(trampoline_pg));
120         // Dealloc the temp shared stack
121         page_decref(smp_stack);
122
123         // Set up the generic remote function call facility
124         init_smp_call_function();
125
126         // Set up all cores to use the proper MTRRs
127         init_barrier(&generic_barrier, num_cpus); // barrier used by smp_mtrr_handler
128         smp_call_function_all(smp_mtrr_handler, 0, 0);
129
130         // Should probably flush everyone's TLB at this point, to get rid of
131         // temp mappings that were removed.  TODO
132 }
133
134 /*
135  * This is called from smp_entry by each core to finish the core bootstrapping.
136  * There is a spinlock around this entire function in smp_entry, for a few reasons,
137  * the most important being that all cores use the same stack when entering here.
138  */
139 uint32_t smp_main(void)
140 {
141         /*
142         // Print some diagnostics.  Uncomment if there're issues.
143         cprintf("Good morning Vietnam!\n");
144         cprintf("This core's Default APIC ID: 0x%08x\n", lapic_get_default_id());
145         cprintf("This core's Current APIC ID: 0x%08x\n", lapic_get_id());
146         if (read_msr(IA32_APIC_BASE) & 0x00000100)
147                 cprintf("I am the Boot Strap Processor\n");
148         else
149                 cprintf("I am an Application Processor\n");
150         cprintf("Num_Cpus: %d\n\n", num_cpus);
151         */
152
153         // Get a per-core kernel stack
154         page_t *my_stack;
155         if (page_alloc(&my_stack))
156                 panic("Unable to alloc a per-core stack!");
157         memset(page2kva(my_stack), 0, PGSIZE);
158
159         // Set up a gdt / gdt_pd for this core, stored at the top of the stack
160         // This is necessary, eagle-eyed readers know why
161         // GDT should be 4-byte aligned.  TS isn't aligned.  Not sure if it matters.
162         pseudodesc_t *my_gdt_pd = page2kva(my_stack) + PGSIZE -
163                 sizeof(pseudodesc_t) - sizeof(segdesc_t)*SEG_COUNT;
164         segdesc_t *my_gdt = page2kva(my_stack) + PGSIZE -
165                 sizeof(segdesc_t)*SEG_COUNT;
166         // TS also needs to be permanent
167         taskstate_t *my_ts = page2kva(my_stack) + PGSIZE -
168                 sizeof(pseudodesc_t) - sizeof(segdesc_t)*SEG_COUNT -
169                 sizeof(taskstate_t);
170         // Usable portion of the KSTACK grows down from here
171         // Won't actually start using this stack til our first interrupt
172         // (issues with changing the stack pointer and then trying to "return")
173         uintptr_t my_stack_top = (uintptr_t)my_ts;
174
175         // Build and load the gdt / gdt_pd
176         memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
177         *my_gdt_pd = (pseudodesc_t) {
178                 sizeof(segdesc_t)*SEG_COUNT - 1, (uintptr_t) my_gdt };
179         asm volatile("lgdt %0" : : "m"(*my_gdt_pd));
180
181         // Need to set the TSS so we know where to trap on this core
182         my_ts->ts_esp0 = my_stack_top;
183         my_ts->ts_ss0 = GD_KD;
184         // Initialize the TSS field of my_gdt.
185         my_gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (my_ts), sizeof(taskstate_t), 0);
186         my_gdt[GD_TSS >> 3].sd_s = 0;
187         // Load the TSS
188         ltr(GD_TSS);
189
190         // Loads the same IDT used by the other cores
191         asm volatile("lidt idt_pd");
192
193         // APIC setup
194         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
195         write_mmreg32(LAPIC_LVT_LINT0, 0x700);
196         // mask it to shut it up for now.  Doesn't seem to matter yet, since both
197         // KVM and Bochs seem to only route the PIC to core0.
198         mask_lapic_lvt(LAPIC_LVT_LINT0);
199         // and then turn it on
200         lapic_enable();
201
202         // set a default logical id for now
203         lapic_set_logid(lapic_get_id());
204
205         return my_stack_top; // will be loaded in smp_entry.S
206 }
207
208 // this idles a core, sometimes we need to call it directly.  never returns.
209 // the pause is somewhat of a hack, since kvm isn't halting.  not sure what the
210 // deal is with that.
211 void smp_idle(void)
212 {
213         asm volatile("1: hlt; pause; jmp 1b;");
214 }
215
216 static int smp_call_function(uint8_t type, uint8_t dest, isr_t handler, void* data,
217                               handler_wrapper_t** wait_wrapper)
218 {
219         extern handler_t interrupt_handlers[];
220         int8_t state = 0;
221         uint32_t wrapper_num;
222         handler_wrapper_t* wrapper;
223
224         // prevents us from ever having more than NUM_HANDLER_WRAPPERS callers in
225         // the process of competing for vectors.  not decremented until both after
226         // the while(1) loop and after it's been waited on.
227         atomic_inc(&outstanding_calls);
228         if (outstanding_calls > NUM_HANDLER_WRAPPERS) {
229                 atomic_dec(&outstanding_calls);
230                 return E_BUSY;
231         }
232         
233         // assumes our cores are numbered in order
234         if ((type == 4) && (dest >= num_cpus))
235                 panic("Destination CPU does not exist!");
236
237         // build the mask based on the type and destination
238         INIT_CHECKLIST_MASK(cpu_mask, MAX_NUM_CPUS);
239         // set checklist mask's size dynamically to the num cpus actually present
240         cpu_mask.size = num_cpus;
241         switch (type) {
242                 case 1: // self
243                         SET_BITMASK_BIT(cpu_mask.bits, lapic_get_id());
244                         break;
245                 case 2: // all
246                         FILL_BITMASK(cpu_mask.bits, num_cpus);
247                         break;
248                 case 3: // all but self
249                         FILL_BITMASK(cpu_mask.bits, num_cpus);
250                         CLR_BITMASK_BIT(cpu_mask.bits, lapic_get_id());
251                         break;
252                 case 4: // physical mode
253                         // note this only supports sending to one specific physical id
254                         // (only sets one bit, so if multiple cores have the same phys id
255                         // the first one through will set this).
256                         SET_BITMASK_BIT(cpu_mask.bits, dest);
257                         break;
258                 case 5: // logical mode
259                         // TODO
260                         warn("Logical mode bitmask handler protection not implemented!");
261                         break;
262                 default:
263                         panic("Invalid type for cross-core function call!");
264         }
265
266         // Find an available vector/wrapper.  Starts with this core's id (mod the
267         // number of wrappers).  Walk through on conflict.
268         // Commit returns an error if it wanted to give up for some reason,
269         // like taking too long to acquire the lock or clear the mask, at which
270         // point, we try the next one.
271         // When we are done, wrapper points to the one we finally got.
272         // this wrapper_num trick doesn't work as well if you send a bunch in a row
273         // and wait, since you always check your main one (which is currently busy).
274         wrapper_num = lapic_get_id() % NUM_HANDLER_WRAPPERS;
275         while(1) {
276                 wrapper = &handler_wrappers[wrapper_num];
277                 if (!commit_checklist_wait(wrapper->cpu_list, &cpu_mask))
278                         break;
279                 wrapper_num = (wrapper_num + 1) % NUM_HANDLER_WRAPPERS;
280                 /*
281                 uint32_t count = 0;
282                 // instead of deadlock, smp_call can fail with this.  makes it harder
283                 // to use (have to check your return value).  consider putting a delay
284                 // here too (like if wrapper_num == initial_wrapper_num)
285                 if (count++ > NUM_HANDLER_WRAPPERS * 1000) // note 1000 isn't enough...
286                         return E_BUSY;
287                 */
288         }
289
290         // Wanting to wait is expressed by having a non-NULL handler_wrapper_t**
291         // passed in.  Pass out our reference to wrapper, to wait later.
292         // If we don't want to wait, release the checklist (though it is still not
293         // clear, so it can't be used til everyone checks in).
294         if (wait_wrapper)
295                 *wait_wrapper = wrapper;
296         else {
297                 release_checklist(wrapper->cpu_list);
298                 atomic_dec(&outstanding_calls);
299         }
300
301         // now register our handler to run
302         register_interrupt_handler(interrupt_handlers, wrapper->vector, handler, data);
303         // WRITE MEMORY BARRIER HERE
304         enable_irqsave(&state);
305         // Send the proper type of IPI.  I made up these numbers.
306         switch (type) {
307                 case 1:
308                         send_self_ipi(wrapper->vector);
309                         break;
310                 case 2:
311                         send_broadcast_ipi(wrapper->vector);
312                         break;
313                 case 3:
314                         send_all_others_ipi(wrapper->vector);
315                         break;
316                 case 4: // physical mode
317                         send_ipi(dest, 0, wrapper->vector);
318                         break;
319                 case 5: // logical mode
320                         send_ipi(dest, 1, wrapper->vector);
321                         break;
322                 default:
323                         panic("Invalid type for cross-core function call!");
324         }
325         // wait long enough to receive our own broadcast (PROBABLY WORKS) TODO
326         lapic_wait_to_send();
327         disable_irqsave(&state);
328         return 0;
329 }
330
331 // Wrapper functions.  Add more as they are needed.
332 int smp_call_function_self(isr_t handler, void* data,
333                            handler_wrapper_t** wait_wrapper)
334 {
335         return smp_call_function(1, 0, handler, data, wait_wrapper);
336 }
337
338 int smp_call_function_all(isr_t handler, void* data,
339                           handler_wrapper_t** wait_wrapper)
340 {
341         return smp_call_function(2, 0, handler, data, wait_wrapper);
342 }
343
344 int smp_call_function_single(uint8_t dest, isr_t handler, void* data,
345                              handler_wrapper_t** wait_wrapper)
346 {
347         return smp_call_function(4, dest, handler, data, wait_wrapper);
348 }
349
350 // If you want to wait, pass the address of a pointer up above, then call
351 // this to do the actual waiting.  Be somewhat careful about uninitialized 
352 // or old wrapper pointers.
353 int smp_call_wait(handler_wrapper_t* wrapper)
354 {
355         if (wrapper) {
356                 waiton_checklist(wrapper->cpu_list);
357                 return 0;
358         } else {
359                 warn("Attempting to wait on null wrapper!  Check your return values!");
360                 return E_FAIL;
361         }
362 }
363