aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kgdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kgdb.c')
-rw-r--r--kernel/kgdb.c165
1 files changed, 82 insertions, 83 deletions
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 42fd128127a6..6882c047452d 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
72static struct debuggerinfo_struct { 78static 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/**
@@ -558,49 +565,6 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid)
558} 565}
559 566
560/* 567/*
561 * CPU debug state control:
562 */
563
564#ifdef CONFIG_SMP
565static 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 * Some architectures need cache flushes when we set/clear a 568 * Some architectures need cache flushes when we set/clear a
605 * breakpoint: 569 * breakpoint:
606 */ 570 */
@@ -1395,34 +1359,12 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
1395 return 1; 1359 return 1;
1396} 1360}
1397 1361
1398/* 1362static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs)
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 */
1405int
1406kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
1407{ 1363{
1408 struct kgdb_state kgdb_var;
1409 struct kgdb_state *ks = &kgdb_var;
1410 unsigned long flags; 1364 unsigned long flags;
1411 int sstep_tries = 100; 1365 int sstep_tries = 100;
1412 int error = 0; 1366 int error = 0;
1413 int i, cpu; 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
1426acquirelock: 1368acquirelock:
1427 /* 1369 /*
1428 * Interrupts will be restored by the 'trap return' code, except when 1370 * Interrupts will be restored by the 'trap return' code, except when
@@ -1430,13 +1372,42 @@ acquirelock:
1430 */ 1372 */
1431 local_irq_save(flags); 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 {
1397return_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 cpu_relax(); 1409 cpu_relax();
1410 }
1440 1411
1441 /* 1412 /*
1442 * For single stepping, try to only enter on the processor 1413 * For single stepping, try to only enter on the processor
@@ -1470,9 +1441,6 @@ acquirelock:
1470 if (kgdb_io_ops->pre_exception) 1441 if (kgdb_io_ops->pre_exception)
1471 kgdb_io_ops->pre_exception(); 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 kgdb_disable_hw_debug(ks->linux_regs); 1444 kgdb_disable_hw_debug(ks->linux_regs);
1477 1445
1478 /* 1446 /*
@@ -1484,12 +1452,6 @@ acquirelock:
1484 atomic_set(&passive_cpu_wait[i], 1); 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#ifdef CONFIG_SMP 1455#ifdef CONFIG_SMP
1494 /* Signal the other CPUs to enter kgdb_wait() */ 1456 /* Signal the other CPUs to enter kgdb_wait() */
1495 if ((!kgdb_single_step) && kgdb_do_roundup) 1457 if ((!kgdb_single_step) && kgdb_do_roundup)
@@ -1521,8 +1483,6 @@ acquirelock:
1521 if (kgdb_io_ops->post_exception) 1483 if (kgdb_io_ops->post_exception)
1522 kgdb_io_ops->post_exception(); 1484 kgdb_io_ops->post_exception();
1523 1485
1524 kgdb_info[ks->cpu].debuggerinfo = NULL;
1525 kgdb_info[ks->cpu].task = NULL;
1526 atomic_set(&cpu_in_kgdb[ks->cpu], 0); 1486 atomic_set(&cpu_in_kgdb[ks->cpu], 0);
1527 1487
1528 if (!kgdb_single_step) { 1488 if (!kgdb_single_step) {
@@ -1555,13 +1515,52 @@ kgdb_restore:
1555 return error; 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 */
1525int
1526kgdb_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
1558int kgdb_nmicallback(int cpu, void *regs) 1548int kgdb_nmicallback(int cpu, void *regs)
1559{ 1549{
1560#ifdef CONFIG_SMP 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 if (!atomic_read(&cpu_in_kgdb[cpu]) && 1558 if (!atomic_read(&cpu_in_kgdb[cpu]) &&
1562 atomic_read(&kgdb_active) != cpu && 1559 atomic_read(&kgdb_active) != -1 &&
1563 atomic_read(&cpu_in_kgdb[atomic_read(&kgdb_active)])) { 1560 atomic_read(&kgdb_active) != cpu) {
1564 kgdb_wait((struct pt_regs *)regs); 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 return 0; 1564 return 0;
1566 } 1565 }
1567#endif 1566#endif