Browse Source

x86: Ignore NMIs that come in during early boot

Don Zickus reports:

A customer generated an external NMI using their iLO to test kdump
worked.  Unfortunately, the machine hung.  Disabling the nmi_watchdog
made things work.

I speculated the external NMI fired, caused the machine to panic (as
expected) and the perf NMI from the watchdog came in and was latched.
My guess was this somehow caused the hang.

   ----

It appears that the latched NMI stays latched until the early page
table generation on 64 bits, which causes exceptions to happen which
end in IRET, which re-enable NMI.  Therefore, ignore NMIs that come in
during early execution, until we have proper exception handling.

Reported-and-tested-by: Don Zickus <dzickus@redhat.com>
Link: http://lkml.kernel.org/r/1394221143-29713-1-git-send-email-dzickus@redhat.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: <stable@vger.kernel.org> # v3.5+, older with some backport effort
H. Peter Anvin 11 years ago
parent
commit
5fa10196bd
2 changed files with 11 additions and 2 deletions
  1. 6 1
      arch/x86/kernel/head_32.S
  2. 5 1
      arch/x86/kernel/head_64.S

+ 6 - 1
arch/x86/kernel/head_32.S

@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
 	/* This is global to keep gas from relaxing the jumps */
 	/* This is global to keep gas from relaxing the jumps */
 ENTRY(early_idt_handler)
 ENTRY(early_idt_handler)
 	cld
 	cld
+
+	cmpl $X86_TRAP_NMI,(%esp)
+	je is_nmi		# Ignore NMI
+
 	cmpl $2,%ss:early_recursion_flag
 	cmpl $2,%ss:early_recursion_flag
 	je hlt_loop
 	je hlt_loop
 	incl %ss:early_recursion_flag
 	incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
 	pop %edx
 	pop %edx
 	pop %ecx
 	pop %ecx
 	pop %eax
 	pop %eax
-	addl $8,%esp		/* drop vector number and error code */
 	decl %ss:early_recursion_flag
 	decl %ss:early_recursion_flag
+is_nmi:
+	addl $8,%esp		/* drop vector number and error code */
 	iret
 	iret
 ENDPROC(early_idt_handler)
 ENDPROC(early_idt_handler)
 
 

+ 5 - 1
arch/x86/kernel/head_64.S

@@ -343,6 +343,9 @@ early_idt_handlers:
 ENTRY(early_idt_handler)
 ENTRY(early_idt_handler)
 	cld
 	cld
 
 
+	cmpl $X86_TRAP_NMI,(%rsp)
+	je is_nmi		# Ignore NMI
+
 	cmpl $2,early_recursion_flag(%rip)
 	cmpl $2,early_recursion_flag(%rip)
 	jz  1f
 	jz  1f
 	incl early_recursion_flag(%rip)
 	incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
 	popq %rdx
 	popq %rdx
 	popq %rcx
 	popq %rcx
 	popq %rax
 	popq %rax
-	addq $16,%rsp		# drop vector number and error code
 	decl early_recursion_flag(%rip)
 	decl early_recursion_flag(%rip)
+is_nmi:
+	addq $16,%rsp		# drop vector number and error code
 	INTERRUPT_RETURN
 	INTERRUPT_RETURN
 ENDPROC(early_idt_handler)
 ENDPROC(early_idt_handler)