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$ 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 %ds 162 pushl %es 163 pushl %fs 164alltraps_with_regs_pushed: 165 SET_KERNEL_SREGS 166 cld 167 FAKE_MCOUNT(TF_EIP(%esp)) 168calltrap: 169 pushl %esp 170 call trap 171 add $4, %esp 172 173 /* 174 * Return via doreti to handle ASTs. 175 */ 176 MEXITCOUNT 177 jmp doreti 178 179/* 180 * Privileged instruction fault. 181 */ 182#ifdef KDTRACE_HOOKS 183 SUPERALIGN_TEXT 184IDTVEC(ill) 185 /* Check if there is no DTrace hook registered. */ 186 cmpl $0,dtrace_invop_jump_addr 187 je norm_ill 188 189 /* Check if this is a user fault. */ 190 cmpl $GSEL_KPL, 4(%esp) /* Check the code segment. */ 191 192 /* If so, just handle it as a normal trap. */ 193 jne norm_ill 194 195 /* 196 * This is a kernel instruction fault that might have been caused 197 * by a DTrace provider. 198 */ 199 pushal /* Push all registers onto the stack. */ 200 201 /* 202 * Set our jump address for the jump back in the event that 203 * the exception wasn't caused by DTrace at all. 204 */ 205 movl $norm_ill, dtrace_invop_calltrap_addr 206 207 /* Jump to the code hooked in by DTrace. */ 208 jmpl *dtrace_invop_jump_addr 209 210 /* 211 * Process the instruction fault in the normal way. 212 */ 213norm_ill: 214 pushl $0 215 TRAP(T_PRIVINFLT) 216#endif 217 218/* 219 * Call gate entry for syscalls (lcall 7,0). 220 * This is used by FreeBSD 1.x a.out executables and "old" NetBSD executables. 221 * 222 * The intersegment call has been set up to specify one dummy parameter. 223 * This leaves a place to put eflags so that the call frame can be 224 * converted to a trap frame. Note that the eflags is (semi-)bogusly 225 * pushed into (what will be) tf_err and then copied later into the 226 * final spot. It has to be done this way because esp can't be just 227 * temporarily altered for the pushfl - an interrupt might come in 228 * and clobber the saved cs/eip. 229 */ 230 SUPERALIGN_TEXT 231IDTVEC(lcall_syscall) 232 pushfl /* save eflags */ 233 popl 8(%esp) /* shuffle into tf_eflags */ 234 pushl $7 /* sizeof "lcall 7,0" */ 235 subl $4,%esp /* skip over tf_trapno */ 236 pushal 237 pushl %ds 238 pushl %es 239 pushl %fs 240 SET_KERNEL_SREGS 241 cld 242 FAKE_MCOUNT(TF_EIP(%esp)) 243 pushl %esp 244 call syscall 245 add $4, %esp 246 MEXITCOUNT 247 jmp doreti 248 249/* 250 * Trap gate entry for syscalls (int 0x80). 251 * This is used by FreeBSD ELF executables, "new" NetBSD executables, and all 252 * Linux executables. 253 * 254 * Even though the name says 'int0x80', this is actually a trap gate, not an 255 * interrupt gate. Thus interrupts are enabled on entry just as they are for 256 * a normal syscall. 257 */ 258 SUPERALIGN_TEXT 259IDTVEC(int0x80_syscall) 260 pushl $2 /* sizeof "int 0x80" */ 261 subl $4,%esp /* skip over tf_trapno */ 262 pushal 263 pushl %ds 264 pushl %es 265 pushl %fs 266 SET_KERNEL_SREGS 267 cld 268 FAKE_MCOUNT(TF_EIP(%esp)) 269 pushl %esp 270 call syscall 271 add $4, %esp 272 MEXITCOUNT 273 jmp doreti 274 275ENTRY(fork_trampoline) 276 pushl %esp /* trapframe pointer */ 277 pushl %ebx /* arg1 */ 278 pushl %esi /* function */ 279 call fork_exit 280 addl $12,%esp 281 /* cut from syscall */ 282 283 /* 284 * Return via doreti to handle ASTs. 285 */ 286 MEXITCOUNT 287 jmp doreti 288 289 290/* 291 * To efficiently implement classification of trap and interrupt handlers 292 * for profiling, there must be only trap handlers between the labels btrap 293 * and bintr, and only interrupt handlers between the labels bintr and 294 * eintr. This is implemented (partly) by including files that contain 295 * some of the handlers. Before including the files, set up a normal asm 296 * environment so that the included files doen't need to know that they are 297 * included. 298 */ 299 300 .data 301 .p2align 4 302 .text 303 SUPERALIGN_TEXT 304MCOUNT_LABEL(bintr) 305 306#ifdef DEV_ATPIC 307#include <i386/i386/atpic_vector.s> 308#endif 309 310#if defined(DEV_APIC) && defined(DEV_ATPIC) 311 .data 312 .p2align 4 313 .text 314 SUPERALIGN_TEXT 315#endif 316 317#ifdef DEV_APIC 318#include <i386/i386/apic_vector.s> 319#endif 320 321 .data 322 .p2align 4 323 .text 324 SUPERALIGN_TEXT 325#include <i386/i386/vm86bios.s> 326 327 .text 328MCOUNT_LABEL(eintr) 329 330/* 331 * void doreti(struct trapframe) 332 * 333 * Handle return from interrupts, traps and syscalls. 334 */ 335 .text 336 SUPERALIGN_TEXT 337 .type doreti,@function 338doreti: 339 FAKE_MCOUNT($bintr) /* init "from" bintr -> doreti */ 340doreti_next: 341 /* 342 * Check if ASTs can be handled now. ASTs cannot be safely 343 * processed when returning from an NMI. 344 */ 345 cmpb $T_NMI,TF_TRAPNO(%esp) 346#ifdef HWPMC_HOOKS 347 je doreti_nmi 348#else 349 je doreti_exit 350#endif 351 /* 352 * PSL_VM must be checked first since segment registers only 353 * have an RPL in non-VM86 mode. 354 * ASTs can not be handled now if we are in a vm86 call. 355 */ 356 testl $PSL_VM,TF_EFLAGS(%esp) 357 jz doreti_notvm86 358 movl PCPU(CURPCB),%ecx 359 testl $PCB_VM86CALL,PCB_FLAGS(%ecx) 360 jz doreti_ast 361 jmp doreti_exit 362 363doreti_notvm86: 364 testb $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */ 365 jz doreti_exit /* can't handle ASTs now if not */ 366 367doreti_ast: 368 /* 369 * Check for ASTs atomically with returning. Disabling CPU 370 * interrupts provides sufficient locking even in the SMP case, 371 * since we will be informed of any new ASTs by an IPI. 372 */ 373 cli 374 movl PCPU(CURTHREAD),%eax 375 testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax) 376 je doreti_exit 377 sti 378 pushl %esp /* pass a pointer to the trapframe */ 379 call ast 380 add $4,%esp 381 jmp doreti_ast 382 383 /* 384 * doreti_exit: pop registers, iret. 385 * 386 * The segment register pop is a special case, since it may 387 * fault if (for example) a sigreturn specifies bad segment 388 * registers. The fault is handled in trap.c. 389 */ 390doreti_exit: 391 MEXITCOUNT 392 393 .globl doreti_popl_fs 394doreti_popl_fs: 395 popl %fs 396 .globl doreti_popl_es 397doreti_popl_es: 398 popl %es 399 .globl doreti_popl_ds 400doreti_popl_ds: 401 popl %ds 402 popal 403 addl $8,%esp 404 .globl doreti_iret 405doreti_iret: 406 iret 407 408 /* 409 * doreti_iret_fault and friends. Alternative return code for 410 * the case where we get a fault in the doreti_exit code 411 * above. trap() (i386/i386/trap.c) catches this specific 412 * case, sends the process a signal and continues in the 413 * corresponding place in the code below. 414 */ 415 ALIGN_TEXT 416 .globl doreti_iret_fault 417doreti_iret_fault: 418 subl $8,%esp 419 pushal 420 pushl %ds 421 .globl doreti_popl_ds_fault 422doreti_popl_ds_fault: 423 pushl %es 424 .globl doreti_popl_es_fault 425doreti_popl_es_fault: 426 pushl %fs 427 .globl doreti_popl_fs_fault 428doreti_popl_fs_fault: 429 sti 430 movl $0,TF_ERR(%esp) /* XXX should be the error code */ 431 movl $T_PROTFLT,TF_TRAPNO(%esp) 432 jmp alltraps_with_regs_pushed 433#ifdef HWPMC_HOOKS 434doreti_nmi: 435 /* 436 * Since we are returning from an NMI, check if the current trap 437 * was from user mode and if so whether the current thread 438 * needs a user call chain capture. 439 */ 440 testb $SEL_RPL_MASK,TF_CS(%esp) 441 jz doreti_exit 442 movl PCPU(CURTHREAD),%eax /* curthread present? */ 443 orl %eax,%eax 444 jz doreti_exit 445 testl $TDP_CALLCHAIN,TD_PFLAGS(%eax) /* flagged for capture? */ 446 jz doreti_exit 447 /* 448 * Take the processor out of NMI mode by executing a fake "iret". 449 */ 450 pushfl 451 pushl %cs 452 pushl $outofnmi 453 iret 454outofnmi: 455 /* 456 * Call the callchain capture hook after turning interrupts back on. 457 */ 458 movl pmc_hook,%ecx 459 orl %ecx,%ecx 460 jz doreti_exit 461 pushl %esp /* frame pointer */ 462 pushl $PMC_FN_USER_CALLCHAIN /* command */ 463 movl PCPU(CURTHREAD),%eax 464 pushl %eax /* curthread */ 465 sti 466 call *%ecx 467 addl $12,%esp 468 jmp doreti_ast 469 ENTRY(end_exceptions) 470#endif 471