ia64/xen-unstable

view xen/common/keyhandler.c @ 13423:ba239a4a7c3f

[XEN] 'd' key dumps both host and guest state.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Jan 12 17:39:26 2007 +0000 (2007-01-12)
parents 4c8f157a3a47
children b2c1eeee2dcf
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 <asm/debugger.h>
17 #include <asm/shadow.h>
18 #include <asm/div64.h>
20 #define KEY_MAX 256
21 #define STR_MAX 64
23 static struct {
24 union {
25 keyhandler_t *handler;
26 irq_keyhandler_t *irq_handler;
27 } u;
28 unsigned int flags;
29 char desc[STR_MAX];
30 } key_table[KEY_MAX];
32 #define KEYHANDLER_IRQ_CALLBACK 0x1
34 static unsigned char keypress_key;
36 static void keypress_softirq(void)
37 {
38 keyhandler_t *h;
39 unsigned char key = keypress_key;
40 console_start_log_everything();
41 if ( (h = key_table[key].u.handler) != NULL )
42 (*h)(key);
43 console_end_log_everything();
44 }
46 void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
47 {
48 irq_keyhandler_t *h;
50 if ( key_table[key].flags & KEYHANDLER_IRQ_CALLBACK )
51 {
52 console_start_log_everything();
53 if ( (h = key_table[key].u.irq_handler) != NULL )
54 (*h)(key, regs);
55 console_end_log_everything();
56 }
57 else
58 {
59 keypress_key = key;
60 raise_softirq(KEYPRESS_SOFTIRQ);
61 }
62 }
64 void register_keyhandler(
65 unsigned char key, keyhandler_t *handler, char *desc)
66 {
67 ASSERT(key_table[key].u.handler == NULL);
68 key_table[key].u.handler = handler;
69 key_table[key].flags = 0;
70 strncpy(key_table[key].desc, desc, STR_MAX);
71 key_table[key].desc[STR_MAX-1] = '\0';
72 }
74 void register_irq_keyhandler(
75 unsigned char key, irq_keyhandler_t *handler, char *desc)
76 {
77 ASSERT(key_table[key].u.irq_handler == NULL);
78 key_table[key].u.irq_handler = handler;
79 key_table[key].flags = KEYHANDLER_IRQ_CALLBACK;
80 strncpy(key_table[key].desc, desc, STR_MAX);
81 key_table[key].desc[STR_MAX-1] = '\0';
82 }
84 static void show_handlers(unsigned char key)
85 {
86 int i;
87 printk("'%c' pressed -> showing installed handlers\n", key);
88 for ( i = 0; i < KEY_MAX; i++ )
89 if ( key_table[i].u.handler != NULL )
90 printk(" key '%c' (ascii '%02x') => %s\n",
91 (i<33 || i>126)?(' '):(i),i,
92 key_table[i].desc);
93 }
95 static void __dump_execstate(void *unused)
96 {
97 dump_execution_state();
98 printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
99 if ( is_idle_vcpu(current) )
100 printk("No guest context (CPU is idle).\n");
101 else
102 show_execution_state(guest_cpu_user_regs());
103 }
105 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
106 {
107 unsigned int cpu;
109 printk("'%c' pressed -> dumping registers\n", key);
111 /* Get local execution state out immediately, in case we get stuck. */
112 printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
113 __dump_execstate(NULL);
115 for_each_online_cpu ( cpu )
116 {
117 if ( cpu == smp_processor_id() )
118 continue;
119 printk("\n*** Dumping CPU%d host state: ***\n", cpu);
120 on_selected_cpus(cpumask_of_cpu(cpu), __dump_execstate, NULL, 1, 1);
121 }
123 printk("\n");
124 }
126 static void halt_machine(unsigned char key, struct cpu_user_regs *regs)
127 {
128 printk("'%c' pressed -> rebooting machine\n", key);
129 machine_restart(NULL);
130 }
132 static void cpuset_print(char *set, int size, cpumask_t mask)
133 {
134 *set++ = '{';
135 set += cpulist_scnprintf(set, size-2, mask);
136 *set++ = '}';
137 *set++ = '\0';
138 }
140 static void dump_domains(unsigned char key)
141 {
142 struct domain *d;
143 struct vcpu *v;
144 s_time_t now = NOW();
145 char cpuset[100];
147 printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
148 (u32)(now>>32), (u32)now);
150 read_lock(&domlist_lock);
152 for_each_domain ( d )
153 {
154 printk("General information for domain %u:\n", d->domain_id);
155 cpuset_print(cpuset, sizeof(cpuset), d->domain_dirty_cpumask);
156 printk(" flags=%lx refcnt=%d nr_pages=%d xenheap_pages=%d "
157 "dirty_cpus=%s\n",
158 d->domain_flags, atomic_read(&d->refcnt),
159 d->tot_pages, d->xenheap_pages, cpuset);
160 printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
161 "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
162 d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
163 d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
164 d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
165 d->handle[12], d->handle[13], d->handle[14], d->handle[15],
166 d->vm_assist);
168 arch_dump_domain_info(d);
170 rangeset_domain_printk(d);
172 dump_pageframe_info(d);
174 printk("VCPU information and callbacks for domain %u:\n",
175 d->domain_id);
176 for_each_vcpu ( d, v ) {
177 printk(" VCPU%d: CPU%d [has=%c] flags=%lx "
178 "upcall_pend = %02x, upcall_mask = %02x ",
179 v->vcpu_id, v->processor,
180 test_bit(_VCPUF_running, &v->vcpu_flags) ? 'T':'F',
181 v->vcpu_flags,
182 vcpu_info(v, evtchn_upcall_pending),
183 vcpu_info(v, evtchn_upcall_mask));
184 cpuset_print(cpuset, sizeof(cpuset), v->vcpu_dirty_cpumask);
185 printk("dirty_cpus=%s ", cpuset);
186 cpuset_print(cpuset, sizeof(cpuset), v->cpu_affinity);
187 printk("cpu_affinity=%s\n", cpuset);
188 arch_dump_vcpu_info(v);
189 printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
190 VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
191 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
192 shared_info_addr(d, evtchn_pending)),
193 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
194 shared_info_addr(d, evtchn_mask)),
195 test_bit(v->virq_to_evtchn[VIRQ_DEBUG]/BITS_PER_GUEST_LONG(d),
196 vcpu_info_addr(v, evtchn_pending_sel)));
197 send_guest_vcpu_virq(v, VIRQ_DEBUG);
198 }
199 }
201 read_unlock(&domlist_lock);
202 }
204 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
205 static s_time_t read_clocks_time[NR_CPUS];
207 static void read_clocks_slave(void *unused)
208 {
209 unsigned int cpu = smp_processor_id();
210 while ( !cpu_isset(cpu, read_clocks_cpumask) )
211 cpu_relax();
212 read_clocks_time[cpu] = NOW();
213 cpu_clear(cpu, read_clocks_cpumask);
214 }
216 static void read_clocks(unsigned char key)
217 {
218 unsigned int cpu = smp_processor_id(), min_cpu, max_cpu;
219 u64 min, max, dif, difus;
220 static DEFINE_SPINLOCK(lock);
222 spin_lock(&lock);
224 smp_call_function(read_clocks_slave, NULL, 0, 0);
226 local_irq_disable();
227 read_clocks_cpumask = cpu_online_map;
228 read_clocks_time[cpu] = NOW();
229 cpu_clear(cpu, read_clocks_cpumask);
230 local_irq_enable();
232 while ( !cpus_empty(read_clocks_cpumask) )
233 cpu_relax();
235 min_cpu = max_cpu = cpu;
236 for_each_online_cpu ( cpu )
237 {
238 if ( read_clocks_time[cpu] < read_clocks_time[min_cpu] )
239 min_cpu = cpu;
240 if ( read_clocks_time[cpu] > read_clocks_time[max_cpu] )
241 max_cpu = cpu;
242 }
244 min = read_clocks_time[min_cpu];
245 max = read_clocks_time[max_cpu];
247 spin_unlock(&lock);
249 dif = difus = max - min;
250 do_div(difus, 1000);
251 printk("Min = %"PRIu64" ; Max = %"PRIu64" ; Diff = %"PRIu64
252 " (%"PRIu64" microseconds)\n",
253 min, max, dif, difus);
254 }
256 extern void dump_runq(unsigned char key);
258 #ifdef PERF_COUNTERS
259 extern void perfc_printall(unsigned char key);
260 extern void perfc_reset(unsigned char key);
261 #endif
263 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
264 {
265 (void)debugger_trap_fatal(0xf001, regs);
266 nop(); /* Prevent the compiler doing tail call
267 optimisation, as that confuses xendbg a
268 bit. */
269 }
271 void initialize_keytable(void)
272 {
273 open_softirq(KEYPRESS_SOFTIRQ, keypress_softirq);
275 register_irq_keyhandler(
276 'd', dump_registers, "dump registers");
277 register_keyhandler(
278 'h', show_handlers, "show this message");
279 register_keyhandler(
280 'q', dump_domains, "dump domain (and guest debug) info");
281 register_keyhandler(
282 'r', dump_runq, "dump run queues");
283 register_irq_keyhandler(
284 'R', halt_machine, "reboot machine");
286 register_keyhandler(
287 't', read_clocks, "display multi-cpu clock info");
289 #ifdef PERF_COUNTERS
290 register_keyhandler(
291 'p', perfc_printall, "print performance counters");
292 register_keyhandler(
293 'P', perfc_reset, "reset performance counters");
294 #endif
296 register_irq_keyhandler('%', do_debug_key, "Trap to xendbg");
297 }
299 /*
300 * Local variables:
301 * mode: C
302 * c-set-style: "BSD"
303 * c-basic-offset: 4
304 * tab-width: 4
305 * indent-tabs-mode: nil
306 * End:
307 */