1
#include <xeno/keyhandler.h>
2
#include <xeno/reboot.h>
7
typedef struct _key_te {
12
static key_te_t key_table[KEY_MAX];
14
void add_key_handler(u_char key, key_handler *handler, char *desc)
19
if(key_table[key].handler != NULL)
20
printk("Warning: overwriting handler for key 0x%x\n", key);
22
key_table[key].handler = handler;
24
str = key_table[key].desc;
25
for(i = 0; i < STR_MAX; i++) {
31
key_table[key].desc[STR_MAX-1] = '\0';
36
key_handler *get_key_handler(u_char key)
38
return key_table[key].handler;
42
static void show_handlers(u_char key, void *dev_id, struct pt_regs *regs)
46
printk("'%c' pressed -> showing installed handlers\n", key);
47
for(i=0; i < KEY_MAX; i++)
48
if(key_table[i].handler)
49
printk(" key '%c' (ascii '%02x') => %s\n",
50
(i<33 || i>126)?(' '):(i),i,
56
static void dump_registers(u_char key, void *dev_id, struct pt_regs *regs)
58
extern void show_registers(struct pt_regs *regs);
60
printk("'%c' pressed -> dumping registers\n", key);
65
static void halt_machine(u_char key, void *dev_id, struct pt_regs *regs)
67
printk("'%c' pressed -> rebooting machine\n", key);
68
machine_restart(NULL);
72
static void kill_dom0(u_char key, void *dev_id, struct pt_regs *regs)
74
printk("'%c' pressed -> gracefully rebooting machine\n", key);
75
kill_other_domain(0, 0);
80
/* XXX SMH: this is keir's fault */
81
static char *task_states[] =
84
"Interruptible Sleep",
85
"Uninterruptible Sleep",
87
NULL, NULL, NULL, "Dying",
90
void do_task_queues(u_char key, void *dev_id, struct pt_regs *regs)
93
struct task_struct *p;
97
printk("'%c' pressed -> dumping task queues\n", key);
99
read_lock_irqsave(&tasklist_lock, flags);
103
printk("Xen: DOM %d, CPU %d [has=%c], state = %s, "
104
"hyp_events = %08x\n",
105
p->domain, p->processor, p->has_cpu ? 'T':'F',
106
task_states[p->state], p->hyp_events);
108
if( !is_idle_task(p) )
110
printk("Guest: events = %08lx, events_mask = %08lx\n",
111
s->events, s->events_mask);
113
if ( (v = find_vif_by_id((p->domain)<<VIF_DOMAIN_SHIFT)) != NULL )
115
printk("rx_prod=%d ,rx_cons=%d, tx_prod=%d, tx_cons=%d\n",
116
v->rx_prod, v->rx_cons, v->tx_prod, v->tx_cons );
117
printk("rx_req_cons=%d, rx_resp_prod=%d, "
118
"tx_req_cons=%d, tx_resp_prod=%d\n",
119
v->rx_req_cons, v->rx_resp_prod,
120
v->tx_req_cons, v->tx_resp_prod);
123
printk("Notifying guest...\n");
124
set_bit(_EVENT_DEBUG, &s->events);
126
} while ( (p = p->next_task) != &idle0_task );
128
read_unlock_irqrestore(&tasklist_lock, flags);
131
extern void perfc_printall (u_char key, void *dev_id, struct pt_regs *regs);
132
extern void perfc_reset (u_char key, void *dev_id, struct pt_regs *regs);
133
extern void dump_runq(u_char key, void *dev_id, struct pt_regs *regs);
134
extern void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
135
extern void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
138
void initialize_keytable()
142
/* first initialize key handler table */
143
for(i = 0; i < KEY_MAX; i++)
144
key_table[i].handler = (key_handler *)NULL;
146
/* setup own handlers */
147
add_key_handler('d', dump_registers, "dump registers");
148
add_key_handler('h', show_handlers, "show this message");
149
add_key_handler('l', print_sched_histo, "print sched latency histogram");
150
add_key_handler('L', reset_sched_histo, "reset sched latency histogram");
151
add_key_handler('p', perfc_printall, "print performance counters");
152
add_key_handler('P', perfc_reset, "reset performance counters");
153
add_key_handler('q', do_task_queues, "dump task queues + guest state");
154
add_key_handler('r', dump_runq, "dump run queues");
155
add_key_handler('B', kill_dom0, "reboot machine gracefully");
156
add_key_handler('R', halt_machine, "reboot machine ungracefully");
1
/******************************************************************************
6
#include <xen/keyhandler.h>
7
#include <xen/shutdown.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[1024];
25
static void keypress_action(unsigned long unused)
27
handle_keypress(keypress_key, NULL);
30
static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
32
void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
36
if ( (h = key_table[key]) == NULL )
39
if ( !in_irq() || h->irq_callback )
41
console_start_log_everything();
42
h->irq_callback ? (*h->u.irq_fn)(key, regs) : (*h->u.fn)(key);
43
console_end_log_everything();
48
tasklet_schedule(&keypress_tasklet);
52
void register_keyhandler(unsigned char key, struct keyhandler *handler)
54
ASSERT(key_table[key] == NULL);
55
key_table[key] = handler;
58
static void show_handlers(unsigned char key)
61
printk("'%c' pressed -> showing installed handlers\n", key);
62
for ( i = 0; i < ARRAY_SIZE(key_table); i++ )
63
if ( key_table[i] != NULL )
64
printk(" key '%c' (ascii '%02x') => %s\n",
65
isprint(i) ? i : ' ', i, key_table[i]->desc);
68
static struct keyhandler show_handlers_keyhandler = {
69
.u.fn = show_handlers,
70
.desc = "show this message"
73
static void __dump_execstate(void *unused)
75
dump_execution_state();
76
printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
77
if ( is_idle_vcpu(current) )
78
printk("No guest context (CPU is idle).\n");
80
show_execution_state(guest_cpu_user_regs());
83
static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
87
/* We want to get everything out that we possibly can. */
91
printk("'%c' pressed -> dumping registers\n", key);
93
/* Get local execution state out immediately, in case we get stuck. */
94
printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
95
__dump_execstate(NULL);
97
for_each_online_cpu ( cpu )
99
if ( cpu == smp_processor_id() )
101
printk("\n*** Dumping CPU%d host state: ***\n", cpu);
102
on_selected_cpus(cpumask_of(cpu), __dump_execstate, NULL, 1);
111
static struct keyhandler dump_registers_keyhandler = {
114
.u.irq_fn = dump_registers,
115
.desc = "dump registers"
118
static void dump_dom0_registers(unsigned char key)
125
printk("'%c' pressed -> dumping Dom0's registers\n", key);
127
for_each_vcpu ( dom0, v )
128
vcpu_show_execution_state(v);
131
static struct keyhandler dump_dom0_registers_keyhandler = {
133
.u.fn = dump_dom0_registers,
134
.desc = "dump Dom0 registers"
137
static void reboot_machine(unsigned char key, struct cpu_user_regs *regs)
139
printk("'%c' pressed -> rebooting machine\n", key);
143
static struct keyhandler reboot_machine_keyhandler = {
145
.u.irq_fn = reboot_machine,
146
.desc = "reboot machine"
149
static void cpuset_print(char *set, int size, cpumask_t mask)
152
set += cpulist_scnprintf(set, size-2, mask);
157
static void periodic_timer_print(char *str, int size, uint64_t period)
161
strlcpy(str, "No periodic timer", size);
166
"%u Hz periodic timer (period %u ms)",
167
1000000000/(int)period, (int)period/1000000);
170
static void dump_domains(unsigned char key)
174
s_time_t now = NOW();
175
#define tmpstr keyhandler_scratch
177
printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
178
(u32)(now>>32), (u32)now);
180
rcu_read_lock(&domlist_read_lock);
182
for_each_domain ( d )
184
printk("General information for domain %u:\n", d->domain_id);
185
cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
186
printk(" refcnt=%d dying=%d nr_pages=%d xenheap_pages=%d "
187
"dirty_cpus=%s max_pages=%u\n",
188
atomic_read(&d->refcnt), d->is_dying,
189
d->tot_pages, d->xenheap_pages, tmpstr, d->max_pages);
190
printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
191
"%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
192
d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
193
d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
194
d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
195
d->handle[12], d->handle[13], d->handle[14], d->handle[15],
198
arch_dump_domain_info(d);
200
rangeset_domain_printk(d);
202
dump_pageframe_info(d);
204
printk("VCPU information and callbacks for domain %u:\n",
206
for_each_vcpu ( d, v ) {
207
printk(" VCPU%d: CPU%d [has=%c] flags=%lx poll=%d "
208
"upcall_pend = %02x, upcall_mask = %02x ",
209
v->vcpu_id, v->processor,
210
v->is_running ? 'T':'F',
211
v->pause_flags, v->poll_evtchn,
212
vcpu_info(v, evtchn_upcall_pending),
213
vcpu_info(v, evtchn_upcall_mask));
214
cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
215
printk("dirty_cpus=%s ", tmpstr);
216
cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
217
printk("cpu_affinity=%s\n", tmpstr);
218
arch_dump_vcpu_info(v);
219
periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
220
printk(" %s\n", tmpstr);
221
printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
222
VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
223
test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
224
&shared_info(d, evtchn_pending)),
225
test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
226
&shared_info(d, evtchn_mask)),
227
test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
228
BITS_PER_EVTCHN_WORD(d),
229
&vcpu_info(v, evtchn_pending_sel)));
230
send_guest_vcpu_virq(v, VIRQ_DEBUG);
234
rcu_read_unlock(&domlist_read_lock);
238
static struct keyhandler dump_domains_keyhandler = {
240
.u.fn = dump_domains,
241
.desc = "dump domain (and guest debug) info"
244
static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
245
static s_time_t read_clocks_time[NR_CPUS];
246
static u64 read_cycles_time[NR_CPUS];
248
static void read_clocks_slave(void *unused)
250
unsigned int cpu = smp_processor_id();
252
while ( !cpu_isset(cpu, read_clocks_cpumask) )
254
read_clocks_time[cpu] = NOW();
255
read_cycles_time[cpu] = get_cycles();
256
cpu_clear(cpu, read_clocks_cpumask);
260
static void read_clocks(unsigned char key)
262
unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
263
unsigned int min_cycles_cpu, max_cycles_cpu;
264
u64 min_stime, max_stime, dif_stime;
265
u64 min_cycles, max_cycles, dif_cycles;
266
static u64 sumdif_stime = 0, maxdif_stime = 0;
267
static u64 sumdif_cycles = 0, maxdif_cycles = 0;
268
static u32 count = 0;
269
static DEFINE_SPINLOCK(lock);
273
smp_call_function(read_clocks_slave, NULL, 0);
276
read_clocks_cpumask = cpu_online_map;
277
read_clocks_time[cpu] = NOW();
278
read_cycles_time[cpu] = get_cycles();
279
cpu_clear(cpu, read_clocks_cpumask);
282
while ( !cpus_empty(read_clocks_cpumask) )
285
min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
286
for_each_online_cpu ( cpu )
288
if ( read_clocks_time[cpu] < read_clocks_time[min_stime_cpu] )
290
if ( read_clocks_time[cpu] > read_clocks_time[max_stime_cpu] )
292
if ( read_cycles_time[cpu] < read_cycles_time[min_cycles_cpu] )
293
min_cycles_cpu = cpu;
294
if ( read_cycles_time[cpu] > read_cycles_time[max_cycles_cpu] )
295
max_cycles_cpu = cpu;
298
min_stime = read_clocks_time[min_stime_cpu];
299
max_stime = read_clocks_time[max_stime_cpu];
300
min_cycles = read_cycles_time[min_cycles_cpu];
301
max_cycles = read_cycles_time[max_cycles_cpu];
305
dif_stime = max_stime - min_stime;
306
if ( dif_stime > maxdif_stime )
307
maxdif_stime = dif_stime;
308
sumdif_stime += dif_stime;
309
dif_cycles = max_cycles - min_cycles;
310
if ( dif_cycles > maxdif_cycles )
311
maxdif_cycles = dif_cycles;
312
sumdif_cycles += dif_cycles;
314
printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
315
"samples=%"PRIu32" current=%"PRIu64"ns\n",
316
maxdif_stime, sumdif_stime/count, count, dif_stime);
317
printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
318
"samples=%"PRIu32" current=%"PRIu64"\n",
319
maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
322
static struct keyhandler read_clocks_keyhandler = {
325
.desc = "display multi-cpu clock info"
328
extern void dump_runq(unsigned char key);
329
static struct keyhandler dump_runq_keyhandler = {
332
.desc = "dump run queues"
336
extern void perfc_printall(unsigned char key);
337
static struct keyhandler perfc_printall_keyhandler = {
339
.u.fn = perfc_printall,
340
.desc = "print performance counters"
342
extern void perfc_reset(unsigned char key);
343
static struct keyhandler perfc_reset_keyhandler = {
345
.desc = "reset performance counters"
350
extern void spinlock_profile_printall(unsigned char key);
351
static struct keyhandler spinlock_printall_keyhandler = {
353
.u.fn = spinlock_profile_printall,
354
.desc = "print lock profile info"
356
extern void spinlock_profile_reset(unsigned char key);
357
static struct keyhandler spinlock_reset_keyhandler = {
358
.u.fn = spinlock_profile_reset,
359
.desc = "reset lock profile info"
363
static void run_all_nonirq_keyhandlers(unsigned long unused)
365
/* Fire all the non-IRQ-context diagnostic keyhandlers */
366
struct keyhandler *h;
369
console_start_log_everything();
370
for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
373
if ( (h == NULL) || !h->diagnostic || h->irq_callback )
375
printk("[%c: %s]\n", k, h->desc);
378
console_end_log_everything();
381
static DECLARE_TASKLET(run_all_keyhandlers_tasklet,
382
run_all_nonirq_keyhandlers, 0);
384
static void run_all_keyhandlers(unsigned char key, struct cpu_user_regs *regs)
386
struct keyhandler *h;
389
printk("'%c' pressed -> firing all diagnostic keyhandlers\n", key);
391
/* Fire all the IRQ-context diangostic keyhandlers now */
392
console_start_log_everything();
393
for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
396
if ( (h == NULL) || !h->diagnostic || !h->irq_callback )
398
printk("[%c: %s]\n", k, h->desc);
399
(*h->u.irq_fn)(k, regs);
401
console_end_log_everything();
403
/* Trigger the others from a tasklet in non-IRQ context */
404
tasklet_schedule(&run_all_keyhandlers_tasklet);
407
static struct keyhandler run_all_keyhandlers_keyhandler = {
409
.u.irq_fn = run_all_keyhandlers,
410
.desc = "print all diagnostics"
413
static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
415
printk("'%c' pressed -> trapping into debugger\n", key);
416
(void)debugger_trap_fatal(0xf001, regs);
417
nop(); /* Prevent the compiler doing tail call
418
optimisation, as that confuses xendbg a
422
static struct keyhandler do_debug_key_keyhandler = {
424
.u.irq_fn = do_debug_key,
425
.desc = "trap to xendbg"
428
void __init initialize_keytable(void)
430
register_keyhandler('d', &dump_registers_keyhandler);
431
register_keyhandler('h', &show_handlers_keyhandler);
432
register_keyhandler('q', &dump_domains_keyhandler);
433
register_keyhandler('r', &dump_runq_keyhandler);
434
register_keyhandler('R', &reboot_machine_keyhandler);
435
register_keyhandler('t', &read_clocks_keyhandler);
436
register_keyhandler('0', &dump_dom0_registers_keyhandler);
437
register_keyhandler('%', &do_debug_key_keyhandler);
438
register_keyhandler('*', &run_all_keyhandlers_keyhandler);
441
register_keyhandler('p', &perfc_printall_keyhandler);
442
register_keyhandler('P', &perfc_reset_keyhandler);
446
register_keyhandler('l', &spinlock_printall_keyhandler);
447
register_keyhandler('L', &spinlock_reset_keyhandler);
458
* indent-tabs-mode: nil