2 * Copyright (c) 2009 The Regents of the University of California
3 * Barret Rhoden <brho@cs.berkeley.edu>
4 * See LICENSE for details.
11 #include <arch/arch.h>
26 struct per_cpu_info per_cpu_info[MAX_NUM_CPUS];
28 // tracks number of global waits on smp_calls, must be <= NUM_HANDLER_WRAPPERS
29 atomic_t outstanding_calls = 0;
31 /* Helper for running a proc (if we should). Lots of repetition with
33 static void try_run_proc(void)
35 struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
36 /* There was a process running here, and we should return to it. */
37 if (pcpui->owning_proc) {
38 assert(!pcpui->cur_kthread->sysc);
39 assert(pcpui->cur_ctx);
40 __proc_startcore(pcpui->owning_proc, pcpui->cur_ctx);
43 /* Make sure we have abandoned core. It's possible to have an owner
44 * without a current (smp_idle, __startcore, __death). */
49 /* All cores end up calling this whenever there is nothing left to do or they
50 * don't know explicitly what to do. Non-zero cores call it when they are done
51 * booting. Other cases include after getting a DEATH IPI.
53 * All cores attempt to run the context of any owning proc. Barring that, they
54 * halt and wake up when interrupted, do any work on their work queue, then halt
55 * again. In between, the ksched gets a chance to tell it to do something else,
56 * or perhaps to halt in another manner. */
57 static void __attribute__((noinline, noreturn)) __smp_idle(void)
59 struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
61 pcpui->cur_kthread->is_ktask = FALSE;
62 enable_irq(); /* one-shot change to get any IRQs before we halt later */
65 process_routine_kmsg();
67 cpu_bored(); /* call out to the ksched */
68 /* cpu_halt() atomically turns on interrupts and halts the core.
69 * Important to do this, since we could have a RKM come in via an
70 * interrupt right while PRKM is returning, and we wouldn't catch
72 __set_cpu_state(pcpui, CPU_STATE_IDLE);
74 /* interrupts are back on now (given our current semantics) */
81 #ifdef CONFIG_RESET_STACKS
82 set_stack_pointer(get_stack_top());
84 #endif /* CONFIG_RESET_STACKS */
89 /* Arch-independent per-cpu initialization. This will call the arch dependent
91 void smp_percpu_init(void)
93 uint32_t coreid = core_id();
94 struct per_cpu_info *pcpui = &per_cpu_info[coreid];
96 struct kthread *kthread;
97 /* Don't initialize __ctx_depth here, since it is already 1 (at least on
98 * x86), since this runs in irq context. */
100 __arch_pcpu_init(coreid);
101 /* init our kthread (tracks our currently running context) */
102 kthread = __kthread_zalloc();
103 kthread->stacktop = get_stack_top(); /* assumes we're on the 1st page */
104 pcpui->cur_kthread = kthread;
105 per_cpu_info[coreid].spare = 0;
106 /* Init relevant lists */
107 spinlock_init_irqsave(&per_cpu_info[coreid].immed_amsg_lock);
108 STAILQ_INIT(&per_cpu_info[coreid].immed_amsgs);
109 spinlock_init_irqsave(&per_cpu_info[coreid].routine_amsg_lock);
110 STAILQ_INIT(&per_cpu_info[coreid].routine_amsgs);
111 /* Initialize the per-core timer chain */
112 init_timer_chain(&per_cpu_info[coreid].tchain, set_pcpu_alarm_interrupt);
113 #ifdef CONFIG_KTHREAD_POISON
114 *kstack_bottom_addr(kthread->stacktop) = 0xdeadbeef;
115 #endif /* CONFIG_KTHREAD_POISON */
116 /* Init generic tracing ring */
117 trace_buf = kpage_alloc_addr();
119 trace_ring_init(&pcpui->traces, trace_buf, PGSIZE,
120 sizeof(struct pcpu_trace_event));
121 for (int i = 0; i < NR_CPU_STATES; i++)
122 pcpui->state_ticks[i] = 0;
123 pcpui->last_tick_cnt = read_tsc();
124 /* Core 0 is in the KERNEL state, called from smp_boot. The other cores are
125 * too, at least on x86, where we were called from asm (woken by POKE). */
126 pcpui->cpu_state = CPU_STATE_KERNEL;
127 /* Enable full lock debugging, after all pcpui work is done */
128 pcpui->__lock_checking_enabled = 1;
131 /* it's actually okay to set the state to the existing state. originally, it
132 * was a bug in the state tracking, but it is possible, at least on x86, to have
133 * a halted core (state IDLE) get woken up by an IRQ that does not trigger the
134 * IRQ handling state. for example, there is the I_POKE_CORE ipi. smp_idle
135 * will just sleep again, and reset the state from IDLE to IDLE. */
136 void __set_cpu_state(struct per_cpu_info *pcpui, int state)
139 assert(!irq_is_enabled());
140 /* TODO: could put in an option to enable/disable state tracking. */
141 now_ticks = read_tsc();
142 pcpui->state_ticks[pcpui->cpu_state] += now_ticks - pcpui->last_tick_cnt;
143 /* TODO: if the state was user, we could account for the vcore's time,
144 * similar to the total_ticks in struct vcore. the difference is that the
145 * total_ticks tracks the vcore's virtual time, while this tracks user time.
146 * something like vcore->user_ticks. */
147 pcpui->cpu_state = state;
148 pcpui->last_tick_cnt = now_ticks;
151 void reset_cpu_state_ticks(int coreid)
153 struct per_cpu_info *pcpui = &per_cpu_info[coreid];
155 if (coreid >= num_cpus)
157 /* need to update last_tick_cnt, so the current value doesn't get added in
158 * next time we update */
159 now_ticks = read_tsc();
160 for (int i = 0; i < NR_CPU_STATES; i++) {
161 pcpui->state_ticks[i] = 0;
162 pcpui->last_tick_cnt = now_ticks;
166 /* PCPUI Trace Rings: */
168 static void pcpui_trace_kmsg_handler(void *event, void *data)
170 struct pcpu_trace_event *te = (struct pcpu_trace_event*)event;
174 func_name = get_fn_name(addr);
175 printk("\tKMSG %p: %s\n", addr, func_name);
179 static void pcpui_trace_locks_handler(void *event, void *data)
181 struct pcpu_trace_event *te = (struct pcpu_trace_event*)event;
183 uintptr_t lock_addr = te->arg1;
184 if (lock_addr > KERN_LOAD_ADDR)
185 func_name = get_fn_name(lock_addr);
187 func_name = "Dynamic lock";
188 printk("Time %uus, lock %p (%s)\n", te->arg0, lock_addr, func_name);
190 spinlock_debug((spinlock_t*)lock_addr);
191 if (lock_addr > KERN_LOAD_ADDR)
195 /* Add specific trace handlers here: */
196 trace_handler_t pcpui_tr_handlers[PCPUI_NR_TYPES] = {
198 pcpui_trace_kmsg_handler,
199 pcpui_trace_locks_handler,
202 /* Generic handler for the pcpui ring. Will switch out to the appropriate
204 static void pcpui_trace_fn(void *event, void *data)
206 struct pcpu_trace_event *te = (struct pcpu_trace_event*)event;
207 int desired_type = (int)(long)data;
208 if (te->type >= PCPUI_NR_TYPES)
209 printk("Bad trace type %d\n", te->type);
210 /* desired_type == 0 means all types */
211 if (desired_type && desired_type != te->type)
213 if (pcpui_tr_handlers[te->type])
214 pcpui_tr_handlers[te->type](event, data);
217 void pcpui_tr_foreach(int coreid, int type)
219 struct trace_ring *tr = &per_cpu_info[coreid].traces;
221 printk("\n\nTrace Ring on Core %d\n--------------\n", coreid);
222 trace_ring_foreach(tr, pcpui_trace_fn, (void*)(long)type);
225 void pcpui_tr_foreach_all(int type)
227 for (int i = 0; i < num_cpus; i++)
228 pcpui_tr_foreach(i, type);
231 void pcpui_tr_reset_all(void)
233 for (int i = 0; i < num_cpus; i++)
234 trace_ring_reset(&per_cpu_info[i].traces);
237 void pcpui_tr_reset_and_clear_all(void)
239 for (int i = 0; i < num_cpus; i++)
240 trace_ring_reset_and_clear(&per_cpu_info[i].traces);