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)