debuggers.hg

annotate xen/common/keyhandler.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents dca1b7cf2e2c
children
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 */