diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kgdb.c | 205 |
1 files changed, 103 insertions, 102 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c index 761fdd2b3034..11f3515ca83f 100644 --- a/kernel/kgdb.c +++ b/kernel/kgdb.c | |||
@@ -69,9 +69,16 @@ struct kgdb_state { | |||
69 | struct pt_regs *linux_regs; | 69 | struct pt_regs *linux_regs; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | /* Exception state values */ | ||
73 | #define DCPU_WANT_MASTER 0x1 /* Waiting to become a master kgdb cpu */ | ||
74 | #define DCPU_NEXT_MASTER 0x2 /* Transition from one master cpu to another */ | ||
75 | #define DCPU_IS_SLAVE 0x4 /* Slave cpu enter exception */ | ||
76 | #define DCPU_SSTEP 0x8 /* CPU is single stepping */ | ||
77 | |||
72 | static struct debuggerinfo_struct { | 78 | static struct debuggerinfo_struct { |
73 | void *debuggerinfo; | 79 | void *debuggerinfo; |
74 | struct task_struct *task; | 80 | struct task_struct *task; |
81 | int exception_state; | ||
75 | } kgdb_info[NR_CPUS]; | 82 | } kgdb_info[NR_CPUS]; |
76 | 83 | ||
77 | /** | 84 | /** |
@@ -391,27 +398,22 @@ int kgdb_mem2hex(char *mem, char *buf, int count) | |||
391 | 398 | ||
392 | /* | 399 | /* |
393 | * Copy the binary array pointed to by buf into mem. Fix $, #, and | 400 | * Copy the binary array pointed to by buf into mem. Fix $, #, and |
394 | * 0x7d escaped with 0x7d. Return a pointer to the character after | 401 | * 0x7d escaped with 0x7d. Return -EFAULT on failure or 0 on success. |
395 | * the last byte written. | 402 | * The input buf is overwitten with the result to write to mem. |
396 | */ | 403 | */ |
397 | static int kgdb_ebin2mem(char *buf, char *mem, int count) | 404 | static int kgdb_ebin2mem(char *buf, char *mem, int count) |
398 | { | 405 | { |
399 | int err = 0; | 406 | int size = 0; |
400 | char c; | 407 | char *c = buf; |
401 | 408 | ||
402 | while (count-- > 0) { | 409 | while (count-- > 0) { |
403 | c = *buf++; | 410 | c[size] = *buf++; |
404 | if (c == 0x7d) | 411 | if (c[size] == 0x7d) |
405 | c = *buf++ ^ 0x20; | 412 | c[size] = *buf++ ^ 0x20; |
406 | 413 | size++; | |
407 | err = probe_kernel_write(mem, &c, 1); | ||
408 | if (err) | ||
409 | break; | ||
410 | |||
411 | mem++; | ||
412 | } | 414 | } |
413 | 415 | ||
414 | return err; | 416 | return probe_kernel_write(mem, c, size); |
415 | } | 417 | } |
416 | 418 | ||
417 | /* | 419 | /* |
@@ -563,49 +565,6 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid) | |||
563 | } | 565 | } |
564 | 566 | ||
565 | /* | 567 | /* |
566 | * CPU debug state control: | ||
567 | */ | ||
568 | |||
569 | #ifdef CONFIG_SMP | ||
570 | static void kgdb_wait(struct pt_regs *regs) | ||
571 | { | ||
572 | unsigned long flags; | ||
573 | int cpu; | ||
574 | |||
575 | local_irq_save(flags); | ||
576 | cpu = raw_smp_processor_id(); | ||
577 | kgdb_info[cpu].debuggerinfo = regs; | ||
578 | kgdb_info[cpu].task = current; | ||
579 | /* | ||
580 | * Make sure the above info reaches the primary CPU before | ||
581 | * our cpu_in_kgdb[] flag setting does: | ||
582 | */ | ||
583 | smp_wmb(); | ||
584 | atomic_set(&cpu_in_kgdb[cpu], 1); | ||
585 | |||
586 | /* Disable any cpu specific hw breakpoints */ | ||
587 | kgdb_disable_hw_debug(regs); | ||
588 | |||
589 | /* Wait till primary CPU is done with debugging */ | ||
590 | while (atomic_read(&passive_cpu_wait[cpu])) | ||
591 | cpu_relax(); | ||
592 | |||
593 | kgdb_info[cpu].debuggerinfo = NULL; | ||
594 | kgdb_info[cpu].task = NULL; | ||
595 | |||
596 | /* fix up hardware debug registers on local cpu */ | ||
597 | if (arch_kgdb_ops.correct_hw_break) | ||
598 | arch_kgdb_ops.correct_hw_break(); | ||
599 | |||
600 | /* Signal the primary CPU that we are done: */ | ||
601 | atomic_set(&cpu_in_kgdb[cpu], 0); | ||
602 | touch_softlockup_watchdog_sync(); | ||
603 | clocksource_touch_watchdog(); | ||
604 | local_irq_restore(flags); | ||
605 | } | ||
606 | #endif | ||
607 | |||
608 | /* | ||
609 | * Some architectures need cache flushes when we set/clear a | 568 | * Some architectures need cache flushes when we set/clear a |
610 | * breakpoint: | 569 | * breakpoint: |
611 | */ | 570 | */ |
@@ -1400,34 +1359,13 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | |||
1400 | return 1; | 1359 | return 1; |
1401 | } | 1360 | } |
1402 | 1361 | ||
1403 | /* | 1362 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) |
1404 | * kgdb_handle_exception() - main entry point from a kernel exception | ||
1405 | * | ||
1406 | * Locking hierarchy: | ||
1407 | * interface locks, if any (begin_session) | ||
1408 | * kgdb lock (kgdb_active) | ||
1409 | */ | ||
1410 | int | ||
1411 | kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | ||
1412 | { | 1363 | { |
1413 | struct kgdb_state kgdb_var; | ||
1414 | struct kgdb_state *ks = &kgdb_var; | ||
1415 | unsigned long flags; | 1364 | unsigned long flags; |
1416 | int sstep_tries = 100; | 1365 | int sstep_tries = 100; |
1417 | int error = 0; | 1366 | int error = 0; |
1418 | int i, cpu; | 1367 | int i, cpu; |
1419 | 1368 | int trace_on = 0; | |
1420 | ks->cpu = raw_smp_processor_id(); | ||
1421 | ks->ex_vector = evector; | ||
1422 | ks->signo = signo; | ||
1423 | ks->ex_vector = evector; | ||
1424 | ks->err_code = ecode; | ||
1425 | ks->kgdb_usethreadid = 0; | ||
1426 | ks->linux_regs = regs; | ||
1427 | |||
1428 | if (kgdb_reenter_check(ks)) | ||
1429 | return 0; /* Ouch, double exception ! */ | ||
1430 | |||
1431 | acquirelock: | 1369 | acquirelock: |
1432 | /* | 1370 | /* |
1433 | * Interrupts will be restored by the 'trap return' code, except when | 1371 | * Interrupts will be restored by the 'trap return' code, except when |
@@ -1435,13 +1373,43 @@ acquirelock: | |||
1435 | */ | 1373 | */ |
1436 | local_irq_save(flags); | 1374 | local_irq_save(flags); |
1437 | 1375 | ||
1438 | cpu = raw_smp_processor_id(); | 1376 | cpu = ks->cpu; |
1377 | kgdb_info[cpu].debuggerinfo = regs; | ||
1378 | kgdb_info[cpu].task = current; | ||
1379 | /* | ||
1380 | * Make sure the above info reaches the primary CPU before | ||
1381 | * our cpu_in_kgdb[] flag setting does: | ||
1382 | */ | ||
1383 | atomic_inc(&cpu_in_kgdb[cpu]); | ||
1439 | 1384 | ||
1440 | /* | 1385 | /* |
1441 | * Acquire the kgdb_active lock: | 1386 | * CPU will loop if it is a slave or request to become a kgdb |
1387 | * master cpu and acquire the kgdb_active lock: | ||
1442 | */ | 1388 | */ |
1443 | while (atomic_cmpxchg(&kgdb_active, -1, cpu) != -1) | 1389 | while (1) { |
1390 | if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | ||
1391 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | ||
1392 | break; | ||
1393 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | ||
1394 | if (!atomic_read(&passive_cpu_wait[cpu])) | ||
1395 | goto return_normal; | ||
1396 | } else { | ||
1397 | return_normal: | ||
1398 | /* Return to normal operation by executing any | ||
1399 | * hw breakpoint fixup. | ||
1400 | */ | ||
1401 | if (arch_kgdb_ops.correct_hw_break) | ||
1402 | arch_kgdb_ops.correct_hw_break(); | ||
1403 | if (trace_on) | ||
1404 | tracing_on(); | ||
1405 | atomic_dec(&cpu_in_kgdb[cpu]); | ||
1406 | touch_softlockup_watchdog_sync(); | ||
1407 | clocksource_touch_watchdog(); | ||
1408 | local_irq_restore(flags); | ||
1409 | return 0; | ||
1410 | } | ||
1444 | cpu_relax(); | 1411 | cpu_relax(); |
1412 | } | ||
1445 | 1413 | ||
1446 | /* | 1414 | /* |
1447 | * For single stepping, try to only enter on the processor | 1415 | * For single stepping, try to only enter on the processor |
@@ -1475,9 +1443,6 @@ acquirelock: | |||
1475 | if (kgdb_io_ops->pre_exception) | 1443 | if (kgdb_io_ops->pre_exception) |
1476 | kgdb_io_ops->pre_exception(); | 1444 | kgdb_io_ops->pre_exception(); |
1477 | 1445 | ||
1478 | kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs; | ||
1479 | kgdb_info[ks->cpu].task = current; | ||
1480 | |||
1481 | kgdb_disable_hw_debug(ks->linux_regs); | 1446 | kgdb_disable_hw_debug(ks->linux_regs); |
1482 | 1447 | ||
1483 | /* | 1448 | /* |
@@ -1486,15 +1451,9 @@ acquirelock: | |||
1486 | */ | 1451 | */ |
1487 | if (!kgdb_single_step) { | 1452 | if (!kgdb_single_step) { |
1488 | for (i = 0; i < NR_CPUS; i++) | 1453 | for (i = 0; i < NR_CPUS; i++) |
1489 | atomic_set(&passive_cpu_wait[i], 1); | 1454 | atomic_inc(&passive_cpu_wait[i]); |
1490 | } | 1455 | } |
1491 | 1456 | ||
1492 | /* | ||
1493 | * spin_lock code is good enough as a barrier so we don't | ||
1494 | * need one here: | ||
1495 | */ | ||
1496 | atomic_set(&cpu_in_kgdb[ks->cpu], 1); | ||
1497 | |||
1498 | #ifdef CONFIG_SMP | 1457 | #ifdef CONFIG_SMP |
1499 | /* Signal the other CPUs to enter kgdb_wait() */ | 1458 | /* Signal the other CPUs to enter kgdb_wait() */ |
1500 | if ((!kgdb_single_step) && kgdb_do_roundup) | 1459 | if ((!kgdb_single_step) && kgdb_do_roundup) |
@@ -1518,6 +1477,9 @@ acquirelock: | |||
1518 | kgdb_single_step = 0; | 1477 | kgdb_single_step = 0; |
1519 | kgdb_contthread = current; | 1478 | kgdb_contthread = current; |
1520 | exception_level = 0; | 1479 | exception_level = 0; |
1480 | trace_on = tracing_is_on(); | ||
1481 | if (trace_on) | ||
1482 | tracing_off(); | ||
1521 | 1483 | ||
1522 | /* Talk to debugger with gdbserial protocol */ | 1484 | /* Talk to debugger with gdbserial protocol */ |
1523 | error = gdb_serial_stub(ks); | 1485 | error = gdb_serial_stub(ks); |
@@ -1526,13 +1488,11 @@ acquirelock: | |||
1526 | if (kgdb_io_ops->post_exception) | 1488 | if (kgdb_io_ops->post_exception) |
1527 | kgdb_io_ops->post_exception(); | 1489 | kgdb_io_ops->post_exception(); |
1528 | 1490 | ||
1529 | kgdb_info[ks->cpu].debuggerinfo = NULL; | 1491 | atomic_dec(&cpu_in_kgdb[ks->cpu]); |
1530 | kgdb_info[ks->cpu].task = NULL; | ||
1531 | atomic_set(&cpu_in_kgdb[ks->cpu], 0); | ||
1532 | 1492 | ||
1533 | if (!kgdb_single_step) { | 1493 | if (!kgdb_single_step) { |
1534 | for (i = NR_CPUS-1; i >= 0; i--) | 1494 | for (i = NR_CPUS-1; i >= 0; i--) |
1535 | atomic_set(&passive_cpu_wait[i], 0); | 1495 | atomic_dec(&passive_cpu_wait[i]); |
1536 | /* | 1496 | /* |
1537 | * Wait till all the CPUs have quit | 1497 | * Wait till all the CPUs have quit |
1538 | * from the debugger. | 1498 | * from the debugger. |
@@ -1551,6 +1511,8 @@ kgdb_restore: | |||
1551 | else | 1511 | else |
1552 | kgdb_sstep_pid = 0; | 1512 | kgdb_sstep_pid = 0; |
1553 | } | 1513 | } |
1514 | if (trace_on) | ||
1515 | tracing_on(); | ||
1554 | /* Free kgdb_active */ | 1516 | /* Free kgdb_active */ |
1555 | atomic_set(&kgdb_active, -1); | 1517 | atomic_set(&kgdb_active, -1); |
1556 | touch_softlockup_watchdog_sync(); | 1518 | touch_softlockup_watchdog_sync(); |
@@ -1560,13 +1522,52 @@ kgdb_restore: | |||
1560 | return error; | 1522 | return error; |
1561 | } | 1523 | } |
1562 | 1524 | ||
1525 | /* | ||
1526 | * kgdb_handle_exception() - main entry point from a kernel exception | ||
1527 | * | ||
1528 | * Locking hierarchy: | ||
1529 | * interface locks, if any (begin_session) | ||
1530 | * kgdb lock (kgdb_active) | ||
1531 | */ | ||
1532 | int | ||
1533 | kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | ||
1534 | { | ||
1535 | struct kgdb_state kgdb_var; | ||
1536 | struct kgdb_state *ks = &kgdb_var; | ||
1537 | int ret; | ||
1538 | |||
1539 | ks->cpu = raw_smp_processor_id(); | ||
1540 | ks->ex_vector = evector; | ||
1541 | ks->signo = signo; | ||
1542 | ks->ex_vector = evector; | ||
1543 | ks->err_code = ecode; | ||
1544 | ks->kgdb_usethreadid = 0; | ||
1545 | ks->linux_regs = regs; | ||
1546 | |||
1547 | if (kgdb_reenter_check(ks)) | ||
1548 | return 0; /* Ouch, double exception ! */ | ||
1549 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | ||
1550 | ret = kgdb_cpu_enter(ks, regs); | ||
1551 | kgdb_info[ks->cpu].exception_state &= ~DCPU_WANT_MASTER; | ||
1552 | return ret; | ||
1553 | } | ||
1554 | |||
1563 | int kgdb_nmicallback(int cpu, void *regs) | 1555 | int kgdb_nmicallback(int cpu, void *regs) |
1564 | { | 1556 | { |
1565 | #ifdef CONFIG_SMP | 1557 | #ifdef CONFIG_SMP |
1558 | struct kgdb_state kgdb_var; | ||
1559 | struct kgdb_state *ks = &kgdb_var; | ||
1560 | |||
1561 | memset(ks, 0, sizeof(struct kgdb_state)); | ||
1562 | ks->cpu = cpu; | ||
1563 | ks->linux_regs = regs; | ||
1564 | |||
1566 | if (!atomic_read(&cpu_in_kgdb[cpu]) && | 1565 | if (!atomic_read(&cpu_in_kgdb[cpu]) && |
1567 | atomic_read(&kgdb_active) != cpu && | 1566 | atomic_read(&kgdb_active) != -1 && |
1568 | atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) { | 1567 | atomic_read(&kgdb_active) != cpu) { |
1569 | kgdb_wait((struct pt_regs *)regs); | 1568 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; |
1569 | kgdb_cpu_enter(ks, regs); | ||
1570 | kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | ||
1570 | return 0; | 1571 | return 0; |
1571 | } | 1572 | } |
1572 | #endif | 1573 | #endif |
@@ -1742,11 +1743,11 @@ EXPORT_SYMBOL_GPL(kgdb_unregister_io_module); | |||
1742 | */ | 1743 | */ |
1743 | void kgdb_breakpoint(void) | 1744 | void kgdb_breakpoint(void) |
1744 | { | 1745 | { |
1745 | atomic_set(&kgdb_setting_breakpoint, 1); | 1746 | atomic_inc(&kgdb_setting_breakpoint); |
1746 | wmb(); /* Sync point before breakpoint */ | 1747 | wmb(); /* Sync point before breakpoint */ |
1747 | arch_kgdb_breakpoint(); | 1748 | arch_kgdb_breakpoint(); |
1748 | wmb(); /* Sync point after breakpoint */ | 1749 | wmb(); /* Sync point after breakpoint */ |
1749 | atomic_set(&kgdb_setting_breakpoint, 0); | 1750 | atomic_dec(&kgdb_setting_breakpoint); |
1750 | } | 1751 | } |
1751 | EXPORT_SYMBOL_GPL(kgdb_breakpoint); | 1752 | EXPORT_SYMBOL_GPL(kgdb_breakpoint); |
1752 | 1753 | ||