1 /*-
2 * Copyright (c) 1989, 1990 William F. Jolitz.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
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: releng/5.0/sys/i386/i386/exception.s 106542 2002-11-07 01:34:23Z davidxu $
35 */
36
37 #include "opt_npx.h"
38
39 #include <machine/asmacros.h>
40 #include <sys/mutex.h>
41 #include <machine/psl.h>
42 #include <machine/trap.h>
43 #ifdef SMP
44 #include <machine/smptests.h> /** various SMP options */
45 #endif
46
47 #include "assym.s"
48
49 #define SEL_RPL_MASK 0x0003
50
51 .text
52
53 /*****************************************************************************/
54 /* Trap handling */
55 /*****************************************************************************/
56 /*
57 * Trap and fault vector routines.
58 *
59 * Most traps are 'trap gates', SDT_SYS386TGT. A trap gate pushes state on
60 * the stack that mostly looks like an interrupt, but does not disable
61 * interrupts. A few of the traps we are use are interrupt gates,
62 * SDT_SYS386IGT, which are nearly the same thing except interrupts are
63 * disabled on entry.
64 *
65 * The cpu will push a certain amount of state onto the kernel stack for
66 * the current process. The amount of state depends on the type of trap
67 * and whether the trap crossed rings or not. See i386/include/frame.h.
68 * At the very least the current EFLAGS (status register, which includes
69 * the interrupt disable state prior to the trap), the code segment register,
70 * and the return instruction pointer are pushed by the cpu. The cpu
71 * will also push an 'error' code for certain traps. We push a dummy
72 * error code for those traps where the cpu doesn't in order to maintain
73 * a consistent frame. We also push a contrived 'trap number'.
74 *
75 * The cpu does not push the general registers, we must do that, and we
76 * must restore them prior to calling 'iret'. The cpu adjusts the %cs and
77 * %ss segment registers, but does not mess with %ds, %es, or %fs. Thus we
78 * must load them with appropriate values for supervisor mode operation.
79 */
80 #define IDTVEC(name) ALIGN_TEXT; .globl __CONCAT(X,name); \
81 .type __CONCAT(X,name),@function; __CONCAT(X,name):
82 #define TRAP(a) pushl $(a) ; jmp alltraps
83
84 #ifdef BDE_DEBUGGER
85 #define BDBTRAP(name) \
86 ss ; \
87 cmpb $0,_bdb_exists ; \
88 je 1f ; \
89 testb $SEL_RPL_MASK,4(%esp) ; \
90 jne 1f ; \
91 ss ; \
92 .globl __CONCAT(__CONCAT(bdb_,name),_ljmp); \
93 __CONCAT(__CONCAT(bdb_,name),_ljmp): \
94 ljmp $0,$0 ; \
95 1:
96 #else
97 #define BDBTRAP(name)
98 #endif
99
100 MCOUNT_LABEL(user)
101 MCOUNT_LABEL(btrap)
102
103 IDTVEC(div)
104 pushl $0; TRAP(T_DIVIDE)
105 IDTVEC(dbg)
106 BDBTRAP(dbg)
107 pushl $0; TRAP(T_TRCTRAP)
108 IDTVEC(nmi)
109 pushl $0; TRAP(T_NMI)
110 IDTVEC(bpt)
111 BDBTRAP(bpt)
112 pushl $0; TRAP(T_BPTFLT)
113 IDTVEC(ofl)
114 pushl $0; TRAP(T_OFLOW)
115 IDTVEC(bnd)
116 pushl $0; TRAP(T_BOUND)
117 IDTVEC(ill)
118 pushl $0; TRAP(T_PRIVINFLT)
119 IDTVEC(dna)
120 pushl $0; TRAP(T_DNA)
121 IDTVEC(fpusegm)
122 pushl $0; TRAP(T_FPOPFLT)
123 IDTVEC(tss)
124 TRAP(T_TSSFLT)
125 IDTVEC(missing)
126 TRAP(T_SEGNPFLT)
127 IDTVEC(stk)
128 TRAP(T_STKFLT)
129 IDTVEC(prot)
130 TRAP(T_PROTFLT)
131 IDTVEC(page)
132 TRAP(T_PAGEFLT)
133 IDTVEC(mchk)
134 pushl $0; TRAP(T_MCHK)
135 IDTVEC(rsvd)
136 pushl $0; TRAP(T_RESERVED)
137 IDTVEC(fpu)
138 pushl $0; TRAP(T_ARITHTRAP)
139 IDTVEC(align)
140 TRAP(T_ALIGNFLT)
141
142 IDTVEC(xmm)
143 pushl $0; TRAP(T_XMMFLT)
144
145 /*
146 * alltraps entry point. Interrupts are enabled if this was a trap
147 * gate (TGT), else disabled if this was an interrupt gate (IGT).
148 * Note that int0x80_syscall is a trap gate. Only page faults
149 * use an interrupt gate.
150 */
151
152 SUPERALIGN_TEXT
153 .globl alltraps
154 .type alltraps,@function
155 alltraps:
156 pushal
157 pushl %ds
158 pushl %es
159 pushl %fs
160 alltraps_with_regs_pushed:
161 mov $KDSEL,%ax
162 mov %ax,%ds
163 mov %ax,%es
164 mov $KPSEL,%ax
165 mov %ax,%fs
166 FAKE_MCOUNT(13*4(%esp))
167 calltrap:
168 FAKE_MCOUNT(btrap) /* init "from" btrap -> calltrap */
169 call trap
170
171 /*
172 * Return via doreti to handle ASTs.
173 */
174 MEXITCOUNT
175 jmp doreti
176
177 /*
178 * SYSCALL CALL GATE (old entry point for a.out binaries)
179 *
180 * The intersegment call has been set up to specify one dummy parameter.
181 *
182 * This leaves a place to put eflags so that the call frame can be
183 * converted to a trap frame. Note that the eflags is (semi-)bogusly
184 * pushed into (what will be) tf_err and then copied later into the
185 * final spot. It has to be done this way because esp can't be just
186 * temporarily altered for the pushfl - an interrupt might come in
187 * and clobber the saved cs/eip.
188 */
189 SUPERALIGN_TEXT
190 IDTVEC(lcall_syscall)
191 pushfl /* save eflags */
192 popl 8(%esp) /* shuffle into tf_eflags */
193 pushl $7 /* sizeof "lcall 7,0" */
194 subl $4,%esp /* skip over tf_trapno */
195 pushal
196 pushl %ds
197 pushl %es
198 pushl %fs
199 mov $KDSEL,%ax /* switch to kernel segments */
200 mov %ax,%ds
201 mov %ax,%es
202 mov $KPSEL,%ax
203 mov %ax,%fs
204 FAKE_MCOUNT(13*4(%esp))
205 call syscall
206 MEXITCOUNT
207 jmp doreti
208
209 /*
210 * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80)
211 *
212 * Even though the name says 'int0x80', this is actually a TGT (trap gate)
213 * rather then an IGT (interrupt gate). Thus interrupts are enabled on
214 * entry just as they are for a normal syscall.
215 */
216 SUPERALIGN_TEXT
217 IDTVEC(int0x80_syscall)
218 pushl $2 /* sizeof "int 0x80" */
219 subl $4,%esp /* skip over tf_trapno */
220 pushal
221 pushl %ds
222 pushl %es
223 pushl %fs
224 mov $KDSEL,%ax /* switch to kernel segments */
225 mov %ax,%ds
226 mov %ax,%es
227 mov $KPSEL,%ax
228 mov %ax,%fs
229 FAKE_MCOUNT(13*4(%esp))
230 call syscall
231 MEXITCOUNT
232 jmp doreti
233
234 ENTRY(fork_trampoline)
235 pushl %esp /* trapframe pointer */
236 pushl %ebx /* arg1 */
237 pushl %esi /* function */
238 movl PCPU(CURTHREAD),%ebx /* setup critnest */
239 movl $1,TD_CRITNEST(%ebx)
240 sti /* enable interrupts */
241 call fork_exit
242 addl $12,%esp
243 /* cut from syscall */
244
245 /*
246 * Return via doreti to handle ASTs.
247 */
248 MEXITCOUNT
249 jmp doreti
250
251
252 /*
253 * Include vm86 call routines, which want to call doreti.
254 */
255 #include "i386/i386/vm86bios.s"
256
257 /*
258 * Include what was once config+isa-dependent code.
259 * XXX it should be in a stand-alone file. It's still icu-dependent and
260 * belongs in i386/isa.
261 */
262 #include "i386/isa/vector.s"
263
264 .data
265 ALIGN_DATA
266
267 /*
268 * void doreti(struct trapframe)
269 *
270 * Handle return from interrupts, traps and syscalls.
271 */
272 .text
273 SUPERALIGN_TEXT
274 .type doreti,@function
275 doreti:
276 FAKE_MCOUNT(bintr) /* init "from" bintr -> doreti */
277 doreti_next:
278 /*
279 * Check if ASTs can be handled now. PSL_VM must be checked first
280 * since segment registers only have an RPL in non-VM86 mode.
281 */
282 testl $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
283 jz doreti_notvm86
284 movl PCPU(CURPCB),%ecx
285 testl $PCB_VM86CALL,PCB_FLAGS(%ecx) /* are we in a vm86 call? */
286 jz doreti_ast /* can handle ASTS now if not */
287 jmp doreti_exit
288
289 doreti_notvm86:
290 testb $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */
291 jz doreti_exit /* can't handle ASTs now if not */
292
293 doreti_ast:
294 /*
295 * Check for ASTs atomically with returning. Disabling CPU
296 * interrupts provides sufficient locking evein the SMP case,
297 * since we will be informed of any new ASTs by an IPI.
298 */
299 cli
300 movl PCPU(CURTHREAD),%eax
301 movl TD_KSE(%eax), %eax
302 testl $KEF_ASTPENDING | KEF_NEEDRESCHED,KE_FLAGS(%eax)
303 je doreti_exit
304 sti
305 pushl %esp /* pass a pointer to the trapframe */
306 call ast
307 add $4,%esp
308 jmp doreti_ast
309
310 /*
311 * doreti_exit: pop registers, iret.
312 *
313 * The segment register pop is a special case, since it may
314 * fault if (for example) a sigreturn specifies bad segment
315 * registers. The fault is handled in trap.c.
316 */
317 doreti_exit:
318 MEXITCOUNT
319
320 .globl doreti_popl_fs
321 doreti_popl_fs:
322 popl %fs
323 .globl doreti_popl_es
324 doreti_popl_es:
325 popl %es
326 .globl doreti_popl_ds
327 doreti_popl_ds:
328 popl %ds
329 popal
330 addl $8,%esp
331 .globl doreti_iret
332 doreti_iret:
333 iret
334
335 /*
336 * doreti_iret_fault and friends. Alternative return code for
337 * the case where we get a fault in the doreti_exit code
338 * above. trap() (i386/i386/trap.c) catches this specific
339 * case, sends the process a signal and continues in the
340 * corresponding place in the code below.
341 */
342 ALIGN_TEXT
343 .globl doreti_iret_fault
344 doreti_iret_fault:
345 subl $8,%esp
346 pushal
347 pushl %ds
348 .globl doreti_popl_ds_fault
349 doreti_popl_ds_fault:
350 pushl %es
351 .globl doreti_popl_es_fault
352 doreti_popl_es_fault:
353 pushl %fs
354 .globl doreti_popl_fs_fault
355 doreti_popl_fs_fault:
356 movl $0,TF_ERR(%esp) /* XXX should be the error code */
357 movl $T_PROTFLT,TF_TRAPNO(%esp)
358 jmp alltraps_with_regs_pushed
359
360 #ifdef APIC_IO
361 #include "i386/isa/apic_ipl.s"
362 #else
363 #include "i386/isa/icu_ipl.s"
364 #endif /* APIC_IO */
Cache object: 760262e745e773ed5a3dcc44635e7d3e
|