-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'x86-debug-for-linus' of git://git.kernel.org/pub/scm/li…
…nux/kernel/git/tip/tip * 'x86-debug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, reboot: Fix typo in nmi reboot path x86, NMI: Add to_cpumask() to silence compile warning x86, NMI: NMI selftest depends on the local apic x86: Add stack top margin for stack overflow checking x86, NMI: NMI-selftest should handle the UP case properly x86: Fix the 32-bit stackoverflow-debug build x86, NMI: Add knob to disable using NMI IPIs to stop cpus x86, NMI: Add NMI IPI selftest x86, reboot: Use NMI instead of REBOOT_VECTOR to stop cpus x86: Clean up the range of stack overflow checking x86: Panic on detection of stack overflow x86: Check stack overflow in detail
- Loading branch information
Showing
12 changed files
with
337 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/* | ||
* arch/x86/kernel/nmi-selftest.c | ||
* | ||
* Testsuite for NMI: IPIs | ||
* | ||
* Started by Don Zickus: | ||
* (using lib/locking-selftest.c as a guide) | ||
* | ||
* Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com> | ||
*/ | ||
|
||
#include <linux/smp.h> | ||
#include <linux/cpumask.h> | ||
#include <linux/delay.h> | ||
|
||
#include <asm/apic.h> | ||
#include <asm/nmi.h> | ||
|
||
#define SUCCESS 0 | ||
#define FAILURE 1 | ||
#define TIMEOUT 2 | ||
|
||
static int nmi_fail; | ||
|
||
/* check to see if NMI IPIs work on this machine */ | ||
static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly; | ||
|
||
static int testcase_total; | ||
static int testcase_successes; | ||
static int expected_testcase_failures; | ||
static int unexpected_testcase_failures; | ||
static int unexpected_testcase_unknowns; | ||
|
||
static int nmi_unk_cb(unsigned int val, struct pt_regs *regs) | ||
{ | ||
unexpected_testcase_unknowns++; | ||
return NMI_HANDLED; | ||
} | ||
|
||
static void init_nmi_testsuite(void) | ||
{ | ||
/* trap all the unknown NMIs we may generate */ | ||
register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); | ||
} | ||
|
||
static void cleanup_nmi_testsuite(void) | ||
{ | ||
unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); | ||
} | ||
|
||
static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) | ||
{ | ||
int cpu = raw_smp_processor_id(); | ||
|
||
if (cpumask_test_and_clear_cpu(cpu, to_cpumask(nmi_ipi_mask))) | ||
return NMI_HANDLED; | ||
|
||
return NMI_DONE; | ||
} | ||
|
||
static void test_nmi_ipi(struct cpumask *mask) | ||
{ | ||
unsigned long timeout; | ||
|
||
if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, | ||
NMI_FLAG_FIRST, "nmi_selftest")) { | ||
nmi_fail = FAILURE; | ||
return; | ||
} | ||
|
||
/* sync above data before sending NMI */ | ||
wmb(); | ||
|
||
apic->send_IPI_mask(mask, NMI_VECTOR); | ||
|
||
/* Don't wait longer than a second */ | ||
timeout = USEC_PER_SEC; | ||
while (!cpumask_empty(mask) && timeout--) | ||
udelay(1); | ||
|
||
/* What happens if we timeout, do we still unregister?? */ | ||
unregister_nmi_handler(NMI_LOCAL, "nmi_selftest"); | ||
|
||
if (!timeout) | ||
nmi_fail = TIMEOUT; | ||
return; | ||
} | ||
|
||
static void remote_ipi(void) | ||
{ | ||
cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask); | ||
cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
if (!cpumask_empty(to_cpumask(nmi_ipi_mask))) | ||
test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
} | ||
|
||
static void local_ipi(void) | ||
{ | ||
cpumask_clear(to_cpumask(nmi_ipi_mask)); | ||
cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
} | ||
|
||
static void reset_nmi(void) | ||
{ | ||
nmi_fail = 0; | ||
} | ||
|
||
static void dotest(void (*testcase_fn)(void), int expected) | ||
{ | ||
testcase_fn(); | ||
/* | ||
* Filter out expected failures: | ||
*/ | ||
if (nmi_fail != expected) { | ||
unexpected_testcase_failures++; | ||
|
||
if (nmi_fail == FAILURE) | ||
printk("FAILED |"); | ||
else if (nmi_fail == TIMEOUT) | ||
printk("TIMEOUT|"); | ||
else | ||
printk("ERROR |"); | ||
dump_stack(); | ||
} else { | ||
testcase_successes++; | ||
printk(" ok |"); | ||
} | ||
testcase_total++; | ||
|
||
reset_nmi(); | ||
} | ||
|
||
static inline void print_testname(const char *testname) | ||
{ | ||
printk("%12s:", testname); | ||
} | ||
|
||
void nmi_selftest(void) | ||
{ | ||
init_nmi_testsuite(); | ||
|
||
/* | ||
* Run the testsuite: | ||
*/ | ||
printk("----------------\n"); | ||
printk("| NMI testsuite:\n"); | ||
printk("--------------------\n"); | ||
|
||
print_testname("remote IPI"); | ||
dotest(remote_ipi, SUCCESS); | ||
printk("\n"); | ||
print_testname("local IPI"); | ||
dotest(local_ipi, SUCCESS); | ||
printk("\n"); | ||
|
||
cleanup_nmi_testsuite(); | ||
|
||
if (unexpected_testcase_failures) { | ||
printk("--------------------\n"); | ||
printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n", | ||
unexpected_testcase_failures, testcase_total); | ||
printk("-----------------------------------------------------------------\n"); | ||
} else if (expected_testcase_failures && testcase_successes) { | ||
printk("--------------------\n"); | ||
printk("%3d out of %3d testcases failed, as expected. |\n", | ||
expected_testcase_failures, testcase_total); | ||
printk("----------------------------------------------------\n"); | ||
} else if (expected_testcase_failures && !testcase_successes) { | ||
printk("--------------------\n"); | ||
printk("All %3d testcases failed, as expected. |\n", | ||
expected_testcase_failures); | ||
printk("----------------------------------------\n"); | ||
} else { | ||
printk("--------------------\n"); | ||
printk("Good, all %3d testcases passed! |\n", | ||
testcase_successes); | ||
printk("---------------------------------\n"); | ||
} | ||
} |
Oops, something went wrong.