[PATCH 1/2] boot: ignore early NMIs

Eric W. Biederman ebiederm at xmission.com
Wed Mar 7 23:41:05 EST 2012


Fernando Luis Vázquez Cao <fernando at oss.ntt.co.jp> writes:

> Subject: [PATCH] boot: ignore early NMIs
>
> From: Fernando Luis Vazquez Cao <fernando at oss.ntt.co.jp>
>
> NMIs very early in the boot process are rarely critical (usually
> it just means that there was a spurious bit flip somewhere in the
> hardware, or that this is a kdump kernel and we received an NMI
> generated in the previous context), so the current behavior of
> halting the system when one occurs is probably a bit over the top.
>
> This patch changes the early IDT so that NMIs are ignored and the
> kernel can, hopefully, continue executing other code. Harsher
> measures (panic, etc) are defered to the final NMI handler, which
> can actually make an informed decision.
>
> This issue presented itself in our environment as seemingly
> random hangs in kdump.
>
> Signed-off-by: Fernando Luis Vazquez Cao <fernando at oss.ntt.co.jp>
> ---
>
> diff -urNp linux-3.3-rc6-orig/arch/x86/kernel/head64.c linux-3.3-rc6/arch/x86/kernel/head64.c
> --- linux-3.3-rc6-orig/arch/x86/kernel/head64.c	2012-03-07 15:49:01.834241787 +0900
> +++ linux-3.3-rc6/arch/x86/kernel/head64.c	2012-03-07 18:39:03.173732875 +0900
> @@ -71,7 +71,7 @@ void __init x86_64_start_kernel(char * r
>  				(__START_KERNEL & PGDIR_MASK)));
>  	BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
>  
> -	/* clear bss before set_intr_gate with early_idt_handler */
> +	/* clear bss before set_intr_gate with early_idt_handlers */
>  	clear_bss();
>  
>  	/* Make NULL pointers segfault */
> @@ -79,13 +79,8 @@ void __init x86_64_start_kernel(char * r
>  
>  	max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
>  
> -	for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) {
> -#ifdef CONFIG_EARLY_PRINTK
> +	for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
>  		set_intr_gate(i, &early_idt_handlers[i]);
> -#else
> -		set_intr_gate(i, early_idt_handler);
> -#endif
> -	}
>  	load_idt((const struct desc_ptr *)&idt_descr);
>  
>  	if (console_loglevel == 10)
> diff -urNp linux-3.3-rc6-orig/arch/x86/kernel/head_64.S linux-3.3-rc6/arch/x86/kernel/head_64.S
> --- linux-3.3-rc6-orig/arch/x86/kernel/head_64.S	2012-03-07 15:49:01.838241839 +0900
> +++ linux-3.3-rc6/arch/x86/kernel/head_64.S	2012-03-07 18:41:21.811516876 +0900
> @@ -270,18 +270,29 @@ bad_address:
>  	jmp bad_address
>  
>  	.section ".init.text","ax"
> -#ifdef CONFIG_EARLY_PRINTK
>  	.globl early_idt_handlers
>  early_idt_handlers:
> -	i = 0
> +	vector = 0
>  	.rept NUM_EXCEPTION_VECTORS
> -	movl $i, %esi
> -	jmp early_idt_handler
> -	i = i + 1
> +	/*
> +	 * NMIs (vector 2) this early in the boot process are rarely critical
> +	 * (usually it just means that there was a spurious bit flip somewhere
> +	 * in the hardware, or that this is a kdump kernel and we received an
> +	 * NMI generated in the previous context), so we ignore them here and
> +	 * try to continue (see early_nmi_handler implementation below).
> +	 * Harsher measures (panic, etc) are defered to the final NMI handler,
> +	 * which can actually make an informed decision.
> +	 */
> +	.if vector == 2
> +	jmp early_nmi_handler

Is just a jump and not a move followed by a jump still 10 bytes?
I hate to say it but I think this fails miserably for any exception
after a nmi.

I expect the simplest solution is to modify early_idt_handler to test
for vector == 2.

Doing something less brittle than:
> extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10];
in segment.h might be a good idea as well.

Eric

> +	.else
> +	movl $vector, %esi
> +	jmp early_exception_handler
> +	.endif
> +	vector = vector + 1
>  	.endr
> -#endif
>  
> -ENTRY(early_idt_handler)
> +early_exception_handler:
>  #ifdef CONFIG_EARLY_PRINTK
>  	cmpl $2,early_recursion_flag(%rip)
>  	jz  1f
> @@ -315,6 +326,9 @@ ENTRY(early_idt_handler)
>  1:	hlt
>  	jmp 1b
>  
> +early_nmi_handler:
> +	iretq
> +
>  #ifdef CONFIG_EARLY_PRINTK
>  early_recursion_flag:
>  	.long 0



More information about the kexec mailing list