exception.S revision 140553
1757Sdg/*- 299703Sjulian * Copyright (c) 1989, 1990 William F. Jolitz. 3757Sdg * Copyright (c) 1990 The Regents of the University of California. 4757Sdg * All rights reserved. 5757Sdg * 6757Sdg * Redistribution and use in source and binary forms, with or without 7757Sdg * modification, are permitted provided that the following conditions 8757Sdg * are met: 9757Sdg * 1. Redistributions of source code must retain the above copyright 10757Sdg * notice, this list of conditions and the following disclaimer. 11757Sdg * 2. Redistributions in binary form must reproduce the above copyright 12757Sdg * notice, this list of conditions and the following disclaimer in the 13757Sdg * documentation and/or other materials provided with the distribution. 14757Sdg * 4. Neither the name of the University nor the names of its contributors 15757Sdg * may be used to endorse or promote products derived from this software 16757Sdg * without specific prior written permission. 17757Sdg * 18757Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19757Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20757Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21757Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22757Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23757Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24757Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25757Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26757Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27757Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28757Sdg * SUCH DAMAGE. 29757Sdg * 3050477Speter * $FreeBSD: head/sys/amd64/amd64/exception.S 140553 2005-01-21 05:56:41Z peter $ 31757Sdg */ 32757Sdg 33129653Sbde#include "opt_atpic.h" 34133854Sobrien#include "opt_compat.h" 35129653Sbde 3628921Sfsmp#include <machine/asmacros.h> 3730786Sbde#include <machine/psl.h> 3830786Sbde#include <machine/trap.h> 39757Sdg 4030786Sbde#include "assym.s" 4130786Sbde 42757Sdg .text 43757Sdg 44757Sdg/*****************************************************************************/ 45757Sdg/* Trap handling */ 46757Sdg/*****************************************************************************/ 47757Sdg/* 4858717Sdillon * Trap and fault vector routines. 4958717Sdillon * 50114928Speter * All traps are 'interrupt gates', SDT_SYSIGT. An interrupt gate pushes 51114928Speter * state on the stack but also disables interrupts. This is important for 52114928Speter * us for the use of the swapgs instruction. We cannot be interrupted 53114928Speter * until the GS.base value is correct. For most traps, we automatically 54114928Speter * then enable interrupts if the interrupted context had them enabled. 55114928Speter * This is equivalent to the i386 port's use of SDT_SYS386TGT. 5658717Sdillon * 5758717Sdillon * The cpu will push a certain amount of state onto the kernel stack for 58114928Speter * the current process. See amd64/include/frame.h. 59114928Speter * This includes the current RFLAGS (status register, which includes 6058717Sdillon * the interrupt disable state prior to the trap), the code segment register, 6158717Sdillon * and the return instruction pointer are pushed by the cpu. The cpu 6258717Sdillon * will also push an 'error' code for certain traps. We push a dummy 6358717Sdillon * error code for those traps where the cpu doesn't in order to maintain 6458717Sdillon * a consistent frame. We also push a contrived 'trap number'. 6558717Sdillon * 6658717Sdillon * The cpu does not push the general registers, we must do that, and we 6758717Sdillon * must restore them prior to calling 'iret'. The cpu adjusts the %cs and 6858717Sdillon * %ss segment registers, but does not mess with %ds, %es, or %fs. Thus we 6958717Sdillon * must load them with appropriate values for supervisor mode operation. 701321Sdg */ 711321Sdg 721321SdgMCOUNT_LABEL(user) 731321SdgMCOUNT_LABEL(btrap) 741321Sdg 75114952Speter/* Traps that we leave interrupts disabled for.. */ 76114952Speter#define TRAP_NOEN(a) \ 77114952Speter subq $TF_RIP,%rsp; \ 78114952Speter movq $(a),TF_TRAPNO(%rsp) ; \ 79114952Speter movq $0,TF_ADDR(%rsp) ; \ 80114952Speter movq $0,TF_ERR(%rsp) ; \ 81114952Speter jmp alltraps_noen 82114952SpeterIDTVEC(dbg) 83114952Speter TRAP_NOEN(T_TRCTRAP) 84114952SpeterIDTVEC(bpt) 85114952Speter TRAP_NOEN(T_BPTFLT) 86114952Speter 87114952Speter/* Regular traps; The cpu does not supply tf_err for these. */ 88114952Speter#define TRAP(a) \ 89114952Speter subq $TF_RIP,%rsp; \ 90114952Speter movq $(a),TF_TRAPNO(%rsp) ; \ 91114952Speter movq $0,TF_ADDR(%rsp) ; \ 92114952Speter movq $0,TF_ERR(%rsp) ; \ 93114952Speter jmp alltraps 94757SdgIDTVEC(div) 95114952Speter TRAP(T_DIVIDE) 96757SdgIDTVEC(nmi) 97114952Speter TRAP(T_NMI) 98757SdgIDTVEC(ofl) 99114952Speter TRAP(T_OFLOW) 100757SdgIDTVEC(bnd) 101114952Speter TRAP(T_BOUND) 102757SdgIDTVEC(ill) 103114952Speter TRAP(T_PRIVINFLT) 104757SdgIDTVEC(dna) 105114952Speter TRAP(T_DNA) 106757SdgIDTVEC(fpusegm) 107114952Speter TRAP(T_FPOPFLT) 108114952SpeterIDTVEC(mchk) 109114952Speter TRAP(T_MCHK) 110114952SpeterIDTVEC(rsvd) 111114952Speter TRAP(T_RESERVED) 112114952SpeterIDTVEC(fpu) 113114952Speter TRAP(T_ARITHTRAP) 114114952SpeterIDTVEC(xmm) 115114952Speter TRAP(T_XMMFLT) 116114952Speter 117114952Speter/* This group of traps have tf_err already pushed by the cpu */ 118114952Speter#define TRAP_ERR(a) \ 119114952Speter subq $TF_ERR,%rsp; \ 120114952Speter movq $(a),TF_TRAPNO(%rsp) ; \ 121114952Speter movq $0,TF_ADDR(%rsp) ; \ 122114952Speter jmp alltraps_noen 123757SdgIDTVEC(tss) 124114952Speter TRAP_ERR(T_TSSFLT) 125757SdgIDTVEC(missing) 126114952Speter TRAP_ERR(T_SEGNPFLT) 127757SdgIDTVEC(stk) 128114952Speter TRAP_ERR(T_STKFLT) 129757SdgIDTVEC(prot) 130114952Speter TRAP_ERR(T_PROTFLT) 1315603SbdeIDTVEC(align) 132114952Speter TRAP_ERR(T_ALIGNFLT) 133140553Speter 13458717Sdillon /* 135114928Speter * alltraps entry point. Use swapgs if this is the first time in the 136114928Speter * kernel from userland. Reenable interrupts if they were enabled 137114928Speter * before the trap. This approximates SDT_SYS386TGT on the i386 port. 13858717Sdillon */ 13958717Sdillon 140757Sdg SUPERALIGN_TEXT 14173011Sjake .globl alltraps 14273011Sjake .type alltraps,@function 14373011Sjakealltraps: 144114928Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 145114928Speter jz alltraps_testi /* already running with kernel GS.base */ 146114928Speter swapgs 147114928Speteralltraps_testi: 148114928Speter testl $PSL_I,TF_RFLAGS(%rsp) 149114928Speter jz alltraps_pushregs 150114928Speter sti 151114928Speteralltraps_pushregs: 152114349Speter movq %rdi,TF_RDI(%rsp) 153114952Speteralltraps_pushregs_no_rdi: 154114349Speter movq %rsi,TF_RSI(%rsp) 155114349Speter movq %rdx,TF_RDX(%rsp) 156114349Speter movq %rcx,TF_RCX(%rsp) 157114349Speter movq %r8,TF_R8(%rsp) 158114349Speter movq %r9,TF_R9(%rsp) 159114349Speter movq %rax,TF_RAX(%rsp) 160114349Speter movq %rbx,TF_RBX(%rsp) 161114349Speter movq %rbp,TF_RBP(%rsp) 162114349Speter movq %r10,TF_R10(%rsp) 163114349Speter movq %r11,TF_R11(%rsp) 164114349Speter movq %r12,TF_R12(%rsp) 165114349Speter movq %r13,TF_R13(%rsp) 166114349Speter movq %r14,TF_R14(%rsp) 167114349Speter movq %r15,TF_R15(%rsp) 1685603Sbdealltraps_with_regs_pushed: 169129623Sbde FAKE_MCOUNT(TF_RIP(%rsp)) 170757Sdgcalltrap: 17173011Sjake call trap 172129623Sbde MEXITCOUNT 173114349Speter jmp doreti /* Handle any pending ASTs */ 174757Sdg 175114928Speter /* 176114928Speter * alltraps_noen entry point. Unlike alltraps above, we want to 177114928Speter * leave the interrupts disabled. This corresponds to 178114928Speter * SDT_SYS386IGT on the i386 port. 179114928Speter */ 180114928Speter SUPERALIGN_TEXT 181114928Speter .globl alltraps_noen 182114928Speter .type alltraps_noen,@function 183114928Speteralltraps_noen: 184114928Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 185114928Speter jz alltraps_pushregs /* already running with kernel GS.base */ 186114928Speter swapgs 187114928Speter jmp alltraps_pushregs 188114928Speter 189114928SpeterIDTVEC(dblfault) 190114952Speter subq $TF_ERR,%rsp 191114952Speter movq $T_DOUBLEFLT,TF_TRAPNO(%rsp) 192114928Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 193114928Speter jz 1f /* already running with kernel GS.base */ 194114928Speter swapgs 195114928Speter1: call dblfault_handler 196114928Speter2: hlt 197114928Speter jmp 2b 198114928Speter 199114952SpeterIDTVEC(page) 200114952Speter subq $TF_ERR,%rsp 201114952Speter movq $T_PAGEFLT,TF_TRAPNO(%rsp) 202114952Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 203114952Speter jz 1f /* already running with kernel GS.base */ 204114952Speter swapgs 205114952Speter1: movq %rdi,TF_RDI(%rsp) /* free up a GP register */ 206114952Speter movq %cr2,%rdi /* preserve %cr2 before .. */ 207114952Speter movq %rdi,TF_ADDR(%rsp) /* enabling interrupts. */ 208114952Speter testl $PSL_I,TF_RFLAGS(%rsp) 209114952Speter jz alltraps_pushregs_no_rdi 210114952Speter sti 211114952Speter jmp alltraps_pushregs_no_rdi 212114952Speter 213757Sdg/* 214114349Speter * Fast syscall entry point. We enter here with just our new %cs/%ss set, 215114349Speter * and the new privilige level. We are still running on the old user stack 216114349Speter * pointer. We have to juggle a few things around to find our stack etc. 217114349Speter * swapgs gives us access to our PCPU space only. 2186380Ssos */ 219114349SpeterIDTVEC(fast_syscall) 220114928Speter swapgs 221114349Speter movq %rsp,PCPU(SCRATCH_RSP) 222122849Speter movq PCPU(RSP0),%rsp 223119924Speter /* Now emulate a trapframe. Make the 8 byte alignment odd for call. */ 224121103Speter subq $TF_SIZE,%rsp 225114349Speter /* defer TF_RSP till we have a spare register */ 226114349Speter movq %r11,TF_RFLAGS(%rsp) 227114928Speter movq %rcx,TF_RIP(%rsp) /* %rcx original value is in %r10 */ 228114928Speter movq PCPU(SCRATCH_RSP),%r11 /* %r11 already saved */ 229114928Speter movq %r11,TF_RSP(%rsp) /* user stack pointer */ 230114928Speter sti 231114928Speter movq $KUDSEL,TF_SS(%rsp) 232114349Speter movq $KUCSEL,TF_CS(%rsp) 233114349Speter movq $2,TF_ERR(%rsp) 234114349Speter movq %rdi,TF_RDI(%rsp) /* arg 1 */ 235114349Speter movq %rsi,TF_RSI(%rsp) /* arg 2 */ 236114349Speter movq %rdx,TF_RDX(%rsp) /* arg 3 */ 237114349Speter movq %r10,TF_RCX(%rsp) /* arg 4 */ 238114349Speter movq %r8,TF_R8(%rsp) /* arg 5 */ 239114349Speter movq %r9,TF_R9(%rsp) /* arg 6 */ 240114349Speter movq %rax,TF_RAX(%rsp) /* syscall number */ 241114349Speter movq %rbx,TF_RBX(%rsp) /* C preserved */ 242114349Speter movq %rbp,TF_RBP(%rsp) /* C preserved */ 243114349Speter movq %r12,TF_R12(%rsp) /* C preserved */ 244114349Speter movq %r13,TF_R13(%rsp) /* C preserved */ 245114349Speter movq %r14,TF_R14(%rsp) /* C preserved */ 246114349Speter movq %r15,TF_R15(%rsp) /* C preserved */ 247129623Sbde FAKE_MCOUNT(TF_RIP(%rsp)) 24873011Sjake call syscall 249114349Speter movq PCPU(CURPCB),%rax 250114349Speter testq $PCB_FULLCTX,PCB_FLAGS(%rax) 251114349Speter jne 3f 252114349Speter1: /* Check for and handle AST's on return to userland */ 253114349Speter cli 254114349Speter movq PCPU(CURTHREAD),%rax 255114349Speter testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax) 256114349Speter je 2f 257114349Speter sti 258114349Speter movq %rsp, %rdi 259114349Speter call ast 260114349Speter jmp 1b 261114349Speter2: /* restore preserved registers */ 262129623Sbde MEXITCOUNT 263114349Speter movq TF_RDI(%rsp),%rdi /* bonus; preserve arg 1 */ 264114349Speter movq TF_RSI(%rsp),%rsi /* bonus: preserve arg 2 */ 265114349Speter movq TF_RDX(%rsp),%rdx /* return value 2 */ 266114349Speter movq TF_RAX(%rsp),%rax /* return value 1 */ 267114349Speter movq TF_RBX(%rsp),%rbx /* C preserved */ 268114349Speter movq TF_RBP(%rsp),%rbp /* C preserved */ 269114349Speter movq TF_R12(%rsp),%r12 /* C preserved */ 270114349Speter movq TF_R13(%rsp),%r13 /* C preserved */ 271114349Speter movq TF_R14(%rsp),%r14 /* C preserved */ 272114349Speter movq TF_R15(%rsp),%r15 /* C preserved */ 273114349Speter movq TF_RFLAGS(%rsp),%r11 /* original %rflags */ 274114349Speter movq TF_RIP(%rsp),%rcx /* original %rip */ 275114349Speter movq TF_RSP(%rsp),%r9 /* user stack pointer */ 276114349Speter movq %r9,%rsp /* original %rsp */ 277114928Speter swapgs 278114349Speter sysretq 279114349Speter3: /* Requested full context restore, use doreti for that */ 280114349Speter andq $~PCB_FULLCTX,PCB_FLAGS(%rax) 281129623Sbde MEXITCOUNT 28273011Sjake jmp doreti 2836380Ssos 284114349Speter/* 285114349Speter * Here for CYA insurance, in case a "syscall" instruction gets 286114349Speter * issued from 32 bit compatability mode. MSR_CSTAR has to point 287114349Speter * to *something* if EFER_SCE is enabled. 288114349Speter */ 289114349SpeterIDTVEC(fast_syscall32) 290114349Speter sysret 291114349Speter 29224691SpeterENTRY(fork_trampoline) 293114349Speter movq %r12, %rdi /* function */ 294114349Speter movq %rbx, %rsi /* arg1 */ 295114349Speter movq %rsp, %rdx /* trapframe pointer */ 29673011Sjake call fork_exit 297129623Sbde MEXITCOUNT 298114349Speter jmp doreti /* Handle any ASTs */ 29924691Speter 300129653Sbde/* 301129653Sbde * To efficiently implement classification of trap and interrupt handlers 302129653Sbde * for profiling, there must be only trap handlers between the labels btrap 303129653Sbde * and bintr, and only interrupt handlers between the labels bintr and 304129653Sbde * eintr. This is implemented (partly) by including files that contain 305129653Sbde * some of the handlers. Before including the files, set up a normal asm 306129653Sbde * environment so that the included files doen't need to know that they are 307129653Sbde * included. 308129653Sbde */ 309129653Sbde 310133854Sobrien#ifdef COMPAT_IA32 31199703Sjulian .data 312129656Sbde .p2align 4 313129653Sbde .text 314129653Sbde SUPERALIGN_TEXT 31599703Sjulian 316129653Sbde#include <amd64/ia32/ia32_exception.S> 317129653Sbde#endif 318129653Sbde 319129653Sbde .data 320129656Sbde .p2align 4 321129653Sbde .text 322129653Sbde SUPERALIGN_TEXT 323129653SbdeMCOUNT_LABEL(bintr) 324129653Sbde 325129653Sbde#include <amd64/amd64/apic_vector.S> 326129653Sbde 327129653Sbde#ifdef DEV_ATPIC 328129653Sbde .data 329129656Sbde .p2align 4 330129653Sbde .text 331129653Sbde SUPERALIGN_TEXT 332129653Sbde 333129653Sbde#include <amd64/isa/atpic_vector.S> 334129653Sbde#endif 335129653Sbde 336129653Sbde .text 337129653SbdeMCOUNT_LABEL(eintr) 338129653Sbde 3393156Sbde/* 34099703Sjulian * void doreti(struct trapframe) 34199703Sjulian * 34299703Sjulian * Handle return from interrupts, traps and syscalls. 3433156Sbde */ 3443156Sbde .text 3453156Sbde SUPERALIGN_TEXT 34699703Sjulian .type doreti,@function 34799703Sjuliandoreti: 348129623Sbde FAKE_MCOUNT($bintr) /* init "from" bintr -> doreti */ 34999703Sjulian /* 350114349Speter * Check if ASTs can be handled now. 35199703Sjulian */ 352114349Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* are we returning to user mode? */ 35399703Sjulian jz doreti_exit /* can't handle ASTs now if not */ 35499703Sjulian 35599703Sjuliandoreti_ast: 35699703Sjulian /* 35799703Sjulian * Check for ASTs atomically with returning. Disabling CPU 358120354Speter * interrupts provides sufficient locking eve in the SMP case, 35999703Sjulian * since we will be informed of any new ASTs by an IPI. 36099703Sjulian */ 36199703Sjulian cli 362114349Speter movq PCPU(CURTHREAD),%rax 363114349Speter testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax) 36499703Sjulian je doreti_exit 36599703Sjulian sti 366114349Speter movq %rsp, %rdi /* pass a pointer to the trapframe */ 36799703Sjulian call ast 36899703Sjulian jmp doreti_ast 36999703Sjulian 37099703Sjulian /* 37199703Sjulian * doreti_exit: pop registers, iret. 37299703Sjulian * 37399703Sjulian * The segment register pop is a special case, since it may 37499703Sjulian * fault if (for example) a sigreturn specifies bad segment 37599703Sjulian * registers. The fault is handled in trap.c. 37699703Sjulian */ 37799703Sjuliandoreti_exit: 378129623Sbde MEXITCOUNT 379114349Speter movq TF_RDI(%rsp),%rdi 380114349Speter movq TF_RSI(%rsp),%rsi 381114349Speter movq TF_RDX(%rsp),%rdx 382114349Speter movq TF_RCX(%rsp),%rcx 383114349Speter movq TF_R8(%rsp),%r8 384114349Speter movq TF_R9(%rsp),%r9 385114349Speter movq TF_RAX(%rsp),%rax 386114349Speter movq TF_RBX(%rsp),%rbx 387114349Speter movq TF_RBP(%rsp),%rbp 388114349Speter movq TF_R10(%rsp),%r10 389114349Speter movq TF_R11(%rsp),%r11 390114349Speter movq TF_R12(%rsp),%r12 391114349Speter movq TF_R13(%rsp),%r13 392114349Speter movq TF_R14(%rsp),%r14 393114349Speter movq TF_R15(%rsp),%r15 394114928Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 395114928Speter jz 1f /* keep running with kernel GS.base */ 396114928Speter cli 397114928Speter swapgs 398114928Speter1: addq $TF_RIP,%rsp /* skip over tf_err, tf_trapno */ 39999703Sjulian .globl doreti_iret 40099703Sjuliandoreti_iret: 401114349Speter iretq 40299703Sjulian 403114928Speter /* 40499703Sjulian * doreti_iret_fault and friends. Alternative return code for 40599703Sjulian * the case where we get a fault in the doreti_exit code 40699703Sjulian * above. trap() (i386/i386/trap.c) catches this specific 40799703Sjulian * case, sends the process a signal and continues in the 40899703Sjulian * corresponding place in the code below. 40999703Sjulian */ 41099703Sjulian ALIGN_TEXT 41199703Sjulian .globl doreti_iret_fault 41299703Sjuliandoreti_iret_fault: 413114349Speter subq $TF_RIP,%rsp /* space including tf_err, tf_trapno */ 414114928Speter testb $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */ 415114928Speter jz 1f /* already running with kernel GS.base */ 416114928Speter swapgs 417114928Speter1: testl $PSL_I,TF_RFLAGS(%rsp) 418114928Speter jz 2f 419114928Speter sti 420114928Speter2: movq %rdi,TF_RDI(%rsp) 421114349Speter movq %rsi,TF_RSI(%rsp) 422114349Speter movq %rdx,TF_RDX(%rsp) 423114349Speter movq %rcx,TF_RCX(%rsp) 424114349Speter movq %r8,TF_R8(%rsp) 425114349Speter movq %r9,TF_R9(%rsp) 426114349Speter movq %rax,TF_RAX(%rsp) 427114349Speter movq %rbx,TF_RBX(%rsp) 428114349Speter movq %rbp,TF_RBP(%rsp) 429114349Speter movq %r10,TF_R10(%rsp) 430114349Speter movq %r11,TF_R11(%rsp) 431114349Speter movq %r12,TF_R12(%rsp) 432114349Speter movq %r13,TF_R13(%rsp) 433114349Speter movq %r14,TF_R14(%rsp) 434114349Speter movq %r15,TF_R15(%rsp) 435114349Speter movq $T_PROTFLT,TF_TRAPNO(%rsp) 436114349Speter movq $0,TF_ERR(%rsp) /* XXX should be the error code */ 43799703Sjulian jmp alltraps_with_regs_pushed 438