rev |
line source |
kaf24@3008
|
1 /******************************************************************************
|
kaf24@3008
|
2 * keyhandler.c
|
kaf24@3008
|
3 */
|
kaf24@1098
|
4
|
cl349@3921
|
5 #include <asm/regs.h>
|
kaf24@1248
|
6 #include <xen/keyhandler.h>
|
kaf24@10989
|
7 #include <xen/shutdown.h>
|
kaf24@1248
|
8 #include <xen/event.h>
|
kaf24@1248
|
9 #include <xen/console.h>
|
kaf24@1248
|
10 #include <xen/serial.h>
|
mwilli2@1284
|
11 #include <xen/sched.h>
|
keir@21242
|
12 #include <xen/tasklet.h>
|
cl349@5285
|
13 #include <xen/domain.h>
|
kaf24@8486
|
14 #include <xen/rangeset.h>
|
ack@13294
|
15 #include <xen/compat.h>
|
keir@20048
|
16 #include <xen/ctype.h>
|
sos22@3801
|
17 #include <asm/debugger.h>
|
kaf24@9261
|
18 #include <asm/div64.h>
|
iap10@274
|
19
|
keir@20048
|
20 static struct keyhandler *key_table[256];
|
kaf24@2842
|
21 static unsigned char keypress_key;
|
keir@21350
|
22 static bool_t alt_key_handling;
|
kaf24@2842
|
23
|
keir@20982
|
24 char keyhandler_scratch[1024];
|
keir@20975
|
25
|
keir@17481
|
26 static void keypress_action(unsigned long unused)
|
kaf24@2842
|
27 {
|
keir@20975
|
28 handle_keypress(keypress_key, NULL);
|
kaf24@2842
|
29 }
|
kaf24@2842
|
30
|
keir@17481
|
31 static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
|
keir@17481
|
32
|
kaf24@4721
|
33 void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
|
kaf24@2842
|
34 {
|
keir@20048
|
35 struct keyhandler *h;
|
cl349@2988
|
36
|
keir@20048
|
37 if ( (h = key_table[key]) == NULL )
|
keir@20048
|
38 return;
|
keir@20048
|
39
|
keir@20048
|
40 if ( !in_irq() || h->irq_callback )
|
kaf24@3008
|
41 {
|
keir@17896
|
42 console_start_log_everything();
|
keir@20975
|
43 h->irq_callback ? (*h->u.irq_fn)(key, regs) : (*h->u.fn)(key);
|
keir@17896
|
44 console_end_log_everything();
|
kaf24@3008
|
45 }
|
cl349@2988
|
46 else
|
kaf24@3008
|
47 {
|
kaf24@3008
|
48 keypress_key = key;
|
keir@17481
|
49 tasklet_schedule(&keypress_tasklet);
|
kaf24@3008
|
50 }
|
kaf24@2842
|
51 }
|
kaf24@2842
|
52
|
keir@20048
|
53 void register_keyhandler(unsigned char key, struct keyhandler *handler)
|
kaf24@1584
|
54 {
|
keir@20048
|
55 ASSERT(key_table[key] == NULL);
|
keir@20048
|
56 key_table[key] = handler;
|
cl349@2988
|
57 }
|
cl349@2988
|
58
|
kaf24@2842
|
59 static void show_handlers(unsigned char key)
|
iap10@274
|
60 {
|
shand@11173
|
61 int i;
|
kaf24@1584
|
62 printk("'%c' pressed -> showing installed handlers\n", key);
|
keir@20048
|
63 for ( i = 0; i < ARRAY_SIZE(key_table); i++ )
|
keir@20048
|
64 if ( key_table[i] != NULL )
|
kaf24@1464
|
65 printk(" key '%c' (ascii '%02x') => %s\n",
|
keir@20048
|
66 isprint(i) ? i : ' ', i, key_table[i]->desc);
|
iap10@274
|
67 }
|
iap10@274
|
68
|
keir@20048
|
69 static struct keyhandler show_handlers_keyhandler = {
|
keir@20048
|
70 .u.fn = show_handlers,
|
keir@20048
|
71 .desc = "show this message"
|
keir@20048
|
72 };
|
keir@20048
|
73
|
keir@21355
|
74 static cpumask_t dump_execstate_mask;
|
keir@21355
|
75
|
keir@21355
|
76 void dump_execstate(struct cpu_user_regs *regs)
|
kfraser@10485
|
77 {
|
keir@21355
|
78 unsigned int cpu = smp_processor_id();
|
keir@21355
|
79
|
keir@21355
|
80 if ( !guest_mode(regs) )
|
keir@21355
|
81 {
|
keir@21355
|
82 printk("*** Dumping CPU%u host state: ***\n", cpu);
|
keir@21355
|
83 show_execution_state(regs);
|
keir@21355
|
84 }
|
keir@21355
|
85
|
keir@21355
|
86 if ( !is_idle_vcpu(current) )
|
keir@21355
|
87 {
|
keir@21355
|
88 printk("*** Dumping CPU%u guest state (d%d:v%d): ***\n",
|
keir@21355
|
89 smp_processor_id(), current->domain->domain_id,
|
keir@21355
|
90 current->vcpu_id);
|
kfraser@13408
|
91 show_execution_state(guest_cpu_user_regs());
|
keir@21355
|
92 printk("\n");
|
keir@21355
|
93 }
|
keir@21355
|
94
|
keir@21355
|
95 cpu_clear(cpu, dump_execstate_mask);
|
keir@21355
|
96 if ( !alt_key_handling )
|
keir@21355
|
97 return;
|
keir@21355
|
98
|
keir@21355
|
99 cpu = cycle_cpu(cpu, dump_execstate_mask);
|
keir@21355
|
100 if ( cpu < NR_CPUS )
|
keir@21355
|
101 {
|
keir@21355
|
102 smp_send_state_dump(cpu);
|
keir@21355
|
103 return;
|
keir@21355
|
104 }
|
keir@21355
|
105
|
keir@21355
|
106 console_end_sync();
|
keir@21355
|
107 watchdog_enable();
|
kfraser@10485
|
108 }
|
kfraser@10485
|
109
|
kaf24@4721
|
110 static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
|
iap10@274
|
111 {
|
kfraser@10485
|
112 unsigned int cpu;
|
kfraser@10485
|
113
|
keir@17896
|
114 /* We want to get everything out that we possibly can. */
|
keir@20678
|
115 watchdog_disable();
|
keir@17896
|
116 console_start_sync();
|
keir@17896
|
117
|
keir@21355
|
118 printk("'%c' pressed -> dumping registers\n\n", key);
|
keir@21355
|
119
|
keir@21355
|
120 dump_execstate_mask = cpu_online_map;
|
kfraser@10485
|
121
|
kfraser@10485
|
122 /* Get local execution state out immediately, in case we get stuck. */
|
keir@21355
|
123 dump_execstate(regs);
|
kfraser@10485
|
124
|
keir@21355
|
125 /* Alt. handling: remaining CPUs are dumped asynchronously one-by-one. */
|
keir@21355
|
126 if ( alt_key_handling )
|
keir@21355
|
127 return;
|
keir@21355
|
128
|
keir@21355
|
129 /* Normal handling: synchronously dump the remaining CPUs' states. */
|
keir@21355
|
130 for_each_cpu_mask ( cpu, dump_execstate_mask )
|
kfraser@10485
|
131 {
|
keir@21355
|
132 smp_send_state_dump(cpu);
|
keir@21355
|
133 while ( cpu_isset(cpu, dump_execstate_mask) )
|
keir@21355
|
134 cpu_relax();
|
kfraser@10485
|
135 }
|
kfraser@13408
|
136
|
keir@17896
|
137 console_end_sync();
|
keir@20678
|
138 watchdog_enable();
|
iap10@274
|
139 }
|
iap10@274
|
140
|
keir@20048
|
141 static struct keyhandler dump_registers_keyhandler = {
|
keir@20048
|
142 .irq_callback = 1,
|
keir@20048
|
143 .diagnostic = 1,
|
keir@20048
|
144 .u.irq_fn = dump_registers,
|
keir@20048
|
145 .desc = "dump registers"
|
keir@20048
|
146 };
|
keir@20048
|
147
|
keir@21350
|
148 static DECLARE_TASKLET(dump_dom0_tasklet, NULL, 0);
|
keir@21350
|
149
|
keir@21350
|
150 static void dump_dom0_action(unsigned long arg)
|
keir@21350
|
151 {
|
keir@21350
|
152 struct vcpu *v = (void *)arg;
|
keir@21350
|
153
|
keir@21350
|
154 for ( ; ; )
|
keir@21350
|
155 {
|
keir@21350
|
156 vcpu_show_execution_state(v);
|
keir@21350
|
157 if ( (v = v->next_in_list) == NULL )
|
keir@21350
|
158 break;
|
keir@21350
|
159 if ( softirq_pending(smp_processor_id()) )
|
keir@21350
|
160 {
|
keir@21350
|
161 dump_dom0_tasklet.data = (unsigned long)v;
|
keir@21350
|
162 tasklet_schedule_on_cpu(&dump_dom0_tasklet, v->processor);
|
keir@21350
|
163 break;
|
keir@21350
|
164 }
|
keir@21350
|
165 }
|
keir@21350
|
166 }
|
keir@21350
|
167
|
keir@17880
|
168 static void dump_dom0_registers(unsigned char key)
|
keir@17880
|
169 {
|
keir@17880
|
170 struct vcpu *v;
|
keir@17880
|
171
|
keir@17880
|
172 if ( dom0 == NULL )
|
keir@17880
|
173 return;
|
keir@17880
|
174
|
keir@17880
|
175 printk("'%c' pressed -> dumping Dom0's registers\n", key);
|
keir@17880
|
176
|
keir@17880
|
177 for_each_vcpu ( dom0, v )
|
keir@21350
|
178 {
|
keir@21350
|
179 if ( alt_key_handling && softirq_pending(smp_processor_id()) )
|
keir@21350
|
180 {
|
keir@21350
|
181 tasklet_kill(&dump_dom0_tasklet);
|
keir@21350
|
182 tasklet_init(&dump_dom0_tasklet, dump_dom0_action,
|
keir@21350
|
183 (unsigned long)v);
|
keir@21350
|
184 tasklet_schedule_on_cpu(&dump_dom0_tasklet, v->processor);
|
keir@21350
|
185 return;
|
keir@21350
|
186 }
|
keir@17880
|
187 vcpu_show_execution_state(v);
|
keir@21350
|
188 }
|
keir@17880
|
189 }
|
keir@17880
|
190
|
keir@20048
|
191 static struct keyhandler dump_dom0_registers_keyhandler = {
|
keir@20048
|
192 .diagnostic = 1,
|
keir@20048
|
193 .u.fn = dump_dom0_registers,
|
keir@20048
|
194 .desc = "dump Dom0 registers"
|
keir@20048
|
195 };
|
keir@20048
|
196
|
keir@20048
|
197 static void reboot_machine(unsigned char key, struct cpu_user_regs *regs)
|
iap10@274
|
198 {
|
shand@11173
|
199 printk("'%c' pressed -> rebooting machine\n", key);
|
keir@18251
|
200 machine_restart(0);
|
iap10@274
|
201 }
|
iap10@274
|
202
|
keir@20048
|
203 static struct keyhandler reboot_machine_keyhandler = {
|
keir@20048
|
204 .irq_callback = 1,
|
keir@20048
|
205 .u.irq_fn = reboot_machine,
|
keir@20048
|
206 .desc = "reboot machine"
|
keir@20048
|
207 };
|
keir@20048
|
208
|
kaf24@8550
|
209 static void cpuset_print(char *set, int size, cpumask_t mask)
|
kaf24@8550
|
210 {
|
kaf24@8550
|
211 *set++ = '{';
|
kaf24@8550
|
212 set += cpulist_scnprintf(set, size-2, mask);
|
kaf24@8550
|
213 *set++ = '}';
|
kaf24@8550
|
214 *set++ = '\0';
|
kaf24@8550
|
215 }
|
kaf24@8550
|
216
|
kfraser@14363
|
217 static void periodic_timer_print(char *str, int size, uint64_t period)
|
kfraser@14363
|
218 {
|
kfraser@14363
|
219 if ( period == 0 )
|
kfraser@14363
|
220 {
|
kfraser@14363
|
221 strlcpy(str, "No periodic timer", size);
|
kfraser@14363
|
222 return;
|
kfraser@14363
|
223 }
|
kfraser@14363
|
224
|
kfraser@14363
|
225 snprintf(str, size,
|
kfraser@14363
|
226 "%u Hz periodic timer (period %u ms)",
|
kfraser@14363
|
227 1000000000/(int)period, (int)period/1000000);
|
kfraser@14363
|
228 }
|
kfraser@14363
|
229
|
kaf24@8550
|
230 static void dump_domains(unsigned char key)
|
iap10@274
|
231 {
|
kaf24@1584
|
232 struct domain *d;
|
kaf24@7416
|
233 struct vcpu *v;
|
kaf24@1580
|
234 s_time_t now = NOW();
|
keir@20975
|
235 #define tmpstr keyhandler_scratch
|
iap10@274
|
236
|
kaf24@8550
|
237 printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
|
shand@11173
|
238 (u32)(now>>32), (u32)now);
|
kaf24@817
|
239
|
kfraser@14074
|
240 rcu_read_lock(&domlist_read_lock);
|
kaf24@817
|
241
|
kaf24@1580
|
242 for_each_domain ( d )
|
kaf24@1161
|
243 {
|
keir@21575
|
244 unsigned int i;
|
kaf24@8499
|
245 printk("General information for domain %u:\n", d->domain_id);
|
kfraser@14363
|
246 cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
|
keir@18759
|
247 printk(" refcnt=%d dying=%d nr_pages=%d xenheap_pages=%d "
|
keir@19055
|
248 "dirty_cpus=%s max_pages=%u\n",
|
keir@18759
|
249 atomic_read(&d->refcnt), d->is_dying,
|
keir@19055
|
250 d->tot_pages, d->xenheap_pages, tmpstr, d->max_pages);
|
kaf24@8499
|
251 printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
|
kaf24@10304
|
252 "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
|
kaf24@7416
|
253 d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
|
kaf24@7416
|
254 d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
|
kaf24@7416
|
255 d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
|
kaf24@10304
|
256 d->handle[12], d->handle[13], d->handle[14], d->handle[15],
|
kaf24@10304
|
257 d->vm_assist);
|
keir@21855
|
258 for ( i = 0 ; i < NR_DOMAIN_WATCHDOG_TIMERS; i++ )
|
keir@21575
|
259 if ( test_bit(i, &d->watchdog_inuse_map) )
|
keir@21575
|
260 printk(" watchdog %d expires in %d seconds\n",
|
keir@21575
|
261 i, (u32)((d->watchdog_timer[i].expires - NOW()) >> 30));
|
kaf24@8993
|
262
|
kaf24@8993
|
263 arch_dump_domain_info(d);
|
kaf24@1678
|
264
|
kaf24@8486
|
265 rangeset_domain_printk(d);
|
kaf24@8486
|
266
|
kaf24@3515
|
267 dump_pageframe_info(d);
|
kaf24@1678
|
268
|
kaf24@8499
|
269 printk("VCPU information and callbacks for domain %u:\n",
|
kaf24@8499
|
270 d->domain_id);
|
keir@21855
|
271 for_each_vcpu ( d, v )
|
keir@21855
|
272 {
|
keir@18566
|
273 printk(" VCPU%d: CPU%d [has=%c] flags=%lx poll=%d "
|
kaf24@8550
|
274 "upcall_pend = %02x, upcall_mask = %02x ",
|
kaf24@8499
|
275 v->vcpu_id, v->processor,
|
kfraser@14692
|
276 v->is_running ? 'T':'F',
|
keir@18566
|
277 v->pause_flags, v->poll_evtchn,
|
keir@20430
|
278 vcpu_info(v, evtchn_upcall_pending),
|
keir@20430
|
279 vcpu_info(v, evtchn_upcall_mask));
|
kfraser@14363
|
280 cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
|
kfraser@14363
|
281 printk("dirty_cpus=%s ", tmpstr);
|
kfraser@14363
|
282 cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
|
kfraser@14363
|
283 printk("cpu_affinity=%s\n", tmpstr);
|
Tim@11889
|
284 arch_dump_vcpu_info(v);
|
kfraser@14363
|
285 periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
|
kfraser@14363
|
286 printk(" %s\n", tmpstr);
|
keir@21855
|
287 }
|
keir@21855
|
288 }
|
keir@21855
|
289
|
keir@21855
|
290 for_each_domain ( d )
|
keir@21855
|
291 {
|
keir@21855
|
292 for_each_vcpu ( d, v )
|
keir@21855
|
293 {
|
keir@21855
|
294 printk("Notifying guest %d:%d (virq %d, port %d, stat %d/%d/%d)\n",
|
keir@21855
|
295 d->domain_id, v->vcpu_id,
|
kaf24@5327
|
296 VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
|
kaf24@5327
|
297 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
|
keir@17232
|
298 &shared_info(d, evtchn_pending)),
|
kaf24@5327
|
299 test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
|
keir@17232
|
300 &shared_info(d, evtchn_mask)),
|
kfraser@14363
|
301 test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
|
keir@19304
|
302 BITS_PER_EVTCHN_WORD(d),
|
keir@17232
|
303 &vcpu_info(v, evtchn_pending_sel)));
|
kaf24@9582
|
304 send_guest_vcpu_virq(v, VIRQ_DEBUG);
|
cl349@2957
|
305 }
|
kaf24@1161
|
306 }
|
iap10@274
|
307
|
kfraser@14074
|
308 rcu_read_unlock(&domlist_read_lock);
|
keir@20975
|
309 #undef tmpstr
|
iap10@274
|
310 }
|
iap10@274
|
311
|
keir@20048
|
312 static struct keyhandler dump_domains_keyhandler = {
|
keir@20048
|
313 .diagnostic = 1,
|
keir@20048
|
314 .u.fn = dump_domains,
|
keir@20048
|
315 .desc = "dump domain (and guest debug) info"
|
keir@20048
|
316 };
|
keir@20048
|
317
|
kaf24@9261
|
318 static cpumask_t read_clocks_cpumask = CPU_MASK_NONE;
|
keir@21810
|
319 static DEFINE_PER_CPU(s_time_t, read_clocks_time);
|
keir@21810
|
320 static DEFINE_PER_CPU(u64, read_cycles_time);
|
kaf24@9261
|
321
|
kaf24@9261
|
322 static void read_clocks_slave(void *unused)
|
kaf24@9261
|
323 {
|
kaf24@9261
|
324 unsigned int cpu = smp_processor_id();
|
keir@18138
|
325 local_irq_disable();
|
kaf24@9261
|
326 while ( !cpu_isset(cpu, read_clocks_cpumask) )
|
kaf24@9261
|
327 cpu_relax();
|
keir@21810
|
328 per_cpu(read_clocks_time, cpu) = NOW();
|
keir@21810
|
329 per_cpu(read_cycles_time, cpu) = get_cycles();
|
kaf24@9261
|
330 cpu_clear(cpu, read_clocks_cpumask);
|
keir@18138
|
331 local_irq_enable();
|
kaf24@9261
|
332 }
|
kaf24@9261
|
333
|
kaf24@9261
|
334 static void read_clocks(unsigned char key)
|
kaf24@9261
|
335 {
|
keir@18189
|
336 unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
|
keir@18189
|
337 unsigned int min_cycles_cpu, max_cycles_cpu;
|
keir@18189
|
338 u64 min_stime, max_stime, dif_stime;
|
keir@18189
|
339 u64 min_cycles, max_cycles, dif_cycles;
|
keir@18189
|
340 static u64 sumdif_stime = 0, maxdif_stime = 0;
|
keir@18189
|
341 static u64 sumdif_cycles = 0, maxdif_cycles = 0;
|
keir@18189
|
342 static u32 count = 0;
|
kaf24@9261
|
343 static DEFINE_SPINLOCK(lock);
|
kaf24@9261
|
344
|
kaf24@9261
|
345 spin_lock(&lock);
|
kaf24@9261
|
346
|
keir@19690
|
347 smp_call_function(read_clocks_slave, NULL, 0);
|
kaf24@9261
|
348
|
kaf24@9261
|
349 local_irq_disable();
|
kaf24@9261
|
350 read_clocks_cpumask = cpu_online_map;
|
keir@21810
|
351 per_cpu(read_clocks_time, cpu) = NOW();
|
keir@21810
|
352 per_cpu(read_cycles_time, cpu) = get_cycles();
|
kaf24@9261
|
353 cpu_clear(cpu, read_clocks_cpumask);
|
kaf24@9261
|
354 local_irq_enable();
|
kaf24@9261
|
355
|
kaf24@9261
|
356 while ( !cpus_empty(read_clocks_cpumask) )
|
kaf24@9261
|
357 cpu_relax();
|
kaf24@9261
|
358
|
keir@18189
|
359 min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
|
kaf24@9261
|
360 for_each_online_cpu ( cpu )
|
kaf24@9261
|
361 {
|
keir@21810
|
362 if ( per_cpu(read_clocks_time, cpu) <
|
keir@21810
|
363 per_cpu(read_clocks_time, min_stime_cpu) )
|
keir@18189
|
364 min_stime_cpu = cpu;
|
keir@21810
|
365 if ( per_cpu(read_clocks_time, cpu) >
|
keir@21810
|
366 per_cpu(read_clocks_time, max_stime_cpu) )
|
keir@18189
|
367 max_stime_cpu = cpu;
|
keir@21810
|
368 if ( per_cpu(read_cycles_time, cpu) <
|
keir@21810
|
369 per_cpu(read_cycles_time, min_cycles_cpu) )
|
keir@18189
|
370 min_cycles_cpu = cpu;
|
keir@21810
|
371 if ( per_cpu(read_cycles_time, cpu) >
|
keir@21810
|
372 per_cpu(read_cycles_time, max_cycles_cpu) )
|
keir@18189
|
373 max_cycles_cpu = cpu;
|
kaf24@9261
|
374 }
|
kaf24@9261
|
375
|
keir@21810
|
376 min_stime = per_cpu(read_clocks_time, min_stime_cpu);
|
keir@21810
|
377 max_stime = per_cpu(read_clocks_time, max_stime_cpu);
|
keir@21810
|
378 min_cycles = per_cpu(read_cycles_time, min_cycles_cpu);
|
keir@21810
|
379 max_cycles = per_cpu(read_cycles_time, max_cycles_cpu);
|
kaf24@9261
|
380
|
kaf24@9261
|
381 spin_unlock(&lock);
|
kaf24@9261
|
382
|
keir@18189
|
383 dif_stime = max_stime - min_stime;
|
keir@18189
|
384 if ( dif_stime > maxdif_stime )
|
keir@18189
|
385 maxdif_stime = dif_stime;
|
keir@18189
|
386 sumdif_stime += dif_stime;
|
keir@18189
|
387 dif_cycles = max_cycles - min_cycles;
|
keir@18189
|
388 if ( dif_cycles > maxdif_cycles )
|
keir@18189
|
389 maxdif_cycles = dif_cycles;
|
keir@18189
|
390 sumdif_cycles += dif_cycles;
|
keir@18189
|
391 count++;
|
keir@18189
|
392 printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
|
keir@18189
|
393 "samples=%"PRIu32" current=%"PRIu64"ns\n",
|
keir@18189
|
394 maxdif_stime, sumdif_stime/count, count, dif_stime);
|
keir@18189
|
395 printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
|
keir@18189
|
396 "samples=%"PRIu32" current=%"PRIu64"\n",
|
keir@18189
|
397 maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
|
kaf24@9261
|
398 }
|
kaf24@9261
|
399
|
keir@20048
|
400 static struct keyhandler read_clocks_keyhandler = {
|
keir@20048
|
401 .diagnostic = 1,
|
keir@20048
|
402 .u.fn = read_clocks,
|
keir@20048
|
403 .desc = "display multi-cpu clock info"
|
keir@20048
|
404 };
|
keir@20048
|
405
|
kaf24@2842
|
406 extern void dump_runq(unsigned char key);
|
keir@20048
|
407 static struct keyhandler dump_runq_keyhandler = {
|
keir@20048
|
408 .diagnostic = 1,
|
keir@20048
|
409 .u.fn = dump_runq,
|
keir@20048
|
410 .desc = "dump run queues"
|
keir@20048
|
411 };
|
iap10@2479
|
412
|
kaf24@1482
|
413 #ifdef PERF_COUNTERS
|
kaf24@2842
|
414 extern void perfc_printall(unsigned char key);
|
keir@20048
|
415 static struct keyhandler perfc_printall_keyhandler = {
|
keir@20048
|
416 .diagnostic = 1,
|
keir@20048
|
417 .u.fn = perfc_printall,
|
keir@20048
|
418 .desc = "print performance counters"
|
keir@20048
|
419 };
|
kaf24@2842
|
420 extern void perfc_reset(unsigned char key);
|
keir@20048
|
421 static struct keyhandler perfc_reset_keyhandler = {
|
keir@20048
|
422 .u.fn = perfc_reset,
|
keir@20048
|
423 .desc = "reset performance counters"
|
keir@20048
|
424 };
|
kaf24@1312
|
425 #endif
|
rn@340
|
426
|
keir@20350
|
427 #ifdef LOCK_PROFILE
|
keir@20350
|
428 extern void spinlock_profile_printall(unsigned char key);
|
keir@20350
|
429 static struct keyhandler spinlock_printall_keyhandler = {
|
keir@20350
|
430 .diagnostic = 1,
|
keir@20350
|
431 .u.fn = spinlock_profile_printall,
|
keir@20350
|
432 .desc = "print lock profile info"
|
keir@20350
|
433 };
|
keir@20350
|
434 extern void spinlock_profile_reset(unsigned char key);
|
keir@20350
|
435 static struct keyhandler spinlock_reset_keyhandler = {
|
keir@20350
|
436 .u.fn = spinlock_profile_reset,
|
keir@20350
|
437 .desc = "reset lock profile info"
|
keir@20350
|
438 };
|
keir@20350
|
439 #endif
|
keir@20350
|
440
|
keir@20048
|
441 static void run_all_nonirq_keyhandlers(unsigned long unused)
|
keir@20048
|
442 {
|
keir@20048
|
443 /* Fire all the non-IRQ-context diagnostic keyhandlers */
|
keir@20048
|
444 struct keyhandler *h;
|
keir@20048
|
445 int k;
|
keir@20048
|
446
|
keir@22677
|
447 console_start_log_everything();
|
keir@22677
|
448
|
keir@20048
|
449 for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
|
keir@20048
|
450 {
|
keir@22584
|
451 process_pending_softirqs();
|
keir@20048
|
452 h = key_table[k];
|
keir@20048
|
453 if ( (h == NULL) || !h->diagnostic || h->irq_callback )
|
keir@20048
|
454 continue;
|
keir@20048
|
455 printk("[%c: %s]\n", k, h->desc);
|
keir@20048
|
456 (*h->u.fn)(k);
|
keir@20048
|
457 }
|
keir@22677
|
458
|
keir@22677
|
459 console_end_log_everything();
|
keir@20048
|
460 }
|
keir@20048
|
461
|
keir@20048
|
462 static DECLARE_TASKLET(run_all_keyhandlers_tasklet,
|
keir@20048
|
463 run_all_nonirq_keyhandlers, 0);
|
keir@20048
|
464
|
keir@20048
|
465 static void run_all_keyhandlers(unsigned char key, struct cpu_user_regs *regs)
|
keir@20048
|
466 {
|
keir@20048
|
467 struct keyhandler *h;
|
keir@20048
|
468 int k;
|
keir@20048
|
469
|
keir@22584
|
470 watchdog_disable();
|
keir@22584
|
471
|
keir@20048
|
472 printk("'%c' pressed -> firing all diagnostic keyhandlers\n", key);
|
keir@20048
|
473
|
keir@20048
|
474 /* Fire all the IRQ-context diangostic keyhandlers now */
|
keir@20048
|
475 for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
|
keir@20048
|
476 {
|
keir@20048
|
477 h = key_table[k];
|
keir@20048
|
478 if ( (h == NULL) || !h->diagnostic || !h->irq_callback )
|
keir@20048
|
479 continue;
|
keir@20048
|
480 printk("[%c: %s]\n", k, h->desc);
|
keir@20048
|
481 (*h->u.irq_fn)(k, regs);
|
keir@20048
|
482 }
|
keir@22584
|
483
|
keir@22584
|
484 watchdog_enable();
|
keir@20048
|
485
|
keir@20048
|
486 /* Trigger the others from a tasklet in non-IRQ context */
|
keir@20048
|
487 tasklet_schedule(&run_all_keyhandlers_tasklet);
|
keir@20048
|
488 }
|
keir@20048
|
489
|
keir@20048
|
490 static struct keyhandler run_all_keyhandlers_keyhandler = {
|
keir@20048
|
491 .irq_callback = 1,
|
keir@20048
|
492 .u.irq_fn = run_all_keyhandlers,
|
keir@20048
|
493 .desc = "print all diagnostics"
|
keir@20048
|
494 };
|
keir@20048
|
495
|
kaf24@9261
|
496 static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
|
sos22@1989
|
497 {
|
keir@16634
|
498 printk("'%c' pressed -> trapping into debugger\n", key);
|
sos22@3814
|
499 (void)debugger_trap_fatal(0xf001, regs);
|
iap10@3871
|
500 nop(); /* Prevent the compiler doing tail call
|
sos22@3801
|
501 optimisation, as that confuses xendbg a
|
sos22@3801
|
502 bit. */
|
sos22@1989
|
503 }
|
sos22@1989
|
504
|
keir@20048
|
505 static struct keyhandler do_debug_key_keyhandler = {
|
keir@20048
|
506 .irq_callback = 1,
|
keir@20048
|
507 .u.irq_fn = do_debug_key,
|
keir@20048
|
508 .desc = "trap to xendbg"
|
keir@20048
|
509 };
|
keir@20048
|
510
|
keir@21350
|
511 static void do_toggle_alt_key(unsigned char key, struct cpu_user_regs *regs)
|
keir@21350
|
512 {
|
keir@21350
|
513 alt_key_handling = !alt_key_handling;
|
keir@21350
|
514 printk("'%c' pressed -> using %s key handling\n", key,
|
keir@21350
|
515 alt_key_handling ? "alternative" : "normal");
|
keir@21350
|
516 }
|
keir@21350
|
517
|
keir@21350
|
518 static struct keyhandler toggle_alt_keyhandler = {
|
keir@21350
|
519 .irq_callback = 1,
|
keir@21350
|
520 .u.irq_fn = do_toggle_alt_key,
|
keir@21350
|
521 .desc = "toggle alternative key handling"
|
keir@21350
|
522 };
|
keir@21350
|
523
|
keir@15081
|
524 void __init initialize_keytable(void)
|
iap10@274
|
525 {
|
keir@21350
|
526 if ( num_present_cpus() > 16 )
|
keir@21350
|
527 {
|
keir@21350
|
528 alt_key_handling = 1;
|
keir@21350
|
529 printk(XENLOG_INFO "Defaulting to alternative key handling; "
|
keir@21350
|
530 "send 'A' to switch to normal mode.\n");
|
keir@21350
|
531 }
|
keir@21350
|
532 register_keyhandler('A', &toggle_alt_keyhandler);
|
keir@20048
|
533 register_keyhandler('d', &dump_registers_keyhandler);
|
keir@20048
|
534 register_keyhandler('h', &show_handlers_keyhandler);
|
keir@20048
|
535 register_keyhandler('q', &dump_domains_keyhandler);
|
keir@20048
|
536 register_keyhandler('r', &dump_runq_keyhandler);
|
keir@20048
|
537 register_keyhandler('R', &reboot_machine_keyhandler);
|
keir@20048
|
538 register_keyhandler('t', &read_clocks_keyhandler);
|
keir@20048
|
539 register_keyhandler('0', &dump_dom0_registers_keyhandler);
|
keir@20048
|
540 register_keyhandler('%', &do_debug_key_keyhandler);
|
keir@20048
|
541 register_keyhandler('*', &run_all_keyhandlers_keyhandler);
|
kaf24@9261
|
542
|
kaf24@1482
|
543 #ifdef PERF_COUNTERS
|
keir@20048
|
544 register_keyhandler('p', &perfc_printall_keyhandler);
|
keir@20048
|
545 register_keyhandler('P', &perfc_reset_keyhandler);
|
kaf24@1312
|
546 #endif
|
keir@20350
|
547
|
keir@20350
|
548 #ifdef LOCK_PROFILE
|
keir@20350
|
549 register_keyhandler('l', &spinlock_printall_keyhandler);
|
keir@20350
|
550 register_keyhandler('L', &spinlock_reset_keyhandler);
|
keir@20350
|
551 #endif
|
keir@20350
|
552
|
iap10@274
|
553 }
|
kaf24@3952
|
554
|
kaf24@3952
|
555 /*
|
kaf24@3952
|
556 * Local variables:
|
kaf24@3952
|
557 * mode: C
|
kaf24@3952
|
558 * c-set-style: "BSD"
|
kaf24@3952
|
559 * c-basic-offset: 4
|
kaf24@3952
|
560 * tab-width: 4
|
kaf24@3952
|
561 * indent-tabs-mode: nil
|
kaf24@4026
|
562 * End:
|
kaf24@3952
|
563 */
|