diff --git a/sys/arch/amd64/amd64/amd64_trap.S b/sys/arch/amd64/amd64/amd64_trap.S index cef01b5d4911..556074992ad0 100644 --- a/sys/arch/amd64/amd64/amd64_trap.S +++ b/sys/arch/amd64/amd64/amd64_trap.S @@ -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 -__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) + swapgs + jmp nmileave + +noswapgs: + movq %rsp,%rdi + incq CPUVAR(NTRAP) + call _C_LABEL(trap) + +nmileave: movw TF_ES(%rsp),%es movw TF_DS(%rsp),%ds - swapgs - jmp 2f -1: - movq %rsp,%rdi - incq CPUVAR(NTRAP) - call _C_LABEL(trap) -2: INTR_RESTORE_GPRS addq $TF_REGSIZE+16,%rsp iretq -#endif /* defined(XEN) */ +#endif IDTVEC_END(trap02) IDTVEC(trap03)