arch/x86/kernel/nmi.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/nmi.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/nmi.c
Extension
.c
Size
21674 bytes
Lines
752
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct nmi_desc {
	raw_spinlock_t lock;
	nmi_handler_t emerg_handler;
	struct list_head 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;
	unsigned int external;
	unsigned int swallow;
	unsigned long recv_jiffies;
	unsigned long idt_seq;
	unsigned long idt_nmi_seq;
	unsigned long idt_ignored;
	atomic_long_t idt_calls;
	unsigned long idt_seq_snap;
	unsigned long idt_nmi_seq_snap;
	unsigned long idt_ignored_snap;
	long idt_calls_snap;
};

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.
 */
static DEFINE_RAW_SPINLOCK(nmi_reason_lock);

static int __init setup_unknown_nmi_panic(char *str)
{
	unknown_nmi_panic = 1;
	return 1;
}
__setup("unknown_nmi_panic", setup_unknown_nmi_panic);

static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;

static int __init nmi_warning_debugfs(void)
{
	debugfs_create_u64("nmi_longest_ns", 0644,
			arch_debugfs_dir, &nmi_longest_ns);
	return 0;
}
fs_initcall(nmi_warning_debugfs);

static void nmi_check_duration(struct nmiaction *action, u64 duration)
{
	int remainder_ns, decimal_msecs;

	if (duration < nmi_longest_ns || duration < action->max_duration)
		return;

	action->max_duration = duration;

	/* Convert duration from nsec to msec */
	remainder_ns = do_div(duration, NSEC_PER_MSEC);
	decimal_msecs = remainder_ns / NSEC_PER_USEC;

	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)
{
	struct nmi_desc *desc = nmi_to_desc(type);
	nmi_handler_t ehandler;
	struct nmiaction *a;
	int handled=0;

Annotation

Implementation Notes