ia64/xen-unstable

view xen/common/keyhandler.c @ 18594:5e4e234d58be

x86: Define __per_cpu_shift label to help kdump/crashdump.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 08 13:11:06 2008 +0100 (2008-10-08)
parents 81483e49c74c
children 15aed96c7b5c
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/div64.h>
19 #define KEY_MAX 256
20 #define STR_MAX 64
22 static struct {
23 union {
24 keyhandler_t *handler;
25 irq_keyhandler_t *irq_handler;
26 } u;
27 unsigned int flags;
28 char desc[STR_MAX];
29 } key_table[KEY_MAX];
31 #define KEYHANDLER_IRQ_CALLBACK 0x1
33 static unsigned char keypress_key;
35 static void keypress_action(unsigned long unused)
36 {
37 keyhandler_t *h;
38 unsigned char key = keypress_key;
39 console_start_log_everything();
40 if ( (h = key_table[key].u.handler) != NULL )
41 (*h)(key);
42 console_end_log_everything();
43 }
45 static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
47 void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
48 {
49 irq_keyhandler_t *h;
51 if ( !in_irq() || (key_table[key].flags & KEYHANDLER_IRQ_CALLBACK) )
52 {
53 console_start_log_everything();
54 if ( (h = key_table[key].u.irq_handler) != NULL )
55 (*h)(key, regs);
56 console_end_log_everything();
57 }
58 else
59 {
60 keypress_key = key;
61 tasklet_schedule(&keypress_tasklet);
62 }
63 }
65 void register_keyhandler(
66 unsigned char key, keyhandler_t *handler, char *desc)
67 {
68 ASSERT(key_table[key].u.handler == NULL);
69 key_table[key].u.handler = handler;
70 key_table[key].flags = 0;
71 safe_strcpy(key_table[key].desc, desc);
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 safe_strcpy(key_table[key].desc, desc);
81 }
83 static void show_handlers(unsigned char key)
84 {
85 int i;
86 printk("'%c' pressed -> showing installed handlers\n", key);
87 for ( i = 0; i < KEY_MAX; i++ )
88 if ( key_table[i].u.handler != NULL )
89 printk(" key '%c' (ascii '%02x') => %s\n",
90 (i<33 || i>126)?(' '):(i),i,
91 key_table[i].desc);
92 }
94 static void __dump_execstate(void *unused)
95 {
96 dump_execution_state();
97 printk("*** Dumping CPU%d guest state: ***\n", smp_processor_id());
98 if ( is_idle_vcpu(current) )
99 printk("No guest context (CPU is idle).\n");
100 else
101 show_execution_state(guest_cpu_user_regs());
102 }
104 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
105 {
106 unsigned int cpu;
108 /* We want to get everything out that we possibly can. */
109 console_start_sync();
111 printk("'%c' pressed -> dumping registers\n", key);
113 /* Get local execution state out immediately, in case we get stuck. */
114 printk("\n*** Dumping CPU%d host state: ***\n", smp_processor_id());
115 __dump_execstate(NULL);
117 for_each_online_cpu ( cpu )
118 {
119 if ( cpu == smp_processor_id() )
120 continue;
121 printk("\n*** Dumping CPU%d host state: ***\n", cpu);
122 on_selected_cpus(cpumask_of_cpu(cpu), __dump_execstate, NULL, 1, 1);
123 }
125 printk("\n");
127 console_end_sync();
128 }
130 static void dump_dom0_registers(unsigned char key)
131 {
132 struct vcpu *v;
134 if ( dom0 == NULL )
135 return;
137 printk("'%c' pressed -> dumping Dom0's registers\n", key);
139 for_each_vcpu ( dom0, v )
140 vcpu_show_execution_state(v);
141 }
143 static void halt_machine(unsigned char key, struct cpu_user_regs *regs)
144 {
145 printk("'%c' pressed -> rebooting machine\n", key);
146 machine_restart(0);
147 }
149 static void cpuset_print(char *set, int size, cpumask_t mask)
150 {
151 *set++ = '{';
152 set += cpulist_scnprintf(set, size-2, mask);
153 *set++ = '}';
154 *set++ = '\0';
155 }
157 static void periodic_timer_print(char *str, int size, uint64_t period)
158 {
159 if ( period == 0 )
160 {
161 strlcpy(str, "No periodic timer", size);
162 return;
163 }
165 snprintf(str, size,
166 "%u Hz periodic timer (period %u ms)",
167 1000000000/(int)period, (int)period/1000000);
168 }
170 static void dump_domains(unsigned char key)
171 {
172 struct domain *d;
173 struct vcpu *v;
174 s_time_t now = NOW();
175 char tmpstr[100];
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 )
183 {
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 nr_pages=%d xenheap_pages=%d "
187 "dirty_cpus=%s\n",
188 atomic_read(&d->refcnt),
189 d->tot_pages, d->xenheap_pages, tmpstr);
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],
196 d->vm_assist);
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",
205 d->domain_id);
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_GUEST_LONG(d),
229 &vcpu_info(v, evtchn_pending_sel)));
230 send_guest_vcpu_virq(v, VIRQ_DEBUG);
231 }
232 }
234 rcu_read_unlock(&domlist_read_lock);
235 }
237 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
238 static s_time_t read_clocks_time[NR_CPUS];
239 static u64 read_cycles_time[NR_CPUS];
241 static void read_clocks_slave(void *unused)
242 {
243 unsigned int cpu = smp_processor_id();
244 local_irq_disable();
245 while ( !cpu_isset(cpu, read_clocks_cpumask) )
246 cpu_relax();
247 read_clocks_time[cpu] = NOW();
248 read_cycles_time[cpu] = get_cycles();
249 cpu_clear(cpu, read_clocks_cpumask);
250 local_irq_enable();
251 }
253 static void read_clocks(unsigned char key)
254 {
255 unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
256 unsigned int min_cycles_cpu, max_cycles_cpu;
257 u64 min_stime, max_stime, dif_stime;
258 u64 min_cycles, max_cycles, dif_cycles;
259 static u64 sumdif_stime = 0, maxdif_stime = 0;
260 static u64 sumdif_cycles = 0, maxdif_cycles = 0;
261 static u32 count = 0;
262 static DEFINE_SPINLOCK(lock);
264 spin_lock(&lock);
266 smp_call_function(read_clocks_slave, NULL, 0, 0);
268 local_irq_disable();
269 read_clocks_cpumask = cpu_online_map;
270 read_clocks_time[cpu] = NOW();
271 read_cycles_time[cpu] = get_cycles();
272 cpu_clear(cpu, read_clocks_cpumask);
273 local_irq_enable();
275 while ( !cpus_empty(read_clocks_cpumask) )
276 cpu_relax();
278 min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
279 for_each_online_cpu ( cpu )
280 {
281 if ( read_clocks_time[cpu] < read_clocks_time[min_stime_cpu] )
282 min_stime_cpu = cpu;
283 if ( read_clocks_time[cpu] > read_clocks_time[max_stime_cpu] )
284 max_stime_cpu = cpu;
285 if ( read_cycles_time[cpu] < read_cycles_time[min_cycles_cpu] )
286 min_cycles_cpu = cpu;
287 if ( read_cycles_time[cpu] > read_cycles_time[max_cycles_cpu] )
288 max_cycles_cpu = cpu;
289 }
291 min_stime = read_clocks_time[min_stime_cpu];
292 max_stime = read_clocks_time[max_stime_cpu];
293 min_cycles = read_cycles_time[min_cycles_cpu];
294 max_cycles = read_cycles_time[max_cycles_cpu];
296 spin_unlock(&lock);
298 dif_stime = max_stime - min_stime;
299 if ( dif_stime > maxdif_stime )
300 maxdif_stime = dif_stime;
301 sumdif_stime += dif_stime;
302 dif_cycles = max_cycles - min_cycles;
303 if ( dif_cycles > maxdif_cycles )
304 maxdif_cycles = dif_cycles;
305 sumdif_cycles += dif_cycles;
306 count++;
307 printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
308 "samples=%"PRIu32" current=%"PRIu64"ns\n",
309 maxdif_stime, sumdif_stime/count, count, dif_stime);
310 printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
311 "samples=%"PRIu32" current=%"PRIu64"\n",
312 maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
313 }
315 extern void dump_runq(unsigned char key);
317 #ifdef PERF_COUNTERS
318 extern void perfc_printall(unsigned char key);
319 extern void perfc_reset(unsigned char key);
320 #endif
322 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
323 {
324 printk("'%c' pressed -> trapping into debugger\n", key);
325 (void)debugger_trap_fatal(0xf001, regs);
326 nop(); /* Prevent the compiler doing tail call
327 optimisation, as that confuses xendbg a
328 bit. */
329 }
331 void __init initialize_keytable(void)
332 {
333 register_irq_keyhandler(
334 'd', dump_registers, "dump registers");
335 register_keyhandler(
336 'h', show_handlers, "show this message");
337 register_keyhandler(
338 'q', dump_domains, "dump domain (and guest debug) info");
339 register_keyhandler(
340 'r', dump_runq, "dump run queues");
341 register_irq_keyhandler(
342 'R', halt_machine, "reboot machine");
344 register_keyhandler(
345 't', read_clocks, "display multi-cpu clock info");
347 #ifdef PERF_COUNTERS
348 register_keyhandler(
349 'p', perfc_printall, "print performance counters");
350 register_keyhandler(
351 'P', perfc_reset, "reset performance counters");
352 #endif
354 register_keyhandler(
355 '0', dump_dom0_registers, "dump Dom0 registers");
357 register_irq_keyhandler('%', do_debug_key, "Trap to xendbg");
358 }
360 /*
361 * Local variables:
362 * mode: C
363 * c-set-style: "BSD"
364 * c-basic-offset: 4
365 * tab-width: 4
366 * indent-tabs-mode: nil
367 * End:
368 */