mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 06:31:58 +02:00
Merge branch 'x86/nmi' into x86/core, to merge dependent commits
Prepare to resolve conflicts with an upstream series of fixes that conflict
with pending x86 changes:
6f5bf947ba Merge tag 'its-for-linus-20250509' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
d6680b0077
|
|
@ -14,12 +14,26 @@ extern void release_perfctr_nmi(unsigned int);
|
|||
extern int reserve_evntsel_nmi(unsigned int);
|
||||
extern void release_evntsel_nmi(unsigned int);
|
||||
|
||||
extern int unknown_nmi_panic;
|
||||
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
extern int unknown_nmi_panic;
|
||||
extern int panic_on_unrecovered_nmi;
|
||||
extern int panic_on_io_nmi;
|
||||
|
||||
/* NMI handler flags */
|
||||
#define NMI_FLAG_FIRST 1
|
||||
|
||||
/**
|
||||
* enum - NMI types.
|
||||
* @NMI_LOCAL: Local NMI, CPU-specific NMI generated by the Local APIC.
|
||||
* @NMI_UNKNOWN: Unknown NMI, the source of the NMI may not be identified.
|
||||
* @NMI_SERR: System Error NMI, typically triggered by PCI errors.
|
||||
* @NMI_IO_CHECK: I/O Check NMI, related to I/O errors.
|
||||
* @NMI_MAX: Maximum value for NMI types.
|
||||
*
|
||||
* NMI types are used to categorize NMIs and to dispatch them to the
|
||||
* appropriate handler.
|
||||
*/
|
||||
enum {
|
||||
NMI_LOCAL=0,
|
||||
NMI_UNKNOWN,
|
||||
|
|
@ -28,6 +42,7 @@ enum {
|
|||
NMI_MAX
|
||||
};
|
||||
|
||||
/* NMI handler return values */
|
||||
#define NMI_DONE 0
|
||||
#define NMI_HANDLED 1
|
||||
|
||||
|
|
@ -41,6 +56,25 @@ struct nmiaction {
|
|||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* register_nmi_handler - Register a handler for a specific NMI type
|
||||
* @t: NMI type (e.g. NMI_LOCAL)
|
||||
* @fn: The NMI handler
|
||||
* @fg: Flags associated with the NMI handler
|
||||
* @n: Name of the NMI handler
|
||||
* @init: Optional __init* attributes for struct nmiaction
|
||||
*
|
||||
* Adds the provided handler to the list of handlers for the specified
|
||||
* NMI type. Handlers flagged with NMI_FLAG_FIRST would be executed first.
|
||||
*
|
||||
* Sometimes the source of an NMI can't be reliably determined which
|
||||
* results in an NMI being tagged as "unknown". Register an additional
|
||||
* handler using the NMI type - NMI_UNKNOWN to handle such cases. The
|
||||
* caller would get one last chance to assume responsibility for the
|
||||
* NMI.
|
||||
*
|
||||
* Return: 0 on success, or an error code on failure.
|
||||
*/
|
||||
#define register_nmi_handler(t, fn, fg, n, init...) \
|
||||
({ \
|
||||
static struct nmiaction init fn##_na = { \
|
||||
|
|
@ -54,7 +88,16 @@ struct nmiaction {
|
|||
|
||||
int __register_nmi_handler(unsigned int, struct nmiaction *);
|
||||
|
||||
void unregister_nmi_handler(unsigned int, const char *);
|
||||
/**
|
||||
* unregister_nmi_handler - Unregister a handler for a specific NMI type
|
||||
* @type: NMI type (e.g. NMI_LOCAL)
|
||||
* @name: Name of the NMI handler used during registration
|
||||
*
|
||||
* Removes the handler associated with the specified NMI type from the
|
||||
* NMI handler list. The "name" is used as a lookup key to identify the
|
||||
* handler.
|
||||
*/
|
||||
void unregister_nmi_handler(unsigned int type, const char *name);
|
||||
|
||||
void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler);
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ struct x86_hyper_runtime {
|
|||
* @set_wallclock: set time back to HW clock
|
||||
* @is_untracked_pat_range exclude from PAT logic
|
||||
* @nmi_init enable NMI on cpus
|
||||
* @get_nmi_reason get the reason an NMI was received
|
||||
* @save_sched_clock_state: save state for sched_clock() on suspend
|
||||
* @restore_sched_clock_state: restore state for sched_clock() on resume
|
||||
* @apic_post_init: adjust apic if needed
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#include <asm/stacktrace.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
int panic_on_unrecovered_nmi;
|
||||
int panic_on_io_nmi;
|
||||
static int die_counter;
|
||||
|
||||
static struct pt_regs exec_summary_regs;
|
||||
|
|
|
|||
|
|
@ -49,27 +49,20 @@ struct nmi_desc {
|
|||
struct list_head head;
|
||||
};
|
||||
|
||||
static struct nmi_desc nmi_desc[NMI_MAX] =
|
||||
{
|
||||
{
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[0].lock),
|
||||
.head = LIST_HEAD_INIT(nmi_desc[0].head),
|
||||
},
|
||||
{
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[1].lock),
|
||||
.head = LIST_HEAD_INIT(nmi_desc[1].head),
|
||||
},
|
||||
{
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[2].lock),
|
||||
.head = LIST_HEAD_INIT(nmi_desc[2].head),
|
||||
},
|
||||
{
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[3].lock),
|
||||
.head = LIST_HEAD_INIT(nmi_desc[3].head),
|
||||
},
|
||||
#define NMI_DESC_INIT(type) { \
|
||||
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[type].lock), \
|
||||
.head = LIST_HEAD_INIT(nmi_desc[type].head), \
|
||||
}
|
||||
|
||||
static struct nmi_desc nmi_desc[NMI_MAX] = {
|
||||
NMI_DESC_INIT(NMI_LOCAL),
|
||||
NMI_DESC_INIT(NMI_UNKNOWN),
|
||||
NMI_DESC_INIT(NMI_SERR),
|
||||
NMI_DESC_INIT(NMI_IO_CHECK),
|
||||
};
|
||||
|
||||
#define nmi_to_desc(type) (&nmi_desc[type])
|
||||
|
||||
struct nmi_stats {
|
||||
unsigned int normal;
|
||||
unsigned int unknown;
|
||||
|
|
@ -91,6 +84,9 @@ static DEFINE_PER_CPU(struct nmi_stats, nmi_stats);
|
|||
static int ignore_nmis __read_mostly;
|
||||
|
||||
int unknown_nmi_panic;
|
||||
int panic_on_unrecovered_nmi;
|
||||
int panic_on_io_nmi;
|
||||
|
||||
/*
|
||||
* Prevent NMI reason port (0x61) being accessed simultaneously, can
|
||||
* only be used in NMI handler.
|
||||
|
|
@ -104,8 +100,6 @@ static int __init setup_unknown_nmi_panic(char *str)
|
|||
}
|
||||
__setup("unknown_nmi_panic", setup_unknown_nmi_panic);
|
||||
|
||||
#define nmi_to_desc(type) (&nmi_desc[type])
|
||||
|
||||
static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
|
||||
|
||||
static int __init nmi_warning_debugfs(void)
|
||||
|
|
@ -125,12 +119,12 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration)
|
|||
|
||||
action->max_duration = duration;
|
||||
|
||||
remainder_ns = do_div(duration, (1000 * 1000));
|
||||
decimal_msecs = remainder_ns / 1000;
|
||||
/* Convert duration from nsec to msec */
|
||||
remainder_ns = do_div(duration, NSEC_PER_MSEC);
|
||||
decimal_msecs = remainder_ns / NSEC_PER_USEC;
|
||||
|
||||
printk_ratelimited(KERN_INFO
|
||||
"INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
|
||||
action->handler, duration, decimal_msecs);
|
||||
pr_info_ratelimited("INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
|
||||
action->handler, duration, decimal_msecs);
|
||||
}
|
||||
|
||||
static int nmi_handle(unsigned int type, struct pt_regs *regs)
|
||||
|
|
@ -333,10 +327,9 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
|
|||
int handled;
|
||||
|
||||
/*
|
||||
* Use 'false' as back-to-back NMIs are dealt with one level up.
|
||||
* Of course this makes having multiple 'unknown' handlers useless
|
||||
* as only the first one is ever run (unless it can actually determine
|
||||
* if it caused the NMI)
|
||||
* As a last resort, let the "unknown" handlers make a
|
||||
* best-effort attempt to figure out if they can claim
|
||||
* responsibility for this Unknown NMI.
|
||||
*/
|
||||
handled = nmi_handle(NMI_UNKNOWN, regs);
|
||||
if (handled) {
|
||||
|
|
@ -366,17 +359,18 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
|
|||
bool b2b = false;
|
||||
|
||||
/*
|
||||
* CPU-specific NMI must be processed before non-CPU-specific
|
||||
* NMI, otherwise we may lose it, because the CPU-specific
|
||||
* NMI can not be detected/processed on other CPUs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Back-to-back NMIs are interesting because they can either
|
||||
* be two NMI or more than two NMIs (any thing over two is dropped
|
||||
* due to NMI being edge-triggered). If this is the second half
|
||||
* of the back-to-back NMI, assume we dropped things and process
|
||||
* more handlers. Otherwise reset the 'swallow' NMI behaviour
|
||||
* Back-to-back NMIs are detected by comparing the RIP of the
|
||||
* current NMI with that of the previous NMI. If it is the same,
|
||||
* it is assumed that the CPU did not have a chance to jump back
|
||||
* into a non-NMI context and execute code in between the two
|
||||
* NMIs.
|
||||
*
|
||||
* They are interesting because even if there are more than two,
|
||||
* only a maximum of two can be detected (anything over two is
|
||||
* dropped due to NMI being edge-triggered). If this is the
|
||||
* second half of the back-to-back NMI, assume we dropped things
|
||||
* and process more handlers. Otherwise, reset the 'swallow' NMI
|
||||
* behavior.
|
||||
*/
|
||||
if (regs->ip == __this_cpu_read(last_nmi_rip))
|
||||
b2b = true;
|
||||
|
|
@ -390,6 +384,11 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
|
|||
if (microcode_nmi_handler_enabled() && microcode_nmi_handler())
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* CPU-specific NMI must be processed before non-CPU-specific
|
||||
* NMI, otherwise we may lose it, because the CPU-specific
|
||||
* NMI can not be detected/processed on other CPUs.
|
||||
*/
|
||||
handled = nmi_handle(NMI_LOCAL, regs);
|
||||
__this_cpu_add(nmi_stats.normal, handled);
|
||||
if (handled) {
|
||||
|
|
@ -426,13 +425,14 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
|
|||
pci_serr_error(reason, regs);
|
||||
else if (reason & NMI_REASON_IOCHK)
|
||||
io_check_error(reason, regs);
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
/*
|
||||
* Reassert NMI in case it became active
|
||||
* meanwhile as it's edge-triggered:
|
||||
*/
|
||||
reassert_nmi();
|
||||
#endif
|
||||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
reassert_nmi();
|
||||
|
||||
__this_cpu_add(nmi_stats.external, 1);
|
||||
raw_spin_unlock(&nmi_reason_lock);
|
||||
goto out;
|
||||
|
|
@ -751,4 +751,3 @@ void local_touch_nmi(void)
|
|||
{
|
||||
__this_cpu_write(last_nmi_rip, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(local_touch_nmi);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* arch/x86/kernel/nmi-selftest.c
|
||||
*
|
||||
* Testsuite for NMI: IPIs
|
||||
*
|
||||
* Started by Don Zickus:
|
||||
|
|
@ -30,7 +28,6 @@ static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata;
|
|||
|
||||
static int __initdata testcase_total;
|
||||
static int __initdata testcase_successes;
|
||||
static int __initdata expected_testcase_failures;
|
||||
static int __initdata unexpected_testcase_failures;
|
||||
static int __initdata unexpected_testcase_unknowns;
|
||||
|
||||
|
|
@ -120,26 +117,22 @@ static void __init dotest(void (*testcase_fn)(void), int expected)
|
|||
unexpected_testcase_failures++;
|
||||
|
||||
if (nmi_fail == FAILURE)
|
||||
printk(KERN_CONT "FAILED |");
|
||||
pr_cont("FAILED |");
|
||||
else if (nmi_fail == TIMEOUT)
|
||||
printk(KERN_CONT "TIMEOUT|");
|
||||
pr_cont("TIMEOUT|");
|
||||
else
|
||||
printk(KERN_CONT "ERROR |");
|
||||
pr_cont("ERROR |");
|
||||
dump_stack();
|
||||
} else {
|
||||
testcase_successes++;
|
||||
printk(KERN_CONT " ok |");
|
||||
pr_cont(" ok |");
|
||||
}
|
||||
pr_cont("\n");
|
||||
|
||||
testcase_total++;
|
||||
|
||||
reset_nmi();
|
||||
}
|
||||
|
||||
static inline void __init print_testname(const char *testname)
|
||||
{
|
||||
printk("%12s:", testname);
|
||||
}
|
||||
|
||||
void __init nmi_selftest(void)
|
||||
{
|
||||
init_nmi_testsuite();
|
||||
|
|
@ -147,38 +140,25 @@ void __init nmi_selftest(void)
|
|||
/*
|
||||
* Run the testsuite:
|
||||
*/
|
||||
printk("----------------\n");
|
||||
printk("| NMI testsuite:\n");
|
||||
printk("--------------------\n");
|
||||
pr_info("----------------\n");
|
||||
pr_info("| NMI testsuite:\n");
|
||||
pr_info("--------------------\n");
|
||||
|
||||
print_testname("remote IPI");
|
||||
pr_info("%12s:", "remote IPI");
|
||||
dotest(remote_ipi, SUCCESS);
|
||||
printk(KERN_CONT "\n");
|
||||
print_testname("local IPI");
|
||||
|
||||
pr_info("%12s:", "local IPI");
|
||||
dotest(local_ipi, SUCCESS);
|
||||
printk(KERN_CONT "\n");
|
||||
|
||||
cleanup_nmi_testsuite();
|
||||
|
||||
pr_info("--------------------\n");
|
||||
if (unexpected_testcase_failures) {
|
||||
printk("--------------------\n");
|
||||
printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n",
|
||||
pr_info("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",
|
||||
pr_info("Good, all %3d testcases passed! |\n",
|
||||
testcase_successes);
|
||||
printk("---------------------------------\n");
|
||||
}
|
||||
pr_info("-----------------------------------------------------------------\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/crash_dump.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/init_ohci1394_dma.h>
|
||||
#include <linux/initrd.h>
|
||||
|
|
@ -18,21 +19,19 @@
|
|||
#include <linux/memblock.h>
|
||||
#include <linux/panic_notifier.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/tboot.h>
|
||||
#include <linux/usb/xhci-dbgp.h>
|
||||
#include <linux/static_call.h>
|
||||
#include <linux/swiotlb.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/tboot.h>
|
||||
#include <linux/usb/xhci-dbgp.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <uapi/linux/mount.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/bios_ebda.h>
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cacheinfo.h>
|
||||
|
|
@ -47,18 +46,16 @@
|
|||
#include <asm/mce.h>
|
||||
#include <asm/memtype.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/numa.h>
|
||||
#include <asm/olpc_ofw.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/thermal.h>
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/vsyscall.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#if defined(CONFIG_X86_LOCAL_APIC)
|
||||
#include <asm/nmi.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* max_low_pfn_mapped: highest directly mapped pfn < 4 GB
|
||||
|
|
@ -151,6 +148,13 @@ static size_t ima_kexec_buffer_size;
|
|||
int bootloader_type, bootloader_version;
|
||||
|
||||
static const struct ctl_table x86_sysctl_table[] = {
|
||||
{
|
||||
.procname = "unknown_nmi_panic",
|
||||
.data = &unknown_nmi_panic,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "panic_on_unrecovered_nmi",
|
||||
.data = &panic_on_unrecovered_nmi,
|
||||
|
|
@ -186,15 +190,6 @@ static const struct ctl_table x86_sysctl_table[] = {
|
|||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
#if defined(CONFIG_X86_LOCAL_APIC)
|
||||
{
|
||||
.procname = "unknown_nmi_panic",
|
||||
.data = &unknown_nmi_panic,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_ACPI_SLEEP)
|
||||
{
|
||||
.procname = "acpi_video_flags",
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ extern bool panic_triggering_all_cpu_backtrace;
|
|||
extern int panic_timeout;
|
||||
extern unsigned long panic_print;
|
||||
extern int panic_on_oops;
|
||||
extern int panic_on_unrecovered_nmi;
|
||||
extern int panic_on_io_nmi;
|
||||
extern int panic_on_warn;
|
||||
|
||||
extern unsigned long panic_on_taint;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user