exception.s revision 3c2dd56dbfb8c4849500001eaf67af2c999a92cf
/*
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
*/
/*
* Copyright (c) 1989, 1990 William F. Jolitz.
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/amd64/amd64/exception.S,v 1.113 2003/10/15 02:04:52 peter Exp $
*/
#include <sys/asm_linkage.h>
#include <sys/asm_misc.h>
#include <sys/privregs.h>
#include <sys/x86_archext.h>
#include <sys/traptrace.h>
#include <sys/machparam.h>
/*
* only one routine in this file is interesting to lint
*/
#if defined(__lint)
void
ndptrap_frstor(void)
{}
#else
#include "assym.h"
/*
* push $0 on stack for traps that do not
* generate an error code. This is so the rest
* of the kernel can expect a consistent stack
* from from any exception.
*
* Note that for all exceptions for amd64
* %r11 and %rcx are on the stack. Just pop
* them back into their appropriate registers and let
* it get saved as is running native.
*/
#define NPTRAP_NOERR(trapno) \
pushq $0; \
#define TRAP_NOERR(trapno) \
XPV_TRAP_POP; \
/*
* error code already pushed by hw
* onto stack.
*/
XPV_TRAP_POP; \
#else /* __xpv && __amd64 */
#define TRAP_NOERR(trapno) \
push $0; \
/*
* error code already pushed by hw
* onto stack.
*/
#endif /* __xpv && __amd64 */
/*
* #DE
*/
/*
* #DB
*
* Fetch %dr6 and clear it, handing off the value to the
* cmntrap code in %r15/%esi
*/
#if defined(__amd64)
#if !defined(__xpv) /* no sysenter support yet */
/*
* If we get here as a result of single-stepping a sysenter
* instruction, we suddenly find ourselves taking a #db
* in kernel mode -before- we've swapgs'ed. So before we can
* take the trap, we do the swapgs here, and fix the return
* %rip in trap() so that we return immediately after the
* swapgs in the sysenter handler to avoid doing the swapgs again.
*
* Nobody said that the design of sysenter was particularly
* elegant, did they?
*/
/*
* At this point the stack looks like this:
*
* (high address) r_ss
* r_rsp
* r_rfl
* r_cs
* r_rip <-- %rsp + 24
* r_err <-- %rsp + 16
* r_trapno <-- %rsp + 8
* (low address) %r11 <-- %rsp
*/
je 1f
jne 2f
1: SWAPGS
#endif /* !__xpv */
#if defined(__xpv)
#else
#endif
#if defined(__xpv)
pushl $6
pushl $0
pushl $6
#else
#endif
#endif /* __i386 */
#if defined(__amd64)
#if !defined(__xpv)
/*
* Macro to set the gsbase or kgsbase to the address of the struct cpu
* for this processor. If we came from userland, set kgsbase else
* set gsbase. We find the proper cpu struct by looping through
* the cpu structs for all processors till we find a match for the gdt
* of the trapping processor. The stack is expected to be pointing at
* the standard regs pushed by hardware on a trap (plus error code and trapno).
*/
#define SET_CPU_GSBASE \
1: \
2: \
/* XXX BIG trouble if we fall thru here. We didn't find a gdt match */ \
3: \
mfence; /* OPTERON_ERRATUM_88 */ \
4: \
wrmsr; \
#else /* __xpv */
#define SET_CPU_GSBASE /* noop on the hypervisor */
#endif /* __xpv */
#endif /* __amd64 */
#if defined(__amd64)
/*
* #NMI
*
* XXPV: See 6532669.
*/
/*
* Save all registers and setup segment registers
* with kernel selectors.
*/
/*NOTREACHED*/
/*
* #NMI
*/
/*
* Save all registers and setup segment registers
* with kernel selectors.
*/
#endif /* __i386 */
/*
* #BP
*/
#if defined(__amd64)
/*
* This is a breakpoint in the kernel -- it is very likely that this
* is DTrace-induced. To unify DTrace handling, we spoof this as an
* invalid opcode (#UD) fault. Note that #BP is a trap, not a fault --
* we must decrement the trapping %rip to make it appear as a fault.
* We then push a non-zero error code to indicate that this is coming
* from #BP.
*/
#endif /* __amd64 */
/*
* #OF
*/
/*
* #BR
*/
#if defined(__amd64)
#if defined(__xpv)
#endif
push $0 /* error code -- zero for #UD */
/*
* We must emulate a "pushq %rbp". To do this, we pull the stack
* down 8 bytes, and then store the base pointer.
*/
IRET /* return from interrupt */
/*NOTREACHED*/
/*
* We must emulate a "leave", which is the same as a "movq %rbp, %rsp"
* followed by a "popq %rbp". This is quite a bit simpler on amd64
* than it is on i386 -- we can exploit the fact that the %rsp is
* explicitly saved to effect the pop without having to reshuffle
* the other data pushed for the trap.
*/
IRET /* return from interrupt */
/*NOTREACHED*/
/*
* We must emulate a "nop". This is obviously not hard: we need only
* advance the %rip by one.
*/
/*NOTREACHED*/
IRET /* return from interrupt */
/*NOTREACHED*/
/*
* We're going to let the kernel handle this as a normal #UD. If,
* however, we came through #BP and are spoofing #UD (in this case,
* the stored error value will be non-zero), we need to de-spoof
* the trap by incrementing %rip and pushing T_BPTFLT.
*/
/*
* #UD
*/
/*
* If we are taking an invalid opcode trap while in the kernel, this
* is likely an FBT probe point.
*/
jne 8f
#if defined(__xpv)
#endif /* __xpv */
je 1f
je 2f
je 3f
je 4f
jmp 7f
1:
/*
* We must emulate a "pushl %ebp". To do this, we pull the stack
* down 4 bytes, and then store the base pointer.
*/
2:
/*
* We must emulate a "popl %ebp". To do this, we do the opposite of
* the above: we remove the %ebp from the stack, and squeeze up the
* saved state from the trap.
*/
3:
/*
* We must emulate a "leave", which is the same as a "movl %ebp, %esp"
* followed by a "popl %ebp". This looks similar to the above, but
* requires two temporaries: one for the new base pointer, and one
* for the staging register.
*/
4:
/*
* We must emulate a "nop". This is obviously not hard: we need only
* advance the %eip by one.
*/
IRET /* return from interrupt */
7:
pushl $0
8:
pushl $0
#endif /* __i386 */
#if defined(__amd64)
/*
* #NM
*/
#if defined(__xpv)
/*
* (On the hypervisor we must make a hypercall so we might as well
* save everything and handle as in a normal trap.)
*/
/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in ndptrap_frstor
* below; for all other cases, we let the trap code handle it
*/
#if LWP_PCB_FPU != 0
#endif
#if FPU_CTX_FPU_REGS != 0
#endif
/*
* the label below is used in trap.c to detect FP faults in
* kernel due to user fault.
*/
IRET /* return to user mode */
/*NOTREACHED*/
/*NOTREACHED*/
pushq $0 /* can not use TRAP_NOERR */
#else /* __xpv */
/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in ndptrap_frstor
* below; for all other cases, we let the trap code handle it
*/
jne 1f
jmp 2f
1:
SWAPGS /* if from user, need swapgs */
2:
/*
* Xrstor needs to use edx as part of its flag.
* NOTE: have to push rdx after "cmpw ...24(%rsp)", otherwise rsp+$24
* will not point to CS.
*/
#if LWP_PCB_FPU != 0
#endif
#if FPU_CTX_FPU_REGS != 0
#endif
/*
* the label below is used in trap.c to detect FP faults in
* kernel due to user fault.
*/
/*NOTREACHED*/
#endif /* __xpv */
/*
* We want to do this quickly as every lwp using fp will take this
* after a context switch -- we do the frequent path in fpnoextflt
* below; for all other cases, we let the trap code handle it
*/
cmpl $0, fpu_exists
#if LWP_PCB_FPU != 0
#endif
#if FPU_CTX_FPU_REGS != 0
#endif
/*
* the label below is used in trap.c to detect FP faults in kernel
* due to user fault.
*/
nop /* (including this byte) */
#endif /* __i386 */
#if !defined(__xpv)
#if defined(__amd64)
/*
* #DF
*/
/*
* We share this handler with kmdb (if kmdb is loaded). As such, we
* may have reached this point after encountering a #df in kmdb. If
* that happens, we'll still be on kmdb's IDT. We need to switch back
* to this CPU's IDT before proceeding. Furthermore, if we did arrive
* here from kmdb, kmdb is probably in a very sickly state, and
* shouldn't be entered from the panic flow. We'll suppress that
* entry by setting nopanicdebug.
*/
je 1f
/*
* freeze trap trace.
*/
#ifdef TRAPTRACE
#endif
/*
* #DF
*/
cli /* disable interrupts */
/*
* We share this handler with kmdb (if kmdb is loaded). As such, we
* may have reached this point after encountering a #df in kmdb. If
* that happens, we'll still be on kmdb's IDT. We need to switch back
* to this CPU's IDT before proceeding. Furthermore, if we did arrive
* here from kmdb, kmdb is probably in a very sickly state, and
* shouldn't be entered from the panic flow. We'll suppress that
* entry by setting nopanicdebug.
*/
je 1f
/*
* Check the CPL in the TSS to see what mode
* (user or kernel) we took the fault in. At this
* point we are running in the context of the double
* fault task (dftss) but the CPU's task points to
* the previous task (ktss) where the process context
* has been saved as the result of the task switch.
*/
/*
* Clear the NT flag to avoid a task switch when the process
* finally pops the EFL off the stack via an iret. Clear
* the TF flag since that is what the processor does for
* a normal exception. Clear the IE flag so that interrupts
* remain disabled.
*/
popfl /* restore the EFL */
/*
* Restore process segment selectors.
*/
/*
* Restore task segment selectors.
*/
/*
* Clear the TS bit, the busy bits in both task
* descriptors, and switch tasks.
*/
/*
* Restore part of the process registers.
*/
/*
* Make a trap frame. Leave the error code (0) on
* the stack since the first word on a trap stack is
* unused anyway.
*/
#endif /* __i386 */
#endif /* !__xpv */
push $0
/*
* #TS
*/
/*
* #NP
*/
#if defined(__amd64)
#endif
/*
* #SS
*/
#if defined(__amd64)
#endif
/*
* #GP
*/
#if defined(__amd64)
#endif
/*
* #PF
*/
#if defined(__xpv)
#if defined(__amd64)
#endif /* __i386 */
#else /* __xpv */
#if defined(__amd64)
#endif /* __i386 */
#endif /* __xpv */
#if !defined(__amd64)
/*
* #PF pentium bug workaround
*/
/*
* Before we assume that we have an unmapped trap on our hands,
* check to see if this is a fault from user mode. If it is,
* we'll kick back into the page fault handler.
*/
/*
* We now know that this is the invalid opcode trap.
*/
#endif /* !__amd64 */
/*
* #MF
*/
/*
* #AC
*/
/*
* #MC
*/
#if defined(__amd64)
#else
#endif
/*
* #XF
*/
#if defined(__amd64)
ja 1f
1:
/*
* Fast syscall number was illegal. Make it look
* as if the INT failed. Modify %rip to point before the
* INT, push the expected error code and fake a GP fault.
*
* XXX Why make the error code be offset into idt + 1?
* Instead we should push a real (soft?) error code
* on the stack and #gp handler could know about fasttraps?
*/
#if defined(__xpv)
#endif
ja 1f
1:
/*
* Fast syscall number was illegal. Make it look
* as if the INT failed. Modify %eip to point before the
* INT, push the expected error code and fake a GP fault.
*
* XXX Why make the error code be offset into idt + 1?
* Instead we should push a real (soft?) error code
* on the stack and #gp handler could know about fasttraps?
*/
#endif /* __i386 */
#if defined(__amd64)
/*
* RFLAGS 24 bytes up the stack from %rsp.
* XXX a constant would be nicer.
*/
/*NOTREACHED*/
#endif /* __i386 */
/*
* Interrupts start at 32
*/
#define MKIVCT(n) \
push $0; \
push $n - 0x20; \
MKIVCT(32)
MKIVCT(33)
MKIVCT(34)
MKIVCT(35)
MKIVCT(36)
MKIVCT(37)
MKIVCT(38)
MKIVCT(39)
MKIVCT(40)
MKIVCT(41)
MKIVCT(42)
MKIVCT(43)
MKIVCT(44)
MKIVCT(45)
MKIVCT(46)
MKIVCT(47)
MKIVCT(48)
MKIVCT(49)
MKIVCT(50)
MKIVCT(51)
MKIVCT(52)
MKIVCT(53)
MKIVCT(54)
MKIVCT(55)
MKIVCT(56)
MKIVCT(57)
MKIVCT(58)
MKIVCT(59)
MKIVCT(60)
MKIVCT(61)
MKIVCT(62)
MKIVCT(63)
MKIVCT(64)
MKIVCT(65)
MKIVCT(66)
MKIVCT(67)
MKIVCT(68)
MKIVCT(69)
MKIVCT(70)
MKIVCT(71)
MKIVCT(72)
MKIVCT(73)
MKIVCT(74)
MKIVCT(75)
MKIVCT(76)
MKIVCT(77)
MKIVCT(78)
MKIVCT(79)
MKIVCT(80)
MKIVCT(81)
MKIVCT(82)
MKIVCT(83)
MKIVCT(84)
MKIVCT(85)
MKIVCT(86)
MKIVCT(87)
MKIVCT(88)
MKIVCT(89)
MKIVCT(90)
MKIVCT(91)
MKIVCT(92)
MKIVCT(93)
MKIVCT(94)
MKIVCT(95)
MKIVCT(96)
MKIVCT(97)
MKIVCT(98)
MKIVCT(99)
MKIVCT(100)
MKIVCT(101)
MKIVCT(102)
MKIVCT(103)
MKIVCT(104)
MKIVCT(105)
MKIVCT(106)
MKIVCT(107)
MKIVCT(108)
MKIVCT(109)
MKIVCT(110)
MKIVCT(111)
MKIVCT(112)
MKIVCT(113)
MKIVCT(114)
MKIVCT(115)
MKIVCT(116)
MKIVCT(117)
MKIVCT(118)
MKIVCT(119)
MKIVCT(120)
MKIVCT(121)
MKIVCT(122)
MKIVCT(123)
MKIVCT(124)
MKIVCT(125)
MKIVCT(126)
MKIVCT(127)
MKIVCT(128)
MKIVCT(129)
MKIVCT(130)
MKIVCT(131)
MKIVCT(132)
MKIVCT(133)
MKIVCT(134)
MKIVCT(135)
MKIVCT(136)
MKIVCT(137)
MKIVCT(138)
MKIVCT(139)
MKIVCT(140)
MKIVCT(141)
MKIVCT(142)
MKIVCT(143)
MKIVCT(144)
MKIVCT(145)
MKIVCT(146)
MKIVCT(147)
MKIVCT(148)
MKIVCT(149)
MKIVCT(150)
MKIVCT(151)
MKIVCT(152)
MKIVCT(153)
MKIVCT(154)
MKIVCT(155)
MKIVCT(156)
MKIVCT(157)
MKIVCT(158)
MKIVCT(159)
MKIVCT(160)
MKIVCT(161)
MKIVCT(162)
MKIVCT(163)
MKIVCT(164)
MKIVCT(165)
MKIVCT(166)
MKIVCT(167)
MKIVCT(168)
MKIVCT(169)
MKIVCT(170)
MKIVCT(171)
MKIVCT(172)
MKIVCT(173)
MKIVCT(174)
MKIVCT(175)
MKIVCT(176)
MKIVCT(177)
MKIVCT(178)
MKIVCT(179)
MKIVCT(180)
MKIVCT(181)
MKIVCT(182)
MKIVCT(183)
MKIVCT(184)
MKIVCT(185)
MKIVCT(186)
MKIVCT(187)
MKIVCT(188)
MKIVCT(189)
MKIVCT(190)
MKIVCT(191)
MKIVCT(192)
MKIVCT(193)
MKIVCT(194)
MKIVCT(195)
MKIVCT(196)
MKIVCT(197)
MKIVCT(198)
MKIVCT(199)
MKIVCT(200)
MKIVCT(201)
MKIVCT(202)
MKIVCT(203)
MKIVCT(204)
MKIVCT(205)
MKIVCT(206)
MKIVCT(207)
MKIVCT(208)
MKIVCT(209)
MKIVCT(210)
MKIVCT(211)
MKIVCT(212)
MKIVCT(213)
MKIVCT(214)
MKIVCT(215)
MKIVCT(216)
MKIVCT(217)
MKIVCT(218)
MKIVCT(219)
MKIVCT(220)
MKIVCT(221)
MKIVCT(222)
MKIVCT(223)
MKIVCT(224)
MKIVCT(225)
MKIVCT(226)
MKIVCT(227)
MKIVCT(228)
MKIVCT(229)
MKIVCT(230)
MKIVCT(231)
MKIVCT(232)
MKIVCT(233)
MKIVCT(234)
MKIVCT(235)
MKIVCT(236)
MKIVCT(237)
MKIVCT(238)
MKIVCT(239)
MKIVCT(240)
MKIVCT(241)
MKIVCT(242)
MKIVCT(243)
MKIVCT(244)
MKIVCT(245)
MKIVCT(246)
MKIVCT(247)
MKIVCT(248)
MKIVCT(249)
MKIVCT(250)
MKIVCT(251)
MKIVCT(252)
MKIVCT(253)
MKIVCT(254)
MKIVCT(255)
#endif /* __lint */