exception.s revision 302041
1/*- 2 * Copyright (c) 1989, 1990 William F. Jolitz. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * Copyright (c) 2007 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * Portions of this software were developed by A. Joseph Koshy under 8 * sponsorship from the FreeBSD Foundation and Google, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $FreeBSD: stable/10/sys/i386/i386/exception.s 302041 2016-06-21 04:51:55Z sephe $ 35 */ 36 37#include "opt_apic.h" 38#include "opt_atpic.h" 39#include "opt_hwpmc_hooks.h" 40#include "opt_kdtrace.h" 41#include "opt_npx.h" 42 43#include <machine/asmacros.h> 44#include <machine/psl.h> 45#include <machine/trap.h> 46 47#include "assym.s" 48 49#define SEL_RPL_MASK 0x0003 50#define GSEL_KPL 0x0020 /* GSEL(GCODE_SEL, SEL_KPL) */ 51 52#ifdef KDTRACE_HOOKS 53 .bss 54 .globl dtrace_invop_jump_addr 55 .align 4 56 .type dtrace_invop_jump_addr, @object 57 .size dtrace_invop_jump_addr, 4 58dtrace_invop_jump_addr: 59 .zero 4 60 .globl dtrace_invop_calltrap_addr 61 .align 4 62 .type dtrace_invop_calltrap_addr, @object 63 .size dtrace_invop_calltrap_addr, 4 64dtrace_invop_calltrap_addr: 65 .zero 8 66#endif 67 .text 68#ifdef HWPMC_HOOKS 69 ENTRY(start_exceptions) 70#endif 71/*****************************************************************************/ 72/* Trap handling */ 73/*****************************************************************************/ 74/* 75 * Trap and fault vector routines. 76 * 77 * Most traps are 'trap gates', SDT_SYS386TGT. A trap gate pushes state on 78 * the stack that mostly looks like an interrupt, but does not disable 79 * interrupts. A few of the traps we are use are interrupt gates, 80 * SDT_SYS386IGT, which are nearly the same thing except interrupts are 81 * disabled on entry. 82 * 83 * The cpu will push a certain amount of state onto the kernel stack for 84 * the current process. The amount of state depends on the type of trap 85 * and whether the trap crossed rings or not. See i386/include/frame.h. 86 * At the very least the current EFLAGS (status register, which includes 87 * the interrupt disable state prior to the trap), the code segment register, 88 * and the return instruction pointer are pushed by the cpu. The cpu 89 * will also push an 'error' code for certain traps. We push a dummy 90 * error code for those traps where the cpu doesn't in order to maintain 91 * a consistent frame. We also push a contrived 'trap number'. 92 * 93 * The cpu does not push the general registers, we must do that, and we 94 * must restore them prior to calling 'iret'. The cpu adjusts the %cs and 95 * %ss segment registers, but does not mess with %ds, %es, or %fs. Thus we 96 * must load them with appropriate values for supervisor mode operation. 97 */ 98 99MCOUNT_LABEL(user) 100MCOUNT_LABEL(btrap) 101 102#define TRAP(a) pushl $(a) ; jmp alltraps 103 104IDTVEC(div) 105 pushl $0; TRAP(T_DIVIDE) 106IDTVEC(dbg) 107 pushl $0; TRAP(T_TRCTRAP) 108IDTVEC(nmi) 109 pushl $0; TRAP(T_NMI) 110IDTVEC(bpt) 111 pushl $0; TRAP(T_BPTFLT) 112IDTVEC(dtrace_ret) 113 pushl $0; TRAP(T_DTRACE_RET) 114IDTVEC(ofl) 115 pushl $0; TRAP(T_OFLOW) 116IDTVEC(bnd) 117 pushl $0; TRAP(T_BOUND) 118#ifndef KDTRACE_HOOKS 119IDTVEC(ill) 120 pushl $0; TRAP(T_PRIVINFLT) 121#endif 122IDTVEC(dna) 123 pushl $0; TRAP(T_DNA) 124IDTVEC(fpusegm) 125 pushl $0; TRAP(T_FPOPFLT) 126IDTVEC(tss) 127 TRAP(T_TSSFLT) 128IDTVEC(missing) 129 TRAP(T_SEGNPFLT) 130IDTVEC(stk) 131 TRAP(T_STKFLT) 132IDTVEC(prot) 133 TRAP(T_PROTFLT) 134IDTVEC(page) 135 TRAP(T_PAGEFLT) 136IDTVEC(mchk) 137 pushl $0; TRAP(T_MCHK) 138IDTVEC(rsvd) 139 pushl $0; TRAP(T_RESERVED) 140IDTVEC(fpu) 141 pushl $0; TRAP(T_ARITHTRAP) 142IDTVEC(align) 143 TRAP(T_ALIGNFLT) 144IDTVEC(xmm) 145 pushl $0; TRAP(T_XMMFLT) 146 147 /* 148 * All traps except ones for syscalls jump to alltraps. If 149 * interrupts were enabled when the trap occurred, then interrupts 150 * are enabled now if the trap was through a trap gate, else 151 * disabled if the trap was through an interrupt gate. Note that 152 * int0x80_syscall is a trap gate. Interrupt gates are used by 153 * page faults, non-maskable interrupts, debug and breakpoint 154 * exceptions. 155 */ 156 SUPERALIGN_TEXT 157 .globl alltraps 158 .type alltraps,@function 159alltraps: 160 pushal 161 pushl $0 162 movw %ds,(%esp) 163 pushl $0 164 movw %es,(%esp) 165 pushl $0 166 movw %fs,(%esp) 167alltraps_with_regs_pushed: 168 SET_KERNEL_SREGS 169 cld 170 FAKE_MCOUNT(TF_EIP(%esp)) 171calltrap: 172 pushl %esp 173 call trap 174 add $4, %esp 175 176 /* 177 * Return via doreti to handle ASTs. 178 */ 179 MEXITCOUNT 180 jmp doreti 181 182/* 183 * Privileged instruction fault. 184 */ 185#ifdef KDTRACE_HOOKS 186 SUPERALIGN_TEXT 187IDTVEC(ill) 188 /* Check if there is no DTrace hook registered. */ 189 cmpl $0,dtrace_invop_jump_addr 190 je norm_ill 191 192 /* Check if this is a user fault. */ 193 cmpl $GSEL_KPL, 4(%esp) /* Check the code segment. */ 194 195 /* If so, just handle it as a normal trap. */ 196 jne norm_ill 197 198 /* 199 * This is a kernel instruction fault that might have been caused 200 * by a DTrace provider. 201 */ 202 pushal /* Push all registers onto the stack. */ 203 204 /* 205 * Set our jump address for the jump back in the event that 206 * the exception wasn't caused by DTrace at all. 207 */ 208 movl $norm_ill, dtrace_invop_calltrap_addr 209 210 /* Jump to the code hooked in by DTrace. */ 211 jmpl *dtrace_invop_jump_addr 212 213 /* 214 * Process the instruction fault in the normal way. 215 */ 216norm_ill: 217 pushl $0 218 TRAP(T_PRIVINFLT) 219#endif 220 221/* 222 * Call gate entry for syscalls (lcall 7,0). 223 * This is used by FreeBSD 1.x a.out executables and "old" NetBSD executables. 224 * 225 * The intersegment call has been set up to specify one dummy parameter. 226 * This leaves a place to put eflags so that the call frame can be 227 * converted to a trap frame. Note that the eflags is (semi-)bogusly 228 * pushed into (what will be) tf_err and then copied later into the 229 * final spot. It has to be done this way because esp can't be just 230 * temporarily altered for the pushfl - an interrupt might come in 231 * and clobber the saved cs/eip. 232 */ 233 SUPERALIGN_TEXT 234IDTVEC(lcall_syscall) 235 pushfl /* save eflags */ 236 popl 8(%esp) /* shuffle into tf_eflags */ 237 pushl $7 /* sizeof "lcall 7,0" */ 238 subl $4,%esp /* skip over tf_trapno */ 239 pushal 240 pushl $0 241 movw %ds,(%esp) 242 pushl $0 243 movw %es,(%esp) 244 pushl $0 245 movw %fs,(%esp) 246 SET_KERNEL_SREGS 247 cld 248 FAKE_MCOUNT(TF_EIP(%esp)) 249 pushl %esp 250 call syscall 251 add $4, %esp 252 MEXITCOUNT 253 jmp doreti 254 255/* 256 * Trap gate entry for syscalls (int 0x80). 257 * This is used by FreeBSD ELF executables, "new" NetBSD executables, and all 258 * Linux executables. 259 * 260 * Even though the name says 'int0x80', this is actually a trap gate, not an 261 * interrupt gate. Thus interrupts are enabled on entry just as they are for 262 * a normal syscall. 263 */ 264 SUPERALIGN_TEXT 265IDTVEC(int0x80_syscall) 266 pushl $2 /* sizeof "int 0x80" */ 267 subl $4,%esp /* skip over tf_trapno */ 268 pushal 269 pushl $0 270 movw %ds,(%esp) 271 pushl $0 272 movw %es,(%esp) 273 pushl $0 274 movw %fs,(%esp) 275 SET_KERNEL_SREGS 276 cld 277 FAKE_MCOUNT(TF_EIP(%esp)) 278 pushl %esp 279 call syscall 280 add $4, %esp 281 MEXITCOUNT 282 jmp doreti 283 284ENTRY(fork_trampoline) 285 pushl %esp /* trapframe pointer */ 286 pushl %ebx /* arg1 */ 287 pushl %esi /* function */ 288 call fork_exit 289 addl $12,%esp 290 /* cut from syscall */ 291 292 /* 293 * Return via doreti to handle ASTs. 294 */ 295 MEXITCOUNT 296 jmp doreti 297 298 299/* 300 * To efficiently implement classification of trap and interrupt handlers 301 * for profiling, there must be only trap handlers between the labels btrap 302 * and bintr, and only interrupt handlers between the labels bintr and 303 * eintr. This is implemented (partly) by including files that contain 304 * some of the handlers. Before including the files, set up a normal asm 305 * environment so that the included files doen't need to know that they are 306 * included. 307 */ 308 309 .data 310 .p2align 4 311 .text 312 SUPERALIGN_TEXT 313MCOUNT_LABEL(bintr) 314 315#ifdef DEV_ATPIC 316#include <i386/i386/atpic_vector.s> 317#endif 318 319#if defined(DEV_APIC) && defined(DEV_ATPIC) 320 .data 321 .p2align 4 322 .text 323 SUPERALIGN_TEXT 324#endif 325 326#ifdef DEV_APIC 327#include <i386/i386/apic_vector.s> 328#endif 329 330 .data 331 .p2align 4 332 .text 333 SUPERALIGN_TEXT 334#include <i386/i386/vm86bios.s> 335 336 .text 337MCOUNT_LABEL(eintr) 338 339/* 340 * void doreti(struct trapframe) 341 * 342 * Handle return from interrupts, traps and syscalls. 343 */ 344 .text 345 SUPERALIGN_TEXT 346 .type doreti,@function 347 .globl doreti 348doreti: 349 FAKE_MCOUNT($bintr) /* init "from" bintr -> doreti */ 350doreti_next: 351 /* 352 * Check if ASTs can be handled now. ASTs cannot be safely 353 * processed when returning from an NMI. 354 */ 355 cmpb $T_NMI,TF_TRAPNO(%esp) 356#ifdef HWPMC_HOOKS 357 je doreti_nmi 358#else 359 je doreti_exit 360#endif 361 /* 362 * PSL_VM must be checked first since segment registers only 363 * have an RPL in non-VM86 mode. 364 * ASTs can not be handled now if we are in a vm86 call. 365 */ 366 testl $PSL_VM,TF_EFLAGS(%esp) 367 jz doreti_notvm86 368 movl PCPU(CURPCB),%ecx 369 testl $PCB_VM86CALL,PCB_FLAGS(%ecx) 370 jz doreti_ast 371 jmp doreti_exit 372 373doreti_notvm86: 374 testb $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */ 375 jz doreti_exit /* can't handle ASTs now if not */ 376 377doreti_ast: 378 /* 379 * Check for ASTs atomically with returning. Disabling CPU 380 * interrupts provides sufficient locking even in the SMP case, 381 * since we will be informed of any new ASTs by an IPI. 382 */ 383 cli 384 movl PCPU(CURTHREAD),%eax 385 testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax) 386 je doreti_exit 387 sti 388 pushl %esp /* pass a pointer to the trapframe */ 389 call ast 390 add $4,%esp 391 jmp doreti_ast 392 393 /* 394 * doreti_exit: pop registers, iret. 395 * 396 * The segment register pop is a special case, since it may 397 * fault if (for example) a sigreturn specifies bad segment 398 * registers. The fault is handled in trap.c. 399 */ 400doreti_exit: 401 MEXITCOUNT 402 403 .globl doreti_popl_fs 404doreti_popl_fs: 405 popl %fs 406 .globl doreti_popl_es 407doreti_popl_es: 408 popl %es 409 .globl doreti_popl_ds 410doreti_popl_ds: 411 popl %ds 412 popal 413 addl $8,%esp 414 .globl doreti_iret 415doreti_iret: 416 iret 417 418 /* 419 * doreti_iret_fault and friends. Alternative return code for 420 * the case where we get a fault in the doreti_exit code 421 * above. trap() (i386/i386/trap.c) catches this specific 422 * case, sends the process a signal and continues in the 423 * corresponding place in the code below. 424 */ 425 ALIGN_TEXT 426 .globl doreti_iret_fault 427doreti_iret_fault: 428 subl $8,%esp 429 pushal 430 pushl $0 431 movw %ds,(%esp) 432 .globl doreti_popl_ds_fault 433doreti_popl_ds_fault: 434 pushl $0 435 movw %es,(%esp) 436 .globl doreti_popl_es_fault 437doreti_popl_es_fault: 438 pushl $0 439 movw %fs,(%esp) 440 .globl doreti_popl_fs_fault 441doreti_popl_fs_fault: 442 sti 443 movl $0,TF_ERR(%esp) /* XXX should be the error code */ 444 movl $T_PROTFLT,TF_TRAPNO(%esp) 445 jmp alltraps_with_regs_pushed 446#ifdef HWPMC_HOOKS 447doreti_nmi: 448 /* 449 * Since we are returning from an NMI, check if the current trap 450 * was from user mode and if so whether the current thread 451 * needs a user call chain capture. 452 */ 453 testb $SEL_RPL_MASK,TF_CS(%esp) 454 jz doreti_exit 455 movl PCPU(CURTHREAD),%eax /* curthread present? */ 456 orl %eax,%eax 457 jz doreti_exit 458 testl $TDP_CALLCHAIN,TD_PFLAGS(%eax) /* flagged for capture? */ 459 jz doreti_exit 460 /* 461 * Take the processor out of NMI mode by executing a fake "iret". 462 */ 463 pushfl 464 pushl %cs 465 pushl $outofnmi 466 iret 467outofnmi: 468 /* 469 * Call the callchain capture hook after turning interrupts back on. 470 */ 471 movl pmc_hook,%ecx 472 orl %ecx,%ecx 473 jz doreti_exit 474 pushl %esp /* frame pointer */ 475 pushl $PMC_FN_USER_CALLCHAIN /* command */ 476 movl PCPU(CURTHREAD),%eax 477 pushl %eax /* curthread */ 478 sti 479 call *%ecx 480 addl $12,%esp 481 jmp doreti_ast 482 ENTRY(end_exceptions) 483#endif 484