Commit 62fae312197a8fbcd3727261d59f5a6bd0dbf158
1 parent
cad08acebf
Exists in
master
and in
7 other branches
kgdb: eliminate kgdb_wait(), all cpus enter the same way
This is a kgdb architectural change to have all the cpus (master or slave) enter the same function. A cpu that hits an exception (wants to be the master cpu) will call kgdb_handle_exception() from the trap handler and then invoke a kgdb_roundup_cpu() to synchronize the other cpus and bring them into the kgdb_handle_exception() as well. A slave cpu will enter kgdb_handle_exception() from the kgdb_nmicallback() and set the exception state to note that the processor is a slave. Previously the salve cpu would have called kgdb_wait(). This change allows the debug core to change cpus without resuming the system in order to inspect arch specific cpu information. Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Showing 1 changed file with 82 additions and 83 deletions Side-by-side Diff
kernel/kgdb.c
... | ... | @@ -69,9 +69,16 @@ |
69 | 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 | 78 | static struct debuggerinfo_struct { |
73 | 79 | void *debuggerinfo; |
74 | 80 | struct task_struct *task; |
81 | + int exception_state; | |
75 | 82 | } kgdb_info[NR_CPUS]; |
76 | 83 | |
77 | 84 | /** |
... | ... | @@ -558,49 +565,6 @@ |
558 | 565 | } |
559 | 566 | |
560 | 567 | /* |
561 | - * CPU debug state control: | |
562 | - */ | |
563 | - | |
564 | -#ifdef CONFIG_SMP | |
565 | -static void kgdb_wait(struct pt_regs *regs) | |
566 | -{ | |
567 | - unsigned long flags; | |
568 | - int cpu; | |
569 | - | |
570 | - local_irq_save(flags); | |
571 | - cpu = raw_smp_processor_id(); | |
572 | - kgdb_info[cpu].debuggerinfo = regs; | |
573 | - kgdb_info[cpu].task = current; | |
574 | - /* | |
575 | - * Make sure the above info reaches the primary CPU before | |
576 | - * our cpu_in_kgdb[] flag setting does: | |
577 | - */ | |
578 | - smp_wmb(); | |
579 | - atomic_set(&cpu_in_kgdb[cpu], 1); | |
580 | - | |
581 | - /* Disable any cpu specific hw breakpoints */ | |
582 | - kgdb_disable_hw_debug(regs); | |
583 | - | |
584 | - /* Wait till primary CPU is done with debugging */ | |
585 | - while (atomic_read(&passive_cpu_wait[cpu])) | |
586 | - cpu_relax(); | |
587 | - | |
588 | - kgdb_info[cpu].debuggerinfo = NULL; | |
589 | - kgdb_info[cpu].task = NULL; | |
590 | - | |
591 | - /* fix up hardware debug registers on local cpu */ | |
592 | - if (arch_kgdb_ops.correct_hw_break) | |
593 | - arch_kgdb_ops.correct_hw_break(); | |
594 | - | |
595 | - /* Signal the primary CPU that we are done: */ | |
596 | - atomic_set(&cpu_in_kgdb[cpu], 0); | |
597 | - touch_softlockup_watchdog_sync(); | |
598 | - clocksource_touch_watchdog(); | |
599 | - local_irq_restore(flags); | |
600 | -} | |
601 | -#endif | |
602 | - | |
603 | -/* | |
604 | 568 | * Some architectures need cache flushes when we set/clear a |
605 | 569 | * breakpoint: |
606 | 570 | */ |
607 | 571 | |
608 | 572 | |
... | ... | @@ -1395,34 +1359,12 @@ |
1395 | 1359 | return 1; |
1396 | 1360 | } |
1397 | 1361 | |
1398 | -/* | |
1399 | - * kgdb_handle_exception() - main entry point from a kernel exception | |
1400 | - * | |
1401 | - * Locking hierarchy: | |
1402 | - * interface locks, if any (begin_session) | |
1403 | - * kgdb lock (kgdb_active) | |
1404 | - */ | |
1405 | -int | |
1406 | -kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |
1362 | +static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) | |
1407 | 1363 | { |
1408 | - struct kgdb_state kgdb_var; | |
1409 | - struct kgdb_state *ks = &kgdb_var; | |
1410 | 1364 | unsigned long flags; |
1411 | 1365 | int sstep_tries = 100; |
1412 | 1366 | int error = 0; |
1413 | 1367 | int i, cpu; |
1414 | - | |
1415 | - ks->cpu = raw_smp_processor_id(); | |
1416 | - ks->ex_vector = evector; | |
1417 | - ks->signo = signo; | |
1418 | - ks->ex_vector = evector; | |
1419 | - ks->err_code = ecode; | |
1420 | - ks->kgdb_usethreadid = 0; | |
1421 | - ks->linux_regs = regs; | |
1422 | - | |
1423 | - if (kgdb_reenter_check(ks)) | |
1424 | - return 0; /* Ouch, double exception ! */ | |
1425 | - | |
1426 | 1368 | acquirelock: |
1427 | 1369 | /* |
1428 | 1370 | * Interrupts will be restored by the 'trap return' code, except when |
1429 | 1371 | |
1430 | 1372 | |
1431 | 1373 | |
... | ... | @@ -1430,13 +1372,42 @@ |
1430 | 1372 | */ |
1431 | 1373 | local_irq_save(flags); |
1432 | 1374 | |
1433 | - cpu = raw_smp_processor_id(); | |
1375 | + cpu = ks->cpu; | |
1376 | + kgdb_info[cpu].debuggerinfo = regs; | |
1377 | + kgdb_info[cpu].task = current; | |
1378 | + /* | |
1379 | + * Make sure the above info reaches the primary CPU before | |
1380 | + * our cpu_in_kgdb[] flag setting does: | |
1381 | + */ | |
1382 | + smp_wmb(); | |
1383 | + atomic_set(&cpu_in_kgdb[cpu], 1); | |
1434 | 1384 | |
1435 | 1385 | /* |
1436 | - * 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: | |
1437 | 1388 | */ |
1438 | - 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 | + atomic_set(&cpu_in_kgdb[cpu], 0); | |
1404 | + touch_softlockup_watchdog_sync(); | |
1405 | + clocksource_touch_watchdog(); | |
1406 | + local_irq_restore(flags); | |
1407 | + return 0; | |
1408 | + } | |
1439 | 1409 | cpu_relax(); |
1410 | + } | |
1440 | 1411 | |
1441 | 1412 | /* |
1442 | 1413 | * For single stepping, try to only enter on the processor |
... | ... | @@ -1470,9 +1441,6 @@ |
1470 | 1441 | if (kgdb_io_ops->pre_exception) |
1471 | 1442 | kgdb_io_ops->pre_exception(); |
1472 | 1443 | |
1473 | - kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs; | |
1474 | - kgdb_info[ks->cpu].task = current; | |
1475 | - | |
1476 | 1444 | kgdb_disable_hw_debug(ks->linux_regs); |
1477 | 1445 | |
1478 | 1446 | /* |
... | ... | @@ -1484,12 +1452,6 @@ |
1484 | 1452 | atomic_set(&passive_cpu_wait[i], 1); |
1485 | 1453 | } |
1486 | 1454 | |
1487 | - /* | |
1488 | - * spin_lock code is good enough as a barrier so we don't | |
1489 | - * need one here: | |
1490 | - */ | |
1491 | - atomic_set(&cpu_in_kgdb[ks->cpu], 1); | |
1492 | - | |
1493 | 1455 | #ifdef CONFIG_SMP |
1494 | 1456 | /* Signal the other CPUs to enter kgdb_wait() */ |
1495 | 1457 | if ((!kgdb_single_step) && kgdb_do_roundup) |
... | ... | @@ -1521,8 +1483,6 @@ |
1521 | 1483 | if (kgdb_io_ops->post_exception) |
1522 | 1484 | kgdb_io_ops->post_exception(); |
1523 | 1485 | |
1524 | - kgdb_info[ks->cpu].debuggerinfo = NULL; | |
1525 | - kgdb_info[ks->cpu].task = NULL; | |
1526 | 1486 | atomic_set(&cpu_in_kgdb[ks->cpu], 0); |
1527 | 1487 | |
1528 | 1488 | if (!kgdb_single_step) { |
1529 | 1489 | |
1530 | 1490 | |
... | ... | @@ -1555,13 +1515,52 @@ |
1555 | 1515 | return error; |
1556 | 1516 | } |
1557 | 1517 | |
1518 | +/* | |
1519 | + * kgdb_handle_exception() - main entry point from a kernel exception | |
1520 | + * | |
1521 | + * Locking hierarchy: | |
1522 | + * interface locks, if any (begin_session) | |
1523 | + * kgdb lock (kgdb_active) | |
1524 | + */ | |
1525 | +int | |
1526 | +kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |
1527 | +{ | |
1528 | + struct kgdb_state kgdb_var; | |
1529 | + struct kgdb_state *ks = &kgdb_var; | |
1530 | + int ret; | |
1531 | + | |
1532 | + ks->cpu = raw_smp_processor_id(); | |
1533 | + ks->ex_vector = evector; | |
1534 | + ks->signo = signo; | |
1535 | + ks->ex_vector = evector; | |
1536 | + ks->err_code = ecode; | |
1537 | + ks->kgdb_usethreadid = 0; | |
1538 | + ks->linux_regs = regs; | |
1539 | + | |
1540 | + if (kgdb_reenter_check(ks)) | |
1541 | + return 0; /* Ouch, double exception ! */ | |
1542 | + kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | |
1543 | + ret = kgdb_cpu_enter(ks, regs); | |
1544 | + kgdb_info[ks->cpu].exception_state &= ~DCPU_WANT_MASTER; | |
1545 | + return ret; | |
1546 | +} | |
1547 | + | |
1558 | 1548 | int kgdb_nmicallback(int cpu, void *regs) |
1559 | 1549 | { |
1560 | 1550 | #ifdef CONFIG_SMP |
1551 | + struct kgdb_state kgdb_var; | |
1552 | + struct kgdb_state *ks = &kgdb_var; | |
1553 | + | |
1554 | + memset(ks, 0, sizeof(struct kgdb_state)); | |
1555 | + ks->cpu = cpu; | |
1556 | + ks->linux_regs = regs; | |
1557 | + | |
1561 | 1558 | if (!atomic_read(&cpu_in_kgdb[cpu]) && |
1562 | - atomic_read(&kgdb_active) != cpu && | |
1563 | - atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) { | |
1564 | - kgdb_wait((struct pt_regs *)regs); | |
1559 | + atomic_read(&kgdb_active) != -1 && | |
1560 | + atomic_read(&kgdb_active) != cpu) { | |
1561 | + kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | |
1562 | + kgdb_cpu_enter(ks, regs); | |
1563 | + kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | |
1565 | 1564 | return 0; |
1566 | 1565 | } |
1567 | 1566 | #endif |