Skip to content

Commit d6680b0

Browse files
author
Ingo Molnar
committed
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: 6f5bf94 Merge tag 'its-for-linus-20250509' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Signed-off-by: Ingo Molnar <[email protected]>
2 parents 1f82e8e + f2e01dc commit d6680b0

File tree

7 files changed

+121
-107
lines changed

7 files changed

+121
-107
lines changed

arch/x86/include/asm/nmi.h

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,26 @@ extern void release_perfctr_nmi(unsigned int);
1414
extern int reserve_evntsel_nmi(unsigned int);
1515
extern void release_evntsel_nmi(unsigned int);
1616

17-
extern int unknown_nmi_panic;
18-
1917
#endif /* CONFIG_X86_LOCAL_APIC */
2018

19+
extern int unknown_nmi_panic;
20+
extern int panic_on_unrecovered_nmi;
21+
extern int panic_on_io_nmi;
22+
23+
/* NMI handler flags */
2124
#define NMI_FLAG_FIRST 1
2225

26+
/**
27+
* enum - NMI types.
28+
* @NMI_LOCAL: Local NMI, CPU-specific NMI generated by the Local APIC.
29+
* @NMI_UNKNOWN: Unknown NMI, the source of the NMI may not be identified.
30+
* @NMI_SERR: System Error NMI, typically triggered by PCI errors.
31+
* @NMI_IO_CHECK: I/O Check NMI, related to I/O errors.
32+
* @NMI_MAX: Maximum value for NMI types.
33+
*
34+
* NMI types are used to categorize NMIs and to dispatch them to the
35+
* appropriate handler.
36+
*/
2337
enum {
2438
NMI_LOCAL=0,
2539
NMI_UNKNOWN,
@@ -28,6 +42,7 @@ enum {
2842
NMI_MAX
2943
};
3044

45+
/* NMI handler return values */
3146
#define NMI_DONE 0
3247
#define NMI_HANDLED 1
3348

@@ -41,6 +56,25 @@ struct nmiaction {
4156
const char *name;
4257
};
4358

59+
/**
60+
* register_nmi_handler - Register a handler for a specific NMI type
61+
* @t: NMI type (e.g. NMI_LOCAL)
62+
* @fn: The NMI handler
63+
* @fg: Flags associated with the NMI handler
64+
* @n: Name of the NMI handler
65+
* @init: Optional __init* attributes for struct nmiaction
66+
*
67+
* Adds the provided handler to the list of handlers for the specified
68+
* NMI type. Handlers flagged with NMI_FLAG_FIRST would be executed first.
69+
*
70+
* Sometimes the source of an NMI can't be reliably determined which
71+
* results in an NMI being tagged as "unknown". Register an additional
72+
* handler using the NMI type - NMI_UNKNOWN to handle such cases. The
73+
* caller would get one last chance to assume responsibility for the
74+
* NMI.
75+
*
76+
* Return: 0 on success, or an error code on failure.
77+
*/
4478
#define register_nmi_handler(t, fn, fg, n, init...) \
4579
({ \
4680
static struct nmiaction init fn##_na = { \
@@ -54,7 +88,16 @@ struct nmiaction {
5488

5589
int __register_nmi_handler(unsigned int, struct nmiaction *);
5690

57-
void unregister_nmi_handler(unsigned int, const char *);
91+
/**
92+
* unregister_nmi_handler - Unregister a handler for a specific NMI type
93+
* @type: NMI type (e.g. NMI_LOCAL)
94+
* @name: Name of the NMI handler used during registration
95+
*
96+
* Removes the handler associated with the specified NMI type from the
97+
* NMI handler list. The "name" is used as a lookup key to identify the
98+
* handler.
99+
*/
100+
void unregister_nmi_handler(unsigned int type, const char *name);
58101

59102
void set_emergency_nmi_handler(unsigned int type, nmi_handler_t handler);
60103

arch/x86/include/asm/x86_init.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ struct x86_hyper_runtime {
292292
* @set_wallclock: set time back to HW clock
293293
* @is_untracked_pat_range exclude from PAT logic
294294
* @nmi_init enable NMI on cpus
295+
* @get_nmi_reason get the reason an NMI was received
295296
* @save_sched_clock_state: save state for sched_clock() on suspend
296297
* @restore_sched_clock_state: restore state for sched_clock() on resume
297298
* @apic_post_init: adjust apic if needed

arch/x86/kernel/dumpstack.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
#include <asm/stacktrace.h>
2424
#include <asm/unwind.h>
2525

26-
int panic_on_unrecovered_nmi;
27-
int panic_on_io_nmi;
2826
static int die_counter;
2927

3028
static struct pt_regs exec_summary_regs;

arch/x86/kernel/nmi.c

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,20 @@ struct nmi_desc {
4949
struct list_head head;
5050
};
5151

52-
static struct nmi_desc nmi_desc[NMI_MAX] =
53-
{
54-
{
55-
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[0].lock),
56-
.head = LIST_HEAD_INIT(nmi_desc[0].head),
57-
},
58-
{
59-
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[1].lock),
60-
.head = LIST_HEAD_INIT(nmi_desc[1].head),
61-
},
62-
{
63-
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[2].lock),
64-
.head = LIST_HEAD_INIT(nmi_desc[2].head),
65-
},
66-
{
67-
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[3].lock),
68-
.head = LIST_HEAD_INIT(nmi_desc[3].head),
69-
},
52+
#define NMI_DESC_INIT(type) { \
53+
.lock = __RAW_SPIN_LOCK_UNLOCKED(&nmi_desc[type].lock), \
54+
.head = LIST_HEAD_INIT(nmi_desc[type].head), \
55+
}
7056

57+
static struct nmi_desc nmi_desc[NMI_MAX] = {
58+
NMI_DESC_INIT(NMI_LOCAL),
59+
NMI_DESC_INIT(NMI_UNKNOWN),
60+
NMI_DESC_INIT(NMI_SERR),
61+
NMI_DESC_INIT(NMI_IO_CHECK),
7162
};
7263

64+
#define nmi_to_desc(type) (&nmi_desc[type])
65+
7366
struct nmi_stats {
7467
unsigned int normal;
7568
unsigned int unknown;
@@ -91,6 +84,9 @@ static DEFINE_PER_CPU(struct nmi_stats, nmi_stats);
9184
static int ignore_nmis __read_mostly;
9285

9386
int unknown_nmi_panic;
87+
int panic_on_unrecovered_nmi;
88+
int panic_on_io_nmi;
89+
9490
/*
9591
* Prevent NMI reason port (0x61) being accessed simultaneously, can
9692
* only be used in NMI handler.
@@ -104,8 +100,6 @@ static int __init setup_unknown_nmi_panic(char *str)
104100
}
105101
__setup("unknown_nmi_panic", setup_unknown_nmi_panic);
106102

107-
#define nmi_to_desc(type) (&nmi_desc[type])
108-
109103
static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
110104

111105
static int __init nmi_warning_debugfs(void)
@@ -125,12 +119,12 @@ static void nmi_check_duration(struct nmiaction *action, u64 duration)
125119

126120
action->max_duration = duration;
127121

128-
remainder_ns = do_div(duration, (1000 * 1000));
129-
decimal_msecs = remainder_ns / 1000;
122+
/* Convert duration from nsec to msec */
123+
remainder_ns = do_div(duration, NSEC_PER_MSEC);
124+
decimal_msecs = remainder_ns / NSEC_PER_USEC;
130125

131-
printk_ratelimited(KERN_INFO
132-
"INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
133-
action->handler, duration, decimal_msecs);
126+
pr_info_ratelimited("INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
127+
action->handler, duration, decimal_msecs);
134128
}
135129

136130
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)
333327
int handled;
334328

