Spinlock irqsave usage checks
[akaros.git] / kern / src / smp.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 #endif
10
11 #include <arch/arch.h>
12 #include <atomic.h>
13 #include <smp.h>
14 #include <error.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <assert.h>
18 #include <pmap.h>
19 #include <process.h>
20 #include <schedule.h>
21 #include <trap.h>
22
23 struct per_cpu_info per_cpu_info[MAX_NUM_CPUS];
24
25 // tracks number of global waits on smp_calls, must be <= NUM_HANDLER_WRAPPERS
26 atomic_t outstanding_calls = 0;
27
28 /* Helper for running a proc (if we should).  Lots of repetition with
29  * proc_restartcore */
30 static void try_run_proc(void)
31 {
32         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
33
34         disable_irq();
35         /* There was a process running here, and we should return to it. */
36         if (pcpui->owning_proc) {
37                 proc_restartcore();
38                 assert(0);
39         }
40 }
41
42 /* All cores end up calling this whenever there is nothing left to do or they
43  * don't know explicitly what to do.  Non-zero cores call it when they are done
44  * booting.  Other cases include after getting a DEATH IPI.
45  *
46  * All cores attempt to run the context of any owning proc.  Barring that, the
47  * cores enter a loop.  They halt and wake up when interrupted, do any work on
48  * their work queue, then halt again.  In between, the ksched gets a chance to
49  * tell it to do something else, or perhaps to halt in another manner. */
50 static void __attribute__((noinline, noreturn)) __smp_idle(void)
51 {
52         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
53         clear_rkmsg(pcpui);
54         /* TODO: idle, abandon_core(), and proc_restartcore() need cleaned up */
55         enable_irq();   /* get any IRQs before we halt later */
56         try_run_proc();
57         /* if we made it here, we truly want to idle */
58         /* in the future, we may need to proactively leave process context here.
59          * for now, it is possible to have a current loaded, even if we are idle
60          * (and presumably about to execute a kmsg or fire up a vcore). */
61         while (1) {
62                 disable_irq();
63                 process_routine_kmsg();
64                 try_run_proc();
65                 cpu_bored();            /* call out to the ksched */
66                 /* cpu_halt() atomically turns on interrupts and halts the core.
67                  * Important to do this, since we could have a RKM come in via an
68                  * interrupt right while PRKM is returning, and we wouldn't catch
69                  * it. */
70                 cpu_halt();
71                 /* interrupts are back on now (given our current semantics) */
72         }
73         assert(0);
74 }
75
76 void smp_idle(void)
77 {
78         #ifdef __CONFIG_RESET_STACKS__
79         set_stack_pointer(get_stack_top());
80         #endif /* __CONFIG_RESET_STACKS__ */
81         __smp_idle();
82         assert(0);
83 }
84
85 /* Arch-independent per-cpu initialization.  This will call the arch dependent
86  * init first. */
87 void smp_percpu_init(void)
88 {
89         uint32_t coreid = core_id();
90         /* Don't initialize __ctx_depth here, since it is already 1 (at least on
91          * x86), since this runs in irq context. */
92         /* Do this first */
93         __arch_pcpu_init(coreid);
94         per_cpu_info[coreid].spare = 0;
95         /* Init relevant lists */
96         spinlock_init_irqsave(&per_cpu_info[coreid].immed_amsg_lock);
97         STAILQ_INIT(&per_cpu_info[coreid].immed_amsgs);
98         spinlock_init_irqsave(&per_cpu_info[coreid].routine_amsg_lock);
99         STAILQ_INIT(&per_cpu_info[coreid].routine_amsgs);
100         /* Initialize the per-core timer chain */
101         init_timer_chain(&per_cpu_info[coreid].tchain, set_pcpu_alarm_interrupt);
102 #ifdef __CONFIG_KTHREAD_POISON__
103         /* TODO: KTHR-STACK */
104         uintptr_t *poison = (uintptr_t*)ROUNDDOWN(get_stack_top() - 1, PGSIZE);
105         *poison = 0xdeadbeef;
106 #endif /* __CONFIG_KTHREAD_POISON__ */
107 }