ia64/xen-unstable

view xen/common/keyhandler.c @ 17864:d4dcd4d39952

Bring back console_start_log_everything() as a milder alternative to
console_start_sync(). Revert keyhandler logic to use it. The
difference now is that serial logic is updated to not drop characters
if inb a log_everything region. Still this is milder than a sync
region since the async buffer must be filled before we start to
busy-wait on each character.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 13 14:15:00 2008 +0100 (2008-06-13)
parents 7eab5d8788a6
children c433ee4844fb
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();
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 "
208 "upcall_pend = %02x, upcall_mask = %02x ",
209 v->vcpu_id, v->processor,
210 v->is_running ? 'T':'F',
211 v->pause_flags,
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];
240 static void read_clocks_slave(void *unused)
241 {
242 unsigned int cpu = smp_processor_id();
243 while ( !cpu_isset(cpu, read_clocks_cpumask) )
244 cpu_relax();
245 read_clocks_time[cpu] = NOW();
246 cpu_clear(cpu, read_clocks_cpumask);
247 }
249 static void read_clocks(unsigned char key)
250 {
251 unsigned int cpu = smp_processor_id(), min_cpu, max_cpu;
252 u64 min, max, dif, difus;
253 static DEFINE_SPINLOCK(lock);
255 spin_lock(&lock);
257 smp_call_function(read_clocks_slave, NULL, 0, 0);
259 local_irq_disable();
260 read_clocks_cpumask = cpu_online_map;
261 read_clocks_time[cpu] = NOW();
262 cpu_clear(cpu, read_clocks_cpumask);
263 local_irq_enable();
265 while ( !cpus_empty(read_clocks_cpumask) )
266 cpu_relax();
268 min_cpu = max_cpu = cpu;
269 for_each_online_cpu ( cpu )
270 {
271 if ( read_clocks_time[cpu] < read_clocks_time[min_cpu] )
272 min_cpu = cpu;
273 if ( read_clocks_time[cpu] > read_clocks_time[max_cpu] )
274 max_cpu = cpu;
275 }
277 min = read_clocks_time[min_cpu];
278 max = read_clocks_time[max_cpu];
280 spin_unlock(&lock);
282 dif = difus = max - min;
283 do_div(difus, 1000);
284 printk("Min = %"PRIu64" ; Max = %"PRIu64" ; Diff = %"PRIu64
285 " (%"PRIu64" microseconds)\n",
286 min, max, dif, difus);
287 }
289 extern void dump_runq(unsigned char key);
291 #ifdef PERF_COUNTERS
292 extern void perfc_printall(unsigned char key);
293 extern void perfc_reset(unsigned char key);
294 #endif
296 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
297 {
298 printk("'%c' pressed -> trapping into debugger\n", key);
299 (void)debugger_trap_fatal(0xf001, regs);
300 nop(); /* Prevent the compiler doing tail call
301 optimisation, as that confuses xendbg a
302 bit. */
303 }
305 void __init initialize_keytable(void)
306 {
307 register_irq_keyhandler(
308 'd', dump_registers, "dump registers");
309 register_keyhandler(
310 'h', show_handlers, "show this message");
311 register_keyhandler(
312 'q', dump_domains, "dump domain (and guest debug) info");
313 register_keyhandler(
314 'r', dump_runq, "dump run queues");
315 register_irq_keyhandler(
316 'R', halt_machine, "reboot machine");
318 register_keyhandler(
319 't', read_clocks, "display multi-cpu clock info");
321 #ifdef PERF_COUNTERS
322 register_keyhandler(
323 'p', perfc_printall, "print performance counters");
324 register_keyhandler(
325 'P', perfc_reset, "reset performance counters");
326 #endif
328 register_keyhandler(
329 '0', dump_dom0_registers, "dump Dom0 registers");
331 register_irq_keyhandler('%', do_debug_key, "Trap to xendbg");
332 }
334 /*
335 * Local variables:
336 * mode: C
337 * c-set-style: "BSD"
338 * c-basic-offset: 4
339 * tab-width: 4
340 * indent-tabs-mode: nil
341 * End:
342 */