335329
/*
336-
* Use 'false' as back-to-back NMIs are dealt with one level up.
337-
* Of course this makes having multiple 'unknown' handlers useless
338-
* as only the first one is ever run (unless it can actually determine
339-
* if it caused the NMI)
330+
* As a last resort, let the "unknown" handlers make a
331+
* best-effort attempt to figure out if they can claim
332+
* responsibility for this Unknown NMI.
340333
*/
341334
handled = nmi_handle(NMI_UNKNOWN, regs);
342335
if (handled) {
@@ -366,17 +359,18 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
366359
bool b2b = false;
367360

368361
/*
369-
* CPU-specific NMI must be processed before non-CPU-specific
370-
* NMI, otherwise we may lose it, because the CPU-specific
371-
* NMI can not be detected/processed on other CPUs.
372-
*/
373-
374-
/*
375-
* Back-to-back NMIs are interesting because they can either
376-
* be two NMI or more than two NMIs (any thing over two is dropped
377-
* due to NMI being edge-triggered). If this is the second half
378-
* of the back-to-back NMI, assume we dropped things and process
379-
* more handlers. Otherwise reset the 'swallow' NMI behaviour
362+
* Back-to-back NMIs are detected by comparing the RIP of the
363+
* current NMI with that of the previous NMI. If it is the same,
364+
* it is assumed that the CPU did not have a chance to jump back
365+
* into a non-NMI context and execute code in between the two
366+
* NMIs.
367+
*
368+
* They are interesting because even if there are more than two,
369+
* only a maximum of two can be detected (anything over two is
370+
* dropped due to NMI being edge-triggered). If this is the
371+
* second half of the back-to-back NMI, assume we dropped things
372+
* and process more handlers. Otherwise, reset the 'swallow' NMI
373+
* behavior.
380374
*/
381375
if (regs->ip == __this_cpu_read(last_nmi_rip))
382376
b2b = true;
@@ -390,6 +384,11 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
390384
if (microcode_nmi_handler_enabled() && microcode_nmi_handler())
391385
goto out;
392386

387+
/*
388+
* CPU-specific NMI must be processed before non-CPU-specific
389+
* NMI, otherwise we may lose it, because the CPU-specific
390+
* NMI can not be detected/processed on other CPUs.
391+
*/
393392
handled = nmi_handle(NMI_LOCAL, regs);
394393
__this_cpu_add(nmi_stats.normal, handled);
395394
if (handled) {
@@ -426,13 +425,14 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
426425
pci_serr_error(reason, regs);
427426
else if (reason & NMI_REASON_IOCHK)
428427
io_check_error(reason, regs);
429-
#ifdef CONFIG_X86_32
428+
430429
/*
431430
* Reassert NMI in case it became active
432431
* meanwhile as it's edge-triggered:
433432
*/
434-
reassert_nmi();
435-
#endif
433+
if (IS_ENABLED(CONFIG_X86_32))
434+
reassert_nmi();
435+
436436
__this_cpu_add(nmi_stats.external, 1);
437437
raw_spin_unlock(&nmi_reason_lock);
438438
goto out;
@@ -751,4 +751,3 @@ void local_touch_nmi(void)
751751
{
752752
__this_cpu_write(last_nmi_rip, 0);
753753
}
754-
EXPORT_SYMBOL_GPL(local_touch_nmi);

arch/x86/kernel/nmi_selftest.c

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* arch/x86/kernel/nmi-selftest.c
4-
*
53
* Testsuite for NMI: IPIs
64
*
75
* Started by Don Zickus:
@@ -30,7 +28,6 @@ static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata;
3028

3129
static int __initdata testcase_total;
3230
static int __initdata testcase_successes;
33-
static int __initdata expected_testcase_failures;
3431
static int __initdata unexpected_testcase_failures;
3532
static int __initdata unexpected_testcase_unknowns;
3633

@@ -120,65 +117,48 @@ static void __init dotest(void (*testcase_fn)(void), int expected)
120117
unexpected_testcase_failures++;
121118

122119
if (nmi_fail == FAILURE)
123-
printk(KERN_CONT "FAILED |");
120+
pr_cont("FAILED |");
124121
else if (nmi_fail == TIMEOUT)
125-
printk(KERN_CONT "TIMEOUT|");
122+
pr_cont("TIMEOUT|");
126123
else
127-
printk(KERN_CONT "ERROR |");
124+
pr_cont("ERROR |");
128125
dump_stack();
129126
} else {
130127
testcase_successes++;
131-
printk(KERN_CONT " ok |");
128+
pr_cont(" ok |");
132129
}
133-
testcase_total++;
130+
pr_cont("\n");
134131

132+
testcase_total++;
135133
reset_nmi();
136134
}
137135

138-
static inline void __init print_testname(const char *testname)
139-
{
140-
printk("%12s:", testname);
141-
}
142-
143136
void __init nmi_selftest(void)
144137
{
145138
init_nmi_testsuite();
146139

147140
/*
148141
* Run the testsuite:
149142
*/
150-
printk("----------------\n");
151-
printk("| NMI testsuite:\n");
152-
printk("--------------------\n");
143+
pr_info("----------------\n");
144+
pr_info("| NMI testsuite:\n");
145+
pr_info("--------------------\n");
153146

154-
print_testname("remote IPI");
147+
pr_info("%12s:", "remote IPI");
155148
dotest(remote_ipi, SUCCESS);
156-
printk(KERN_CONT "\n");
157-
print_testname("local IPI");
149+
150+
pr_info("%12s:", "local IPI");
158151
dotest(local_ipi, SUCCESS);
159-
printk(KERN_CONT "\n");
160152

161153
cleanup_nmi_testsuite();
162154

155+
pr_info("--------------------\n");
163156
if (unexpected_testcase_failures) {
164-
printk("--------------------\n");
165-
printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n",
157+
pr_info("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n",
166158
unexpected_testcase_failures, testcase_total);
167-
printk("-----------------------------------------------------------------\n");
168-
} else if (expected_testcase_failures && testcase_successes) {
169-
printk("--------------------\n");
170-
printk("%3d out of %3d testcases failed, as expected. |\n",
171-
expected_testcase_failures, testcase_total);
172-
printk("----------------------------------------------------\n");
173-
} else if (expected_testcase_failures && !testcase_successes) {
174-
printk("--------------------\n");
175-
printk("All %3d testcases failed, as expected. |\n",
176-
expected_testcase_failures);
177-
printk("----------------------------------------\n");
178159
} else {
179-
printk("--------------------\n");
180-
printk("Good, all %3d testcases passed! |\n",
160+
pr_info("Good, all %3d testcases passed! |\n",
181161
testcase_successes);
182-
printk("---------------------------------\n");
183162
}
163+
pr_info("-----------------------------------------------------------------\n");
184164
}

0 commit comments

Comments
 (0)