Module Name:    src
Committed By:   maxv
Date:           Fri Mar 24 18:03:32 UTC 2017

Modified Files:
        src/sys/arch/amd64/amd64: amd64_trap.S

Log Message:
Unconditionnally save the segment registers - because we could have a
kernel %gs and a userland %es/%ds -, and explain why T_NMI is a special
case.

Note that checking %gs directly is not a good idea: recent CPUs have the
FSGSBASE instruction set, which allows userland to directly modify %gs
without going through the kernel. If we ever enable this set, we will have
to change this function, since we won't be able to test %gs against
VM_MIN_KERNEL_ADDRESS anymore.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/amd64/amd64/amd64_trap.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/amd64/amd64/amd64_trap.S
diff -u src/sys/arch/amd64/amd64/amd64_trap.S:1.4 src/sys/arch/amd64/amd64/amd64_trap.S:1.5
--- src/sys/arch/amd64/amd64/amd64_trap.S:1.4	Sun Aug  7 09:04:55 2016
+++ src/sys/arch/amd64/amd64/amd64_trap.S	Fri Mar 24 18:03:32 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: amd64_trap.S,v 1.4 2016/08/07 09:04:55 maxv Exp $	*/
+/*	$NetBSD: amd64_trap.S,v 1.5 2017/03/24 18:03:32 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
 
 #if 0
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: amd64_trap.S,v 1.4 2016/08/07 09:04:55 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amd64_trap.S,v 1.5 2017/03/24 18:03:32 maxv Exp $");
 #endif
 
 /*
@@ -103,39 +103,54 @@ IDTVEC(trap01)
 	ZTRAP(T_TRCTRAP)
 IDTVEC_END(trap01)
 
+/*
+ * Non Maskable Interrupts are a special case: they can be triggered even
+ * with interrupts disabled, and once triggered they block further NMIs
+ * until an 'iret' instruction is executed.
+ *
+ * Therefore we don't enable interrupts, because the CPU could switch to
+ * another LWP, call 'iret' and unintentionally leave the NMI mode.
+ *
+ * We need to be careful about %gs too, because it is possible that we were
+ * running in kernel mode with a userland %gs.
+ */
 IDTVEC(trap02)
 #if defined(XEN)
 	ZTRAP(T_NMI)
-#else /* defined(XEN) */
-	pushq $0
-	pushq $T_NMI
+#else
+	pushq	$0
+	pushq	$T_NMI
 	subq	$TF_REGSIZE,%rsp
 	INTR_SAVE_GPRS
-	movl	$MSR_GSBASE,%ecx
-	rdmsr
-	cmpl	$VM_MIN_KERNEL_ADDRESS_HIGH32,%edx
-	jae	1f
-	swapgs
 	movw	%gs,TF_GS(%rsp)
 	movw	%fs,TF_FS(%rsp)
 	movw	%es,TF_ES(%rsp)
 	movw	%ds,TF_DS(%rsp)
+
+	movl	$MSR_GSBASE,%ecx
+	rdmsr
+	cmpl	$VM_MIN_KERNEL_ADDRESS_HIGH32,%edx
+	jae	noswapgs
+
+	swapgs
 	movq	%rsp,%rdi
 	incq	CPUVAR(NTRAP)
 	call	_C_LABEL(trap)
-	movw	TF_ES(%rsp),%es
-	movw	TF_DS(%rsp),%ds
 	swapgs
-	jmp	2f
-1:
+	jmp	nmileave
+
+noswapgs:
 	movq	%rsp,%rdi
 	incq	CPUVAR(NTRAP)
 	call	_C_LABEL(trap)
-2:
+
+nmileave:
+	movw	TF_ES(%rsp),%es
+	movw	TF_DS(%rsp),%ds
 	INTR_RESTORE_GPRS
 	addq	$TF_REGSIZE+16,%rsp
 	iretq
-#endif /* defined(XEN) */
+#endif
 IDTVEC_END(trap02)
 
 IDTVEC(trap03)

Reply via email to