/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * 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 * documentation and/or other materials provided with the distribution. * 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 $ */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include /* * 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. */ #define TRAP_NOERR(trapno) \ push $0; \ push $trapno /* * error code already pushed by hw * onto stack. */ #define TRAP_ERR(trapno) \ push $trapno /* * #DE */ ENTRY_NP(div0trap) TRAP_NOERR(T_ZERODIV) /* $0 */ jmp cmntrap SET_SIZE(div0trap) #if defined(__amd64) /* * #DB * * 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? */ ENTRY_NP(dbgtrap) pushq %r11 leaq sys_sysenter(%rip), %r11 cmpq %r11, 8(%rsp) jne 1f swapgs 1: popq %r11 TRAP_NOERR(T_SGLSTP) /* $1 */ jmp cmntrap SET_SIZE(dbgtrap) #elif defined(__i386) /* * #DB */ ENTRY_NP(dbgtrap) TRAP_NOERR(T_SGLSTP) /* $1 */ jmp cmntrap SET_SIZE(dbgtrap) #endif #if defined(__amd64) /* * 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 clear * gs and 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 \ subq $REGOFF_TRAPNO, %rsp; /* save regs */ \ movq %rax, REGOFF_RAX(%rsp); \ movq %rbx, REGOFF_RBX(%rsp); \ movq %rcx, REGOFF_RCX(%rsp); \ movq %rdx, REGOFF_RDX(%rsp); \ movq %rbp, REGOFF_RBP(%rsp); \ movq %rsp, %rbp; \ subq $16, %rsp; /* space for gdt */ \ sgdt 6(%rsp); \ movq 8(%rsp), %rcx; /* %rcx has gdt to match */ \ xorl %ebx, %ebx; /* loop index */ \ leaq cpu(%rip), %rdx; /* cpu pointer array */ \ 1: \ movq (%rdx, %rbx, CLONGSIZE), %rax; /* get cpu[i] */ \ cmpq $0x0, %rax; /* cpu[i] == NULL ? */ \ je 2f; /* yes, continue */ \ cmpq %rcx, CPU_GDT(%rax); /* gdt == cpu[i]->cpu_gdt ? */ \ je 3f; /* yes, go set gsbase */ \ 2: \ incl %ebx; /* i++ */ \ cmpl $NCPU, %ebx; /* i < NCPU ? */ \ jb 1b; /* yes, loop */ \ /* XXX BIG trouble if we fall thru here. We didn't find a gdt match */ \ 3: \ movl $MSR_AMD_KGSBASE, %ecx; \ cmpw $KCS_SEL, REGOFF_CS(%rbp); /* trap from kernel? */ \ jne 4f; /* no, go set KGSBASE */ \ movl $MSR_AMD_GSBASE, %ecx; /* yes, set GSBASE */ \ mfence; /* OPTERON_ERRATUM_88 */ \ 4: \ movq %rax, %rdx; /* write base register */ \ shrq $32, %rdx; \ wrmsr; \ movq REGOFF_RDX(%rbp), %rdx; /* restore regs */ \ movq REGOFF_RCX(%rbp), %rcx; \ movq REGOFF_RBX(%rbp), %rbx; \ movq REGOFF_RAX(%rbp), %rax; \ movq %rbp, %rsp; \ movq REGOFF_RBP(%rsp), %rbp; \ addq $REGOFF_TRAPNO, %rsp /* pop stack */ #endif /* __amd64 */ .globl nmivect .globl idt0_default_r #if defined(__amd64) /* * #NMI */ ENTRY_NP(nmiint) TRAP_NOERR(T_NMIFLT) /* $2 */ SET_CPU_GSBASE /* * Save all registers and setup segment registers * with kernel selectors. */ INTR_PUSH DISABLE_INTR_FLAGS /* and set the kernel flags */ TRACE_PTR(%r12, %rax, %eax, %rdx, $TT_TRAP) TRACE_REGS(%r12, %rsp, %rax, %rbx) TRACE_STAMP(%r12) movq %rsp, %rbp movq %rbp, %rdi call av_dispatch_nmivect INTR_POP iretq SET_SIZE(nmiint) #elif defined(__i386) /* * #NMI */ ENTRY_NP(nmiint) TRAP_NOERR(T_NMIFLT) /* $2 */ /* * Save all registers and setup segment registers * with kernel selectors. */ INTR_PUSH /* * setup pointer to reg struct as 2nd argument. */ movl %esp, %ebp pushl %ebp DISABLE_INTR_FLAGS movl nmivect, %esi /* get autovect structure */ loop1: cmpl $0, %esi /* if pointer is null */ je .intr_ret /* we're done */ movl AV_VECTOR(%esi), %edx /* get the interrupt routine */ pushl AV_INTARG1(%esi) /* get argument to interrupt routine */ call *%edx /* call interrupt routine with arg */ addl $4, %esp movl AV_LINK(%esi), %esi /* get next routine on list */ jmp loop1 /* keep looping until end of list */ .intr_ret: addl $4, %esp /* 'pop' %ebp */ INTR_POP_USER iret SET_SIZE(nmiint) #endif /* __i386 */ /* * #BP */ ENTRY_NP(brktrap) #if defined(__amd64) cmpw $KCS_SEL, 8(%rsp) je bp_jmpud #endif TRAP_NOERR(T_BPTFLT) /* $3 */ jmp dtrace_trap #if defined(__amd64) bp_jmpud: /* * 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. */ decq (%rsp) push $1 /* error code -- non-zero for #BP */ jmp ud_kernel #endif SET_SIZE(brktrap) /* * #OF */ ENTRY_NP(ovflotrap) TRAP_NOERR(T_OVFLW) /* $4 */ jmp cmntrap SET_SIZE(ovflotrap) /* * #BR */ ENTRY_NP(boundstrap) TRAP_NOERR(T_BOUNDFLT) /* $5 */ jmp cmntrap SET_SIZE(boundstrap) #if defined(__amd64) ENTRY_NP(invoptrap) cmpw $KCS_SEL, 8(%rsp) jne ud_user push $0 /* error code -- zero for #UD */ ud_kernel: push $0xdddd /* a dummy trap number */ TRAP_PUSH movq REGOFF_RIP(%rsp), %rdi movq REGOFF_RSP(%rsp), %rsi movq REGOFF_RAX(%rsp), %rdx pushq (%rsi) movq %rsp, %rsi call dtrace_invop ALTENTRY(dtrace_invop_callsite) addq $8, %rsp cmpl $DTRACE_INVOP_PUSHL_EBP, %eax je ud_push cmpl $DTRACE_INVOP_LEAVE, %eax je ud_leave cmpl $DTRACE_INVOP_NOP, %eax je ud_nop cmpl $DTRACE_INVOP_RET, %eax je ud_ret jmp ud_trap ud_push: /* * We must emulate a "pushq %rbp". To do this, we pull the stack * down 8 bytes, and then store the base pointer. */ INTR_POP subq $16, %rsp /* make room for %rbp */ pushq %rax /* push temp */ movq 24(%rsp), %rax /* load calling RIP */ addq $1, %rax /* increment over trapping instr */ movq %rax, 8(%rsp) /* store calling RIP */ movq 32(%rsp), %rax /* load calling CS */ movq %rax, 16(%rsp) /* store calling CS */ movq 40(%rsp), %rax /* load calling RFLAGS */ movq %rax, 24(%rsp) /* store calling RFLAGS */ movq 48(%rsp), %rax /* load calling RSP */ subq $8, %rax /* make room for %rbp */ movq %rax, 32(%rsp) /* store calling RSP */ movq 56(%rsp), %rax /* load calling SS */ movq %rax, 40(%rsp) /* store calling SS */ movq 32(%rsp), %rax /* reload calling RSP */ movq %rbp, (%rax) /* store %rbp there */ popq %rax /* pop off temp */ iretq /* return from interrupt */ ud_leave: /* * 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. */ INTR_POP pushq %rax /* push temp */ movq 8(%rsp), %rax /* load calling RIP */ addq $1, %rax /* increment over trapping instr */ movq %rax, 8(%rsp) /* store calling RIP */ movq (%rbp), %rax /* get new %rbp */ addq $8, %rbp /* adjust new %rsp */ movq %rbp, 32(%rsp) /* store new %rsp */ movq %rax, %rbp /* set new %rbp */ popq %rax /* pop off temp */ iretq /* return from interrupt */ ud_nop: /* * We must emulate a "nop". This is obviously not hard: we need only * advance the %rip by one. */ INTR_POP incq (%rsp) iretq ud_ret: INTR_POP pushq %rax /* push temp */ movq 32(%rsp), %rax /* load %rsp */ movq (%rax), %rax /* load calling RIP */ movq %rax, 8(%rsp) /* store calling RIP */ addq $8, 32(%rsp) /* adjust new %rsp */ popq %rax /* pop off temp */ iretq /* return from interrupt */ ud_trap: /* * 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. */ cmpq $0, REGOFF_ERR(%rsp) je ud_ud incq REGOFF_RIP(%rsp) addq $REGOFF_RIP, %rsp TRAP_NOERR(T_BPTFLT) /* $3 */ jmp cmntrap ud_ud: addq $REGOFF_RIP, %rsp ud_user: TRAP_NOERR(T_ILLINST) jmp cmntrap SET_SIZE(invoptrap) #elif defined(__i386) /* * #UD */ ENTRY_NP(invoptrap) /* * If we are taking an invalid opcode trap while in the kernel, this * is likely an FBT probe point. */ pushl %gs cmpw $KGS_SEL, (%esp) jne 8f addl $4, %esp pusha pushl %eax /* push %eax -- may be return value */ pushl %esp /* push stack pointer */ addl $48, (%esp) /* adjust to incoming args */ pushl 40(%esp) /* push calling EIP */ call dtrace_invop ALTENTRY(dtrace_invop_callsite) addl $12, %esp cmpl $DTRACE_INVOP_PUSHL_EBP, %eax je 1f cmpl $DTRACE_INVOP_POPL_EBP, %eax je 2f cmpl $DTRACE_INVOP_LEAVE, %eax je 3f cmpl $DTRACE_INVOP_NOP, %eax 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. */ popa subl $4, %esp /* make room for %ebp */ pushl %eax /* push temp */ movl 8(%esp), %eax /* load calling EIP */ incl %eax /* increment over LOCK prefix */ movl %eax, 4(%esp) /* store calling EIP */ movl 12(%esp), %eax /* load calling CS */ movl %eax, 8(%esp) /* store calling CS */ movl 16(%esp), %eax /* load calling EFLAGS */ movl %eax, 12(%esp) /* store calling EFLAGS */ movl %ebp, 16(%esp) /* push %ebp */ popl %eax /* pop off temp */ iret /* return from interrupt */ 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. */ popa pushl %eax /* push temp */ movl 16(%esp), %ebp /* pop %ebp */ movl 12(%esp), %eax /* load calling EFLAGS */ movl %eax, 16(%esp) /* store calling EFLAGS */ movl 8(%esp), %eax /* load calling CS */ movl %eax, 12(%esp) /* store calling CS */ movl 4(%esp), %eax /* load calling EIP */ incl %eax /* increment over LOCK prefix */ movl %eax, 8(%esp) /* store calling EIP */ popl %eax /* pop off temp */ addl $4, %esp /* adjust stack pointer */ iret /* return from interrupt */ 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. */ popa pushl %eax /* push temp */ pushl %ebx /* push temp */ movl %ebp, %ebx /* set temp to old %ebp */ movl (%ebx), %ebp /* pop %ebp */ movl 16(%esp), %eax /* load calling EFLAGS */ movl %eax, (%ebx) /* store calling EFLAGS */ movl 12(%esp), %eax /* load calling CS */ movl %eax, -4(%ebx) /* store calling CS */ movl 8(%esp), %eax /* load calling EIP */ incl %eax /* increment over LOCK prefix */ movl %eax, -8(%ebx) /* store calling EIP */ movl %ebx, -4(%esp) /* temporarily store new %esp */ popl %ebx /* pop off temp */ popl %eax /* pop off temp */ movl -12(%esp), %esp /* set stack pointer */ subl $8, %esp /* adjust for three pushes, one pop */ iret /* return from interrupt */ 4: /* * We must emulate a "nop". This is obviously not hard: we need only * advance the %eip by one. */ popa incl (%esp) iret 7: popa pushl $0 pushl $T_ILLINST /* $6 */ jmp cmntrap 8: addl $4, %esp pushl $0 pushl $T_ILLINST /* $6 */ jmp cmntrap SET_SIZE(invoptrap) #endif /* __i386 */ #if defined(__amd64) /* * #NM */ ENTRY_NP(ndptrap) /* * 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 */ pushq %rax pushq %rbx cmpw $KCS_SEL, 24(%rsp) /* did we come from kernel mode? */ jne 1f LOADCPU(%rbx) /* if yes, don't swapgs */ jmp 2f 1: swapgs /* if from user, need swapgs */ LOADCPU(%rbx) swapgs 2: cmpl $0, fpu_exists(%rip) je .handle_in_trap /* let trap handle no fp case */ movq CPU_THREAD(%rbx), %rax /* %rax = curthread */ movl $FPU_EN, %ebx movq T_LWP(%rax), %rax /* %rax = lwp */ testq %rax, %rax jz .handle_in_trap /* should not happen? */ #if LWP_PCB_FPU != 0 addq $LWP_PCB_FPU, %rax /* &lwp->lwp_pcb.pcb_fpu */ #endif testl %ebx, PCB_FPU_FLAGS(%rax) jz .handle_in_trap /* must be the first fault */ clts andl $_BITNOT(FPU_VALID), PCB_FPU_FLAGS(%rax) #if FPU_CTX_FPU_REGS != 0 addq $FPU_CTX_FPU_REGS, %rax #endif /* * the label below is used in trap.c to detect FP faults in * kernel due to user fault. */ ALTENTRY(ndptrap_frstor) fxrstor (%rax) popq %rbx popq %rax iretq .handle_in_trap: popq %rbx popq %rax TRAP_NOERR(T_NOEXTFLT) /* $7 */ jmp cmninttrap SET_SIZE(ndptrap_frstor) SET_SIZE(ndptrap) #elif defined(__i386) ENTRY_NP(ndptrap) /* * 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 */ pushl %eax pushl %ebx pushl %ds pushl %gs movl $KDS_SEL, %ebx movw %bx, %ds movl $KGS_SEL, %eax movw %ax, %gs LOADCPU(%ebx) cmpl $0, fpu_exists je .handle_in_trap /* let trap handle no fp case */ movl CPU_THREAD(%ebx), %eax /* %eax = curthread */ movl $FPU_EN, %ebx movl T_LWP(%eax), %eax /* %eax = lwp */ testl %eax, %eax jz .handle_in_trap /* should not happen? */ #if LWP_PCB_FPU != 0 addl $LWP_PCB_FPU, %eax /* &lwp->lwp_pcb.pcb_fpu */ #endif testl %ebx, PCB_FPU_FLAGS(%eax) jz .handle_in_trap /* must be the first fault */ clts andl $_BITNOT(FPU_VALID), PCB_FPU_FLAGS(%eax) #if FPU_CTX_FPU_REGS != 0 addl $FPU_CTX_FPU_REGS, %eax #endif /* * the label below is used in trap.c to detect FP faults in kernel * due to user fault. */ ALTENTRY(ndptrap_frstor) .globl _patch_fxrstor_eax _patch_fxrstor_eax: frstor (%eax) /* may be patched to fxrstor */ nop /* (including this byte) */ popl %gs popl %ds popl %ebx popl %eax iret .handle_in_trap: popl %gs popl %ds popl %ebx popl %eax pushl $0 pushl $T_NOEXTFLT /* $7 */ jmp cmninttrap SET_SIZE(ndptrap_frstor) SET_SIZE(ndptrap) #endif /* __i386 */ #if defined(__amd64) /* * #DF */ ENTRY_NP(syserrtrap) pushq $T_DBLFLT SET_CPU_GSBASE /* * 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. */ pushq %rax subq $DESCTBR_SIZE, %rsp sidt (%rsp) movq %gs:CPU_IDT, %rax cmpq %rax, DTR_BASE(%rsp) je 1f movq %rax, DTR_BASE(%rsp) movw $_MUL(NIDT, GATE_DESC_SIZE), DTR_LIMIT(%rsp) lidt (%rsp) movl $1, nopanicdebug 1: addq $DESCTBR_SIZE, %rsp popq %rax DFTRAP_PUSH /* * freeze trap trace. */ #ifdef TRAPTRACE leaq trap_trace_freeze(%rip), %r11 incl (%r11) #endif ENABLE_INTR_FLAGS movq %rsp, %rdi /* ®s */ xorl %esi, %esi /* clear address */ xorl %edx, %edx /* cpuid = 0 */ call trap SET_SIZE(syserrtrap) #elif defined(__i386) /* * #DF */ ENTRY_NP(syserrtrap) 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. */ subl $DESCTBR_SIZE, %esp movl %gs:CPU_IDT, %eax sidt (%esp) cmpl DTR_BASE(%esp), %eax je 1f movl %eax, DTR_BASE(%esp) movw $_MUL(NIDT, GATE_DESC_SIZE), DTR_LIMIT(%esp) lidt (%esp) movl $1, nopanicdebug 1: addl $DESCTBR_SIZE, %esp /* * 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. */ movl %gs:CPU_TSS, %eax /* get the TSS */ movl TSS_SS(%eax), %ebx /* save the fault SS */ movl TSS_ESP(%eax), %edx /* save the fault ESP */ testw $CPL_MASK, TSS_CS(%eax) /* user mode ? */ jz make_frame movw TSS_SS0(%eax), %ss /* get on the kernel stack */ movl TSS_ESP0(%eax), %esp /* * 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. */ movl TSS_EFL(%eax), %ecx andl $_BITNOT(PS_NT|PS_T|PS_IE), %ecx pushl %ecx popfl /* restore the EFL */ movw TSS_LDT(%eax), %cx /* restore the LDT */ lldt %cx /* * Restore process segment selectors. */ movw TSS_DS(%eax), %ds movw TSS_ES(%eax), %es movw TSS_FS(%eax), %fs movw TSS_GS(%eax), %gs /* * Restore task segment selectors. */ movl $KDS_SEL, TSS_DS(%eax) movl $KDS_SEL, TSS_ES(%eax) movl $KDS_SEL, TSS_SS(%eax) movl $KFS_SEL, TSS_FS(%eax) movl $KGS_SEL, TSS_GS(%eax) /* * Clear the TS bit, the busy bits in both task * descriptors, and switch tasks. */ clts leal gdt0, %ecx movl DFTSS_SEL+4(%ecx), %esi andl $_BITNOT(0x200), %esi movl %esi, DFTSS_SEL+4(%ecx) movl KTSS_SEL+4(%ecx), %esi andl $_BITNOT(0x200), %esi movl %esi, KTSS_SEL+4(%ecx) movw $KTSS_SEL, %cx ltr %cx /* * Restore part of the process registers. */ movl TSS_EBP(%eax), %ebp movl TSS_ECX(%eax), %ecx movl TSS_ESI(%eax), %esi movl TSS_EDI(%eax), %edi make_frame: /* * Make a trap frame. Leave the error code (0) on * the stack since the first word on a trap stack is * unused anyway. */ pushl %ebx / fault SS pushl %edx / fault ESP pushl TSS_EFL(%eax) / fault EFL pushl TSS_CS(%eax) / fault CS pushl TSS_EIP(%eax) / fault EIP pushl $0 / error code pushl $T_DBLFLT / trap number 8 movl TSS_EBX(%eax), %ebx / restore EBX movl TSS_EDX(%eax), %edx / restore EDX movl TSS_EAX(%eax), %eax / restore EAX sti / enable interrupts jmp cmntrap SET_SIZE(syserrtrap) #endif /* __i386 */ ENTRY_NP(overrun) push $0 TRAP_NOERR(T_EXTOVRFLT) /* $9 i386 only - not generated */ jmp cmninttrap SET_SIZE(overrun) /* * #TS */ ENTRY_NP(invtsstrap) TRAP_ERR(T_TSSFLT) /* $10 already have error code on stack */ jmp cmntrap SET_SIZE(invtsstrap) /* * #NP */ ENTRY_NP(segnptrap) TRAP_ERR(T_SEGFLT) /* $11 already have error code on stack */ #if defined(__amd64) SET_CPU_GSBASE #endif jmp cmntrap SET_SIZE(segnptrap) /* * #SS */ ENTRY_NP(stktrap) TRAP_ERR(T_STKFLT) /* $12 already have error code on stack */ jmp cmntrap SET_SIZE(stktrap) /* * #GP */ ENTRY_NP(gptrap) TRAP_ERR(T_GPFLT) /* $13 already have error code on stack */ #if defined(__amd64) SET_CPU_GSBASE #endif jmp cmntrap SET_SIZE(gptrap) /* * #PF */ ENTRY_NP(pftrap) TRAP_ERR(T_PGFLT) /* $14 already have error code on stack */ jmp cmntrap SET_SIZE(pftrap) #if !defined(__amd64) /* * #PF pentium bug workaround */ ENTRY_NP(pentium_pftrap) pushl %eax movl %cr2, %eax andl $MMU_STD_PAGEMASK, %eax cmpl %eax, %cs:idt0_default_r+2 /* fixme */ je check_for_user_address user_mode: popl %eax pushl $T_PGFLT /* $14 */ jmp cmntrap check_for_user_address: /* * 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. */ movl 4(%esp), %eax /* error code */ andl $PF_ERR_USER, %eax jnz user_mode /* * We now know that this is the invalid opcode trap. */ popl %eax addl $4, %esp /* pop error code */ jmp invoptrap SET_SIZE(pentium_pftrap) #endif /* !__amd64 */ ENTRY_NP(resvtrap) TRAP_NOERR(15) /* (reserved) */ jmp cmntrap SET_SIZE(resvtrap) /* * #MF */ ENTRY_NP(ndperr) TRAP_NOERR(T_EXTERRFLT) /* $16 */ jmp cmninttrap SET_SIZE(ndperr) /* * #AC */ ENTRY_NP(achktrap) TRAP_ERR(T_ALIGNMENT) /* $17 */ jmp cmntrap SET_SIZE(achktrap) /* * #MC */ ENTRY_NP(mcetrap) TRAP_NOERR(T_MCE) /* $18 */ #if defined(__amd64) SET_CPU_GSBASE #endif jmp cmninttrap SET_SIZE(mcetrap) /* * #XF */ ENTRY_NP(xmtrap) TRAP_NOERR(T_SIMDFPE) /* $19 */ jmp cmntrap SET_SIZE(xmtrap) ENTRY_NP(invaltrap) TRAP_NOERR(30) /* very invalid */ jmp cmntrap SET_SIZE(invaltrap) ENTRY_NP(invalint) TRAP_NOERR(31) /* even more so */ jmp cmnint SET_SIZE(invalint) .globl fasttable #if defined(__amd64) ENTRY_NP(fasttrap) cmpl $T_LASTFAST, %eax ja 1f orl %eax, %eax /* (zero extend top 32-bits) */ leaq fasttable(%rip), %r11 leaq (%r11, %rax, CLONGSIZE), %r11 jmp *(%r11) 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? */ subq $2, (%rsp) /* XXX int insn 2-bytes */ pushq $_CONST(_MUL(T_FASTTRAP, GATE_DESC_SIZE) + 2) jmp gptrap SET_SIZE(fasttrap) #elif defined(__i386) ENTRY_NP(fasttrap) cmpl $T_LASTFAST, %eax ja 1f jmp *%cs:fasttable(, %eax, CLONGSIZE) 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? */ subl $2, (%esp) /* XXX int insn 2-bytes */ pushl $_CONST(_MUL(T_FASTTRAP, GATE_DESC_SIZE) + 2) jmp gptrap SET_SIZE(fasttrap) #endif /* __i386 */ ENTRY_NP(dtrace_fasttrap) TRAP_NOERR(T_DTRACE_PROBE) jmp dtrace_trap SET_SIZE(dtrace_fasttrap) ENTRY_NP(dtrace_ret) TRAP_NOERR(T_DTRACE_RET) jmp dtrace_trap SET_SIZE(dtrace_ret) #if defined(__amd64) /* * RFLAGS 24 bytes up the stack from %rsp. * XXX a constant would be nicer. */ ENTRY_NP(fast_null) orq $PS_C, 24(%rsp) /* set carry bit in user flags */ iretq SET_SIZE(fast_null) #elif defined(__i386) ENTRY_NP(fast_null) orw $PS_C, 8(%esp) /* set carry bit in user flags */ iret SET_SIZE(fast_null) #endif /* __i386 */ /* * Interrupts start at 32 */ #define MKIVCT(n) \ ENTRY_NP(ivct/**/n) \ push $0; \ push $n - 0x20; \ jmp cmnint; \ SET_SIZE(ivct/**/n) 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 */