debuggers.hg

view xen/common/keyhandler.c @ 20975:bd0d6ec8caaa

keyhandler: global shared scratch space for temporary strings

Put one static definition in one place and we can make it as big as we
think reasonable.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 11 21:08:06 2010 +0000 (2010-02-11)
parents 40a598cb0e91
children a4ddf47a1e91
line source
1 /******************************************************************************
2 * keyhandler.c
3 */
5 #include <asm/regs.h>
6 #include <xen/keyhandler.h>
7 #include <xen/shutdown.h>
8 #include <xen/event.h>
9 #include <xen/console.h>
10 #include <xen/serial.h>
11 #include <xen/sched.h>
12 #include <xen/softirq.h>
13 #include <xen/domain.h>
14 #include <xen/rangeset.h>
15 #include <xen/compat.h>
16 #include <xen/ctype.h>
17 #include <asm/debugger.h>
18 #include <asm/div64.h>
20 static struct keyhandler *key_table[256];
21 static unsigned char keypress_key;
23 char keyhandler_scratch[100];
25 static void keypress_action(unsigned long unused)
26 {
27 handle_keypress(keypress_key, NULL);
28 }
30 static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
32 void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
33 {
34 static bool_t executing_handler;
35 struct keyhandler *h;
37 if ( (h = key_table[key]) == NULL )
38 return;
40 if ( !in_irq() || h->irq_callback )
41 {
42 /*
43 * No concurrent handler execution: prevents garbled console and
44 * protects keyhandler_scratch[].
45 */
46 if ( test_and_set_bool(executing_handler) )
47 return;
48 wmb();
49 console_start_log_everything();
50 h->irq_callback ? (*h->u.irq_fn)(key, regs) : (*h->u.fn)(key);
51 console_end_log_everything();
52 wmb();
53 executing_handler = 0;
54 }
55 else
56 {
57 keypress_key = key;
58 tasklet_schedule(&keypress_tasklet);
59 }
60 }
62 void register_keyhandler(unsigned char key, struct keyhandler *handler)
63 {
64 ASSERT(key_table[key] == NULL);
65 key_table[key] = handler;
66 }
68 static void show_handlers(unsigned char key)
69 {
70 int i;
71 printk("'%c' pressed -> showing installed handlers\n", key);
72 for ( i = 0; i < ARRAY_SIZE(key_table); i++ )
73 if ( key_table[i] != NULL )
74 printk(" key '%c' (ascii '%02x') => %s\n",
75 isprint(i) ? i : ' ', i, key_table[i]->desc);
76 }
78 static struct keyhandler show_handlers_keyhandler = {
79 .u.fn = show_handlers,
80 .desc = "show this message"
81 };
83 static void __dump_execstate(void *unused)
84 {
85 dump_execution_state();
86 printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
87 if ( is_idle_vcpu(current) )
88 printk("No guest context (CPU is idle).\n");
89 else
90 show_execution_state(guest_cpu_user_regs());
91 }
93 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
94 {
95 unsigned int cpu;
97 /* We want to get everything out that we possibly can. */
98 watchdog_disable();
99 console_start_sync();
101 printk("'%c' pressed -> dumping registers\n", key);
103 /* Get local execution state out immediately, in case we get stuck. */
104 printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
105 __dump_execstate(NULL);
107 for_each_online_cpu ( cpu )
108 {
109 if ( cpu == smp_processor_id() )
110 continue;
111 printk("\n*** Dumping CPU%d host state: ***\n", cpu);
112 on_selected_cpus(cpumask_of(cpu), __dump_execstate, NULL, 1);
113 }
115 printk("\n");
117 console_end_sync();
118 watchdog_enable();
119 }
121 static struct keyhandler dump_registers_keyhandler = {
122 .irq_callback = 1,
123 .diagnostic = 1,
124 .u.irq_fn = dump_registers,
125 .desc = "dump registers"
126 };
128 static void dump_dom0_registers(unsigned char key)
129 {
130 struct vcpu *v;
132 if ( dom0 == NULL )
133 return;
135 printk("'%c' pressed -> dumping Dom0's registers\n", key);
137 for_each_vcpu ( dom0, v )
138 vcpu_show_execution_state(v);
139 }
141 static struct keyhandler dump_dom0_registers_keyhandler = {
142 .diagnostic = 1,
143 .u.fn = dump_dom0_registers,
144 .desc = "dump Dom0 registers"
145 };
147 static void reboot_machine(unsigned char key, struct cpu_user_regs *regs)
148 {
149 printk("'%c' pressed -> rebooting machine\n", key);
150 machine_restart(0);
151 }
153 static struct keyhandler reboot_machine_keyhandler = {
154 .irq_callback = 1,
155 .u.irq_fn = reboot_machine,
156 .desc = "reboot machine"
157 };
159 static void cpuset_print(char *set, int size, cpumask_t mask)
160 {
161 *set++ = '{';
162 set += cpulist_scnprintf(set, size-2, mask);
163 *set++ = '}';
164 *set++ = '\0';
165 }
167 static void periodic_timer_print(char *str, int size, uint64_t period)
168 {
169 if ( period == 0 )
170 {
171 strlcpy(str, "No periodic timer", size);
172 return;
173 }
175 snprintf(str, size,
176 "%u Hz periodic timer (period %u ms)",
177 1000000000/(int)period, (int)period/1000000);
178 }
180 static void dump_domains(unsigned char key)
181 {
182 struct domain *d;
183 struct vcpu *v;
184 s_time_t now = NOW();
185 #define tmpstr keyhandler_scratch
187 printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
188 (u32)(now>>32), (u32)now);
190 rcu_read_lock(&domlist_read_lock);
192 for_each_domain ( d )
193 {
194 printk("General information for domain %u:\n", d->domain_id);
195 cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
196 printk(" refcnt=%d dying=%d nr_pages=%d xenheap_pages=%d "
197 "dirty_cpus=%s max_pages=%u\n",
198 atomic_read(&d->refcnt), d->is_dying,
199 d->tot_pages, d->xenheap_pages, tmpstr, d->max_pages);
200 printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
201 "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
202 d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
203 d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
204 d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
205 d->handle[12], d->handle[13], d->handle[14], d->handle[15],
206 d->vm_assist);
208 arch_dump_domain_info(d);
210 rangeset_domain_printk(d);
212 dump_pageframe_info(d);
214 printk("VCPU information and callbacks for domain %u:\n",
215 d->domain_id);
216 for_each_vcpu ( d, v ) {
217 printk(" VCPU%d: CPU%d [has=%c] flags=%lx poll=%d "
218 "upcall_pend = %02x, upcall_mask = %02x ",
219 v->vcpu_id, v->processor,
220 v->is_running ? 'T':'F',
221 v->pause_flags, v->poll_evtchn,
222 vcpu_info(v, evtchn_upcall_pending),
223 vcpu_info(v, evtchn_upcall_mask));
224 cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
225 printk("dirty_cpus=%s ", tmpstr);
226 cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
227 printk("cpu_affinity=%s\n", tmpstr);
228 arch_dump_vcpu_info(v);
229 periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
230 printk(" %s\n", tmpstr);
231 printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
232 VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
233 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
234 &shared_info(d, evtchn_pending)),
235 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
236 &shared_info(d, evtchn_mask)),
237 test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
238 BITS_PER_EVTCHN_WORD(d),
239 &vcpu_info(v, evtchn_pending_sel)));
240 send_guest_vcpu_virq(v, VIRQ_DEBUG);
241 }
242 }
244 rcu_read_unlock(&domlist_read_lock);
245 #undef tmpstr
246 }
248 static struct keyhandler dump_domains_keyhandler = {
249 .diagnostic = 1,
250 .u.fn = dump_domains,
251 .desc = "dump domain (and guest debug) info"
252 };
254 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
255 static s_time_t read_clocks_time[NR_CPUS];
256 static u64 read_cycles_time[NR_CPUS];
258 static void read_clocks_slave(void *unused)
259 {
260 unsigned int cpu = smp_processor_id();
261 local_irq_disable();
262 while ( !cpu_isset(cpu, read_clocks_cpumask) )
263 cpu_relax();
264 read_clocks_time[cpu] = NOW();
265 read_cycles_time[cpu] = get_cycles();
266 cpu_clear(cpu, read_clocks_cpumask);
267 local_irq_enable();
268 }
270 static void read_clocks(unsigned char key)
271 {
272 unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
273 unsigned int min_cycles_cpu, max_cycles_cpu;
274 u64 min_stime, max_stime, dif_stime;
275 u64 min_cycles, max_cycles, dif_cycles;
276 static u64 sumdif_stime = 0, maxdif_stime = 0;
277 static u64 sumdif_cycles = 0, maxdif_cycles = 0;
278 static u32 count = 0;
279 static DEFINE_SPINLOCK(lock);
281 spin_lock(&lock);
283 smp_call_function(read_clocks_slave, NULL, 0);
285 local_irq_disable();
286 read_clocks_cpumask = cpu_online_map;
287 read_clocks_time[cpu] = NOW();
288 read_cycles_time[cpu] = get_cycles();
289 cpu_clear(cpu, read_clocks_cpumask);
290 local_irq_enable();
292 while ( !cpus_empty(read_clocks_cpumask) )
293 cpu_relax();
295 min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
296 for_each_online_cpu ( cpu )
297 {
298 if ( read_clocks_time[cpu] < read_clocks_time[min_stime_cpu] )
299 min_stime_cpu = cpu;
300 if ( read_clocks_time[cpu] > read_clocks_time[max_stime_cpu] )
301 max_stime_cpu = cpu;
302 if ( read_cycles_time[cpu] < read_cycles_time[min_cycles_cpu] )
303 min_cycles_cpu = cpu;
304 if ( read_cycles_time[cpu] > read_cycles_time[max_cycles_cpu] )
305 max_cycles_cpu = cpu;
306 }
308 min_stime = read_clocks_time[min_stime_cpu];
309 max_stime = read_clocks_time[max_stime_cpu];
310 min_cycles = read_cycles_time[min_cycles_cpu];
311 max_cycles = read_cycles_time[max_cycles_cpu];
313 spin_unlock(&lock);
315 dif_stime = max_stime - min_stime;
316 if ( dif_stime > maxdif_stime )
317 maxdif_stime = dif_stime;
318 sumdif_stime += dif_stime;
319 dif_cycles = max_cycles - min_cycles;
320 if ( dif_cycles > maxdif_cycles )
321 maxdif_cycles = dif_cycles;
322 sumdif_cycles += dif_cycles;
323 count++;
324 printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
325 "samples=%"PRIu32" current=%"PRIu64"ns\n",
326 maxdif_stime, sumdif_stime/count, count, dif_stime);
327 printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
328 "samples=%"PRIu32" current=%"PRIu64"\n",
329 maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
330 }
332 static struct keyhandler read_clocks_keyhandler = {
333 .diagnostic = 1,
334 .u.fn = read_clocks,
335 .desc = "display multi-cpu clock info"
336 };
338 extern void dump_runq(unsigned char key);
339 static struct keyhandler dump_runq_keyhandler = {
340 .diagnostic = 1,
341 .u.fn = dump_runq,
342 .desc = "dump run queues"
343 };
345 #ifdef PERF_COUNTERS
346 extern void perfc_printall(unsigned char key);
347 static struct keyhandler perfc_printall_keyhandler = {
348 .diagnostic = 1,
349 .u.fn = perfc_printall,
350 .desc = "print performance counters"
351 };
352 extern void perfc_reset(unsigned char key);
353 static struct keyhandler perfc_reset_keyhandler = {
354 .u.fn = perfc_reset,
355 .desc = "reset performance counters"
356 };
357 #endif
359 #ifdef LOCK_PROFILE
360 extern void spinlock_profile_printall(unsigned char key);
361 static struct keyhandler spinlock_printall_keyhandler = {
362 .diagnostic = 1,
363 .u.fn = spinlock_profile_printall,
364 .desc = "print lock profile info"
365 };
366 extern void spinlock_profile_reset(unsigned char key);
367 static struct keyhandler spinlock_reset_keyhandler = {
368 .u.fn = spinlock_profile_reset,
369 .desc = "reset lock profile info"
370 };
371 #endif
373 static void run_all_nonirq_keyhandlers(unsigned long unused)
374 {
375 /* Fire all the non-IRQ-context diagnostic keyhandlers */
376 struct keyhandler *h;
377 int k;
379 console_start_log_everything();
380 for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
381 {
382 h = key_table[k];
383 if ( (h == NULL) || !h->diagnostic || h->irq_callback )
384 continue;
385 printk("[%c: %s]\n", k, h->desc);
386 (*h->u.fn)(k);
387 }
388 console_end_log_everything();
389 }
391 static DECLARE_TASKLET(run_all_keyhandlers_tasklet,
392 run_all_nonirq_keyhandlers, 0);
394 static void run_all_keyhandlers(unsigned char key, struct cpu_user_regs *regs)
395 {
396 struct keyhandler *h;
397 int k;
399 printk("'%c' pressed -> firing all diagnostic keyhandlers\n", key);
401 /* Fire all the IRQ-context diangostic keyhandlers now */
402 console_start_log_everything();
403 for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
404 {
405 h = key_table[k];
406 if ( (h == NULL) || !h->diagnostic || !h->irq_callback )
407 continue;
408 printk("[%c: %s]\n", k, h->desc);
409 (*h->u.irq_fn)(k, regs);
410 }
411 console_end_log_everything();
413 /* Trigger the others from a tasklet in non-IRQ context */
414 tasklet_schedule(&run_all_keyhandlers_tasklet);
415 }
417 static struct keyhandler run_all_keyhandlers_keyhandler = {
418 .irq_callback = 1,
419 .u.irq_fn = run_all_keyhandlers,
420 .desc = "print all diagnostics"
421 };
423 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
424 {
425 printk("'%c' pressed -> trapping into debugger\n", key);
426 (void)debugger_trap_fatal(0xf001, regs);
427 nop(); /* Prevent the compiler doing tail call
428 optimisation, as that confuses xendbg a
429 bit. */
430 }
432 static struct keyhandler do_debug_key_keyhandler = {
433 .irq_callback = 1,
434 .u.irq_fn = do_debug_key,
435 .desc = "trap to xendbg"
436 };
438 void __init initialize_keytable(void)
439 {
440 register_keyhandler('d', &dump_registers_keyhandler);
441 register_keyhandler('h', &show_handlers_keyhandler);
442 register_keyhandler('q', &dump_domains_keyhandler);
443 register_keyhandler('r', &dump_runq_keyhandler);
444 register_keyhandler('R', &reboot_machine_keyhandler);
445 register_keyhandler('t', &read_clocks_keyhandler);
446 register_keyhandler('0', &dump_dom0_registers_keyhandler);
447 register_keyhandler('%', &do_debug_key_keyhandler);
448 register_keyhandler('*', &run_all_keyhandlers_keyhandler);
450 #ifdef PERF_COUNTERS
451 register_keyhandler('p', &perfc_printall_keyhandler);
452 register_keyhandler('P', &perfc_reset_keyhandler);
453 #endif
455 #ifdef LOCK_PROFILE
456 register_keyhandler('l', &spinlock_printall_keyhandler);
457 register_keyhandler('L', &spinlock_reset_keyhandler);
458 #endif
460 }
462 /*
463 * Local variables:
464 * mode: C
465 * c-set-style: "BSD"
466 * c-basic-offset: 4
467 * tab-width: 4
468 * indent-tabs-mode: nil
469 * End:
470 */