exception.s revision 68737
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: head/sys/i386/i386/exception.s 68737 2000-11-14 23:01:24Z jhb $ 34 */ 35 36#include "npx.h" 37 38#include <machine/asmacros.h> 39#include <sys/ipl.h> 40#include <machine/lock.h> 41#include <machine/mutex.h> 42#include <machine/psl.h> 43#include <machine/trap.h> 44#ifdef SMP 45#include <machine/smptests.h> /** various SMP options */ 46#endif 47 48#include "assym.s" 49 50#ifdef SMP 51#define MOVL_KPSEL_EAX movl $KPSEL,%eax 52#else 53#define MOVL_KPSEL_EAX 54#endif 55#define SEL_RPL_MASK 0x0003 56 57 .text 58 59/*****************************************************************************/ 60/* Trap handling */ 61/*****************************************************************************/ 62/* 63 * Trap and fault vector routines. 64 * 65 * Most traps are 'trap gates', SDT_SYS386TGT. A trap gate pushes state on 66 * the stack that mostly looks like an interrupt, but does not disable 67 * interrupts. A few of the traps we are use are interrupt gates, 68 * SDT_SYS386IGT, which are nearly the same thing except interrupts are 69 * disabled on entry. 70 * 71 * The cpu will push a certain amount of state onto the kernel stack for 72 * the current process. The amount of state depends on the type of trap 73 * and whether the trap crossed rings or not. See i386/include/frame.h. 74 * At the very least the current EFLAGS (status register, which includes 75 * the interrupt disable state prior to the trap), the code segment register, 76 * and the return instruction pointer are pushed by the cpu. The cpu 77 * will also push an 'error' code for certain traps. We push a dummy 78 * error code for those traps where the cpu doesn't in order to maintain 79 * a consistent frame. We also push a contrived 'trap number'. 80 * 81 * The cpu does not push the general registers, we must do that, and we 82 * must restore them prior to calling 'iret'. The cpu adjusts the %cs and 83 * %ss segment registers, but does not mess with %ds, %es, or %fs. Thus we 84 * must load them with appropriate values for supervisor mode operation. 85 * 86 * On entry to a trap or interrupt WE DO NOT OWN THE MP LOCK. This means 87 * that we must be careful in regards to accessing global variables. We 88 * save (push) the current cpl (our software interrupt disable mask), call 89 * the trap function, then call _doreti to restore the cpl and deal with 90 * ASTs (software interrupts). _doreti will determine if the restoration 91 * of the cpl unmasked any pending interrupts and will issue those interrupts 92 * synchronously prior to doing the iret. 93 * 94 * At the moment we must own the MP lock to do any cpl manipulation, which 95 * means we must own it prior to calling _doreti. The syscall case attempts 96 * to avoid this by handling a reduced set of cases itself and iret'ing. 97 */ 98#define IDTVEC(name) ALIGN_TEXT; .globl __CONCAT(_X,name); \ 99 .type __CONCAT(_X,name),@function; __CONCAT(_X,name): 100#define TRAP(a) pushl $(a) ; jmp _alltraps 101 102#ifdef BDE_DEBUGGER 103#define BDBTRAP(name) \ 104 ss ; \ 105 cmpb $0,_bdb_exists ; \ 106 je 1f ; \ 107 testb $SEL_RPL_MASK,4(%esp) ; \ 108 jne 1f ; \ 109 ss ; \ 110 .globl __CONCAT(__CONCAT(bdb_,name),_ljmp); \ 111__CONCAT(__CONCAT(bdb_,name),_ljmp): \ 112 ljmp $0,$0 ; \ 1131: 114#else 115#define BDBTRAP(name) 116#endif 117 118#define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; TRAP(a) 119 120MCOUNT_LABEL(user) 121MCOUNT_LABEL(btrap) 122 123IDTVEC(div) 124 pushl $0; TRAP(T_DIVIDE) 125IDTVEC(dbg) 126 BDBTRAP(dbg) 127 pushl $0; BPTTRAP(T_TRCTRAP) 128IDTVEC(nmi) 129 pushl $0; TRAP(T_NMI) 130IDTVEC(bpt) 131 BDBTRAP(bpt) 132 pushl $0; BPTTRAP(T_BPTFLT) 133IDTVEC(ofl) 134 pushl $0; TRAP(T_OFLOW) 135IDTVEC(bnd) 136 pushl $0; TRAP(T_BOUND) 137IDTVEC(ill) 138 pushl $0; TRAP(T_PRIVINFLT) 139IDTVEC(dna) 140 pushl $0; TRAP(T_DNA) 141IDTVEC(fpusegm) 142 pushl $0; TRAP(T_FPOPFLT) 143IDTVEC(tss) 144 TRAP(T_TSSFLT) 145IDTVEC(missing) 146 TRAP(T_SEGNPFLT) 147IDTVEC(stk) 148 TRAP(T_STKFLT) 149IDTVEC(prot) 150 TRAP(T_PROTFLT) 151IDTVEC(page) 152 TRAP(T_PAGEFLT) 153IDTVEC(mchk) 154 pushl $0; TRAP(T_MCHK) 155IDTVEC(rsvd) 156 pushl $0; TRAP(T_RESERVED) 157 158IDTVEC(fpu) 159#if NNPX > 0 160 /* 161 * Handle like an interrupt (except for accounting) so that we can 162 * call npx_intr to clear the error. It would be better to handle 163 * npx interrupts as traps. Nested interrupts would probably have 164 * to be converted to ASTs. 165 */ 166 pushl $0 /* dummy error code */ 167 pushl $0 /* dummy trap type */ 168 pushal 169 pushl %ds 170 pushl %es /* now stack frame is a trap frame */ 171 pushl %fs 172 mov $KDSEL,%ax 173 mov %ax,%ds 174 mov %ax,%es 175 MOVL_KPSEL_EAX 176 mov %ax,%fs 177 FAKE_MCOUNT(13*4(%esp)) 178 179 MPLOCKED incl _cnt+V_TRAP 180 pushl $0 /* dummy unit to finish intr frame */ 181 182 call __mtx_enter_giant_def 183 call _npx_intr 184 call __mtx_exit_giant_def 185 186 incb _intr_nesting_level 187 MEXITCOUNT 188 jmp _doreti 189#else /* NNPX > 0 */ 190 pushl $0; TRAP(T_ARITHTRAP) 191#endif /* NNPX > 0 */ 192 193IDTVEC(align) 194 TRAP(T_ALIGNFLT) 195 196 /* 197 * _alltraps entry point. Interrupts are enabled if this was a trap 198 * gate (TGT), else disabled if this was an interrupt gate (IGT). 199 * Note that int0x80_syscall is a trap gate. Only page faults 200 * use an interrupt gate. 201 */ 202 203 SUPERALIGN_TEXT 204 .globl _alltraps 205 .type _alltraps,@function 206_alltraps: 207 pushal 208 pushl %ds 209 pushl %es 210 pushl %fs 211alltraps_with_regs_pushed: 212 mov $KDSEL,%ax 213 mov %ax,%ds 214 mov %ax,%es 215 MOVL_KPSEL_EAX 216 mov %ax,%fs 217 FAKE_MCOUNT(13*4(%esp)) 218calltrap: 219 FAKE_MCOUNT(_btrap) /* init "from" _btrap -> calltrap */ 220 call _trap 221 222 /* 223 * Return via _doreti to handle ASTs. Have to change trap frame 224 * to interrupt frame. 225 */ 226 subl $4,%esp /* dummy unit to finish intr frame */ 227 incb _intr_nesting_level 228 MEXITCOUNT 229 jmp _doreti 230 231/* 232 * SYSCALL CALL GATE (old entry point for a.out binaries) 233 * 234 * The intersegment call has been set up to specify one dummy parameter. 235 * 236 * This leaves a place to put eflags so that the call frame can be 237 * converted to a trap frame. Note that the eflags is (semi-)bogusly 238 * pushed into (what will be) tf_err and then copied later into the 239 * final spot. It has to be done this way because esp can't be just 240 * temporarily altered for the pushfl - an interrupt might come in 241 * and clobber the saved cs/eip. 242 * 243 * We do not obtain the MP lock, but the call to syscall2 might. If it 244 * does it will release the lock prior to returning. 245 */ 246 SUPERALIGN_TEXT 247IDTVEC(syscall) 248 pushfl /* save eflags in tf_err for now */ 249 subl $4,%esp /* skip over tf_trapno */ 250 pushal 251 pushl %ds 252 pushl %es 253 pushl %fs 254 mov $KDSEL,%ax /* switch to kernel segments */ 255 mov %ax,%ds 256 mov %ax,%es 257 MOVL_KPSEL_EAX 258 mov %ax,%fs 259 movl TF_ERR(%esp),%eax /* copy saved eflags to final spot */ 260 movl %eax,TF_EFLAGS(%esp) 261 movl $7,TF_ERR(%esp) /* sizeof "lcall 7,0" */ 262 FAKE_MCOUNT(13*4(%esp)) 263 call _syscall2 264 MEXITCOUNT 265 cli /* atomic astpending access */ 266 cmpl $0,_astpending /* AST pending? */ 267 je doreti_syscall_ret /* no, get out of here */ 268 subl $4,%esp /* dummy unit for interrupt frame */ 269 movb $1,_intr_nesting_level 270 jmp _doreti 271 272/* 273 * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80) 274 * 275 * Even though the name says 'int0x80', this is actually a TGT (trap gate) 276 * rather then an IGT (interrupt gate). Thus interrupts are enabled on 277 * entry just as they are for a normal syscall. 278 * 279 * We do not obtain the MP lock, but the call to syscall2 might. If it 280 * does it will release the lock prior to returning. 281 */ 282 SUPERALIGN_TEXT 283IDTVEC(int0x80_syscall) 284 subl $8,%esp /* skip over tf_trapno and tf_err */ 285 pushal 286 pushl %ds 287 pushl %es 288 pushl %fs 289 mov $KDSEL,%ax /* switch to kernel segments */ 290 mov %ax,%ds 291 mov %ax,%es 292 MOVL_KPSEL_EAX 293 mov %ax,%fs 294 movl $2,TF_ERR(%esp) /* sizeof "int 0x80" */ 295 FAKE_MCOUNT(13*4(%esp)) 296 call _syscall2 297 MEXITCOUNT 298 cli /* atomic astpending access */ 299 cmpl $0,_astpending /* AST pending? */ 300 je doreti_syscall_ret /* no, get out of here */ 301 subl $4,%esp /* dummy unit for interrupt frame */ 302 movb $1,_intr_nesting_level 303 jmp _doreti 304 305ENTRY(fork_trampoline) 306 MTX_EXIT(_sched_lock, %ecx) 307 sti /* XXX: we need this for kernel threads 308 created very early before interrupts 309 are enabled */ 310 311#ifdef SMP 312 cmpl $0,_switchtime 313 jne 1f 314 movl $gd_switchtime,%eax 315 addl %fs:0,%eax 316 pushl %eax 317 call _microuptime 318 popl %edx 319 movl _ticks,%eax 320 movl %eax,_switchticks 3211: 322#endif 323 324 /* 325 * cpu_set_fork_handler intercepts this function call to 326 * have this call a non-return function to stay in kernel mode. 327 * initproc has its own fork handler, but it does return. 328 */ 329 pushl %ebx /* arg1 */ 330 call *%esi /* function */ 331 addl $4,%esp 332 /* cut from syscall */ 333 334 /* 335 * Return via _doreti to handle ASTs. 336 */ 337 subl $4,%esp /* dummy unit to finish intr frame */ 338 movb $1,_intr_nesting_level 339 MEXITCOUNT 340 jmp _doreti 341 342 343/* 344 * Include vm86 call routines, which want to call _doreti. 345 */ 346#include "i386/i386/vm86bios.s" 347 348/* 349 * Include what was once config+isa-dependent code. 350 * XXX it should be in a stand-alone file. It's still icu-dependent and 351 * belongs in i386/isa. 352 */ 353#include "i386/isa/vector.s" 354 355/* 356 * Include what was once icu-dependent code. 357 * XXX it should be merged into this file (also move the definition of 358 * imen to vector.s or isa.c). 359 * Before including it, set up a normal asm environment so that vector.s 360 * doesn't have to know that stuff is included after it. 361 */ 362 .data 363 ALIGN_DATA 364 .text 365 SUPERALIGN_TEXT 366#include "i386/isa/ipl.s" 367