Adds a Makelocal option for resetting the stack
[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 <manager.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 /* All cores end up calling this whenever there is nothing left to do.  Non-zero
29  * cores call it when they are done booting.  Other cases include after getting
30  * a DEATH IPI.
31  * - Management cores (core 0 for now) call manager, which should never return.
32  * - Worker cores halt and wake up when interrupted, do any work on their work
33  *   queue, then halt again.
34  * TODO: think about unifying the manager into a workqueue function, so we don't
35  * need to check mgmt_core in here.  it gets a little ugly, since there are
36  * other places where we check for mgmt and might not smp_idle / call manager.
37  */
38 static void __smp_idle(void)
39 {
40         int8_t state = 0;
41         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
42
43         /* There was a process running here, and we should return to it */
44         if (pcpui->cur_tf) {                    /* aka, current_tf */
45                 assert(pcpui->cur_proc);        /* aka, current */
46                 proc_restartcore();
47                 assert(0);
48         }
49         /* if we made it here, we truly want to idle */
50         /* in the future, we may need to proactively leave process context here.
51          * for now, it is possible to have a current loaded, even if we are idle
52          * (and presumably about to execute a kmsg or fire up a vcore). */
53         if (!management_core()) {
54                 enable_irq();
55                 while (1) {
56                         process_routine_kmsg(0);
57                         cpu_halt();
58                 }
59         } else {
60                 enable_irqsave(&state);
61                 /* this makes us wait to enter the manager til any IO is done (totally
62                  * arbitrary 10ms), so we can handle the routine message that we
63                  * currently use to do the completion.  Note this also causes us to wait
64                  * 10ms regardless of how long the IO takes.  This all needs work. */
65                 //udelay(10000); /* done in the manager for now */
66                 process_routine_kmsg(0);
67                 disable_irqsave(&state);
68                 manager();
69         }
70         assert(0);
71 }
72
73 void smp_idle(void)
74 {
75         #ifdef __CONFIG_RESET_STACKS__
76         set_stack_pointer(get_stack_top());
77         #endif /* __CONFIG_RESET_STACKS__ */
78         __smp_idle();
79         assert(0);
80 }