]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/i386/exception.s
This commit was generated by cvs2svn to compensate for changes in r172683,
[FreeBSD/FreeBSD.git] / sys / i386 / i386 / exception.s
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  * 4. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 #include "opt_apic.h"
34 #include "opt_npx.h"
35
36 #include <machine/asmacros.h>
37 #include <machine/psl.h>
38 #include <machine/trap.h>
39
40 #include "assym.s"
41
42 #define SEL_RPL_MASK    0x0003
43
44         .text
45
46 /*****************************************************************************/
47 /* Trap handling                                                             */
48 /*****************************************************************************/
49 /*
50  * Trap and fault vector routines.
51  *
52  * Most traps are 'trap gates', SDT_SYS386TGT.  A trap gate pushes state on
53  * the stack that mostly looks like an interrupt, but does not disable 
54  * interrupts.  A few of the traps we are use are interrupt gates, 
55  * SDT_SYS386IGT, which are nearly the same thing except interrupts are
56  * disabled on entry.
57  *
58  * The cpu will push a certain amount of state onto the kernel stack for
59  * the current process.  The amount of state depends on the type of trap 
60  * and whether the trap crossed rings or not.  See i386/include/frame.h.  
61  * At the very least the current EFLAGS (status register, which includes 
62  * the interrupt disable state prior to the trap), the code segment register,
63  * and the return instruction pointer are pushed by the cpu.  The cpu 
64  * will also push an 'error' code for certain traps.  We push a dummy 
65  * error code for those traps where the cpu doesn't in order to maintain 
66  * a consistent frame.  We also push a contrived 'trap number'.
67  *
68  * The cpu does not push the general registers, we must do that, and we 
69  * must restore them prior to calling 'iret'.  The cpu adjusts the %cs and
70  * %ss segment registers, but does not mess with %ds, %es, or %fs.  Thus we
71  * must load them with appropriate values for supervisor mode operation.
72  */
73
74 MCOUNT_LABEL(user)
75 MCOUNT_LABEL(btrap)
76
77 #define TRAP(a)         pushl $(a) ; jmp alltraps
78
79 IDTVEC(div)
80         pushl $0; TRAP(T_DIVIDE)
81 IDTVEC(dbg)
82         pushl $0; TRAP(T_TRCTRAP)
83 IDTVEC(nmi)
84         pushl $0; TRAP(T_NMI)
85 IDTVEC(bpt)
86         pushl $0; TRAP(T_BPTFLT)
87 IDTVEC(ofl)
88         pushl $0; TRAP(T_OFLOW)
89 IDTVEC(bnd)
90         pushl $0; TRAP(T_BOUND)
91 IDTVEC(ill)
92         pushl $0; TRAP(T_PRIVINFLT)
93 IDTVEC(dna)
94         pushl $0; TRAP(T_DNA)
95 IDTVEC(fpusegm)
96         pushl $0; TRAP(T_FPOPFLT)
97 IDTVEC(tss)
98         TRAP(T_TSSFLT)
99 IDTVEC(missing)
100         TRAP(T_SEGNPFLT)
101 IDTVEC(stk)
102         TRAP(T_STKFLT)
103 IDTVEC(prot)
104         TRAP(T_PROTFLT)
105 IDTVEC(page)
106         TRAP(T_PAGEFLT)
107 IDTVEC(mchk)
108         pushl $0; TRAP(T_MCHK)
109 IDTVEC(rsvd)
110         pushl $0; TRAP(T_RESERVED)
111 IDTVEC(fpu)
112         pushl $0; TRAP(T_ARITHTRAP)
113 IDTVEC(align)
114         TRAP(T_ALIGNFLT)
115 IDTVEC(xmm)
116         pushl $0; TRAP(T_XMMFLT)
117
118         /*
119          * alltraps entry point.  Interrupts are enabled if this was a trap
120          * gate (TGT), else disabled if this was an interrupt gate (IGT).
121          * Note that int0x80_syscall is a trap gate.   Interrupt gates are
122          * used by page faults, non-maskable interrupts, debug and breakpoint
123          * exceptions.
124          */
125
126         SUPERALIGN_TEXT
127         .globl  alltraps
128         .type   alltraps,@function
129 alltraps:
130         pushal
131         pushl   %ds
132         pushl   %es
133         pushl   %fs
134 alltraps_with_regs_pushed:
135         SET_KERNEL_SREGS
136         FAKE_MCOUNT(TF_EIP(%esp))
137 calltrap:
138         pushl   %esp
139         call    trap
140         add     $4, %esp
141         
142         /*
143          * Return via doreti to handle ASTs.
144          */
145         MEXITCOUNT
146         jmp     doreti
147
148 /*
149  * SYSCALL CALL GATE (old entry point for a.out binaries)
150  *
151  * The intersegment call has been set up to specify one dummy parameter.
152  *
153  * This leaves a place to put eflags so that the call frame can be
154  * converted to a trap frame. Note that the eflags is (semi-)bogusly
155  * pushed into (what will be) tf_err and then copied later into the
156  * final spot. It has to be done this way because esp can't be just
157  * temporarily altered for the pushfl - an interrupt might come in
158  * and clobber the saved cs/eip.
159  */
160         SUPERALIGN_TEXT
161 IDTVEC(lcall_syscall)
162         pushfl                          /* save eflags */
163         popl    8(%esp)                 /* shuffle into tf_eflags */
164         pushl   $7                      /* sizeof "lcall 7,0" */
165         subl    $4,%esp                 /* skip over tf_trapno */
166         pushal
167         pushl   %ds
168         pushl   %es
169         pushl   %fs
170         SET_KERNEL_SREGS
171         FAKE_MCOUNT(TF_EIP(%esp))
172         pushl   %esp
173         call    syscall
174         add     $4, %esp
175         MEXITCOUNT
176         jmp     doreti
177
178 /*
179  * Call gate entry for FreeBSD ELF and Linux/NetBSD syscall (int 0x80)
180  *
181  * Even though the name says 'int0x80', this is actually a TGT (trap gate)
182  * rather then an IGT (interrupt gate).  Thus interrupts are enabled on
183  * entry just as they are for a normal syscall.
184  */
185         SUPERALIGN_TEXT
186 IDTVEC(int0x80_syscall)
187         pushl   $2                      /* sizeof "int 0x80" */
188         subl    $4,%esp                 /* skip over tf_trapno */
189         pushal
190         pushl   %ds
191         pushl   %es
192         pushl   %fs
193         SET_KERNEL_SREGS
194         FAKE_MCOUNT(TF_EIP(%esp))
195         pushl   %esp
196         call    syscall
197         add     $4, %esp
198         MEXITCOUNT
199         jmp     doreti
200
201 ENTRY(fork_trampoline)
202         pushl   %esp                    /* trapframe pointer */
203         pushl   %ebx                    /* arg1 */
204         pushl   %esi                    /* function */
205         call    fork_exit
206         addl    $12,%esp
207         /* cut from syscall */
208
209         /*
210          * Return via doreti to handle ASTs.
211          */
212         MEXITCOUNT
213         jmp     doreti
214
215
216 /*
217  * To efficiently implement classification of trap and interrupt handlers
218  * for profiling, there must be only trap handlers between the labels btrap
219  * and bintr, and only interrupt handlers between the labels bintr and
220  * eintr.  This is implemented (partly) by including files that contain
221  * some of the handlers.  Before including the files, set up a normal asm
222  * environment so that the included files doen't need to know that they are
223  * included.
224  */
225
226         .data
227         .p2align 4
228         .text
229         SUPERALIGN_TEXT
230 MCOUNT_LABEL(bintr)
231
232 #include <i386/isa/atpic_vector.s>
233
234 #ifdef DEV_APIC
235         .data
236         .p2align 4
237         .text
238         SUPERALIGN_TEXT
239
240 #include <i386/i386/apic_vector.s>
241 #endif
242
243         .data
244         .p2align 4
245         .text
246         SUPERALIGN_TEXT
247 #include <i386/i386/vm86bios.s>
248
249         .text
250 MCOUNT_LABEL(eintr)
251
252 /*
253  * void doreti(struct trapframe)
254  *
255  * Handle return from interrupts, traps and syscalls.
256  */
257         .text
258         SUPERALIGN_TEXT
259         .type   doreti,@function
260 doreti:
261         FAKE_MCOUNT($bintr)             /* init "from" bintr -> doreti */
262 doreti_next:
263         /*
264          * Check if ASTs can be handled now.  PSL_VM must be checked first
265          * since segment registers only have an RPL in non-VM86 mode.
266          */
267         testl   $PSL_VM,TF_EFLAGS(%esp) /* are we in vm86 mode? */
268         jz      doreti_notvm86
269         movl    PCPU(CURPCB),%ecx
270         testl   $PCB_VM86CALL,PCB_FLAGS(%ecx)   /* are we in a vm86 call? */
271         jz      doreti_ast              /* can handle ASTS now if not */
272         jmp     doreti_exit
273
274 doreti_notvm86:
275         testb   $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */
276         jz      doreti_exit             /* can't handle ASTs now if not */
277
278 doreti_ast:
279         /*
280          * Check for ASTs atomically with returning.  Disabling CPU
281          * interrupts provides sufficient locking even in the SMP case,
282          * since we will be informed of any new ASTs by an IPI.
283          */
284         cli
285         movl    PCPU(CURTHREAD),%eax
286         testl   $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax)
287         je      doreti_exit
288         sti
289         pushl   %esp                    /* pass a pointer to the trapframe */
290         call    ast
291         add     $4,%esp
292         jmp     doreti_ast
293
294         /*
295          * doreti_exit: pop registers, iret.
296          *
297          *      The segment register pop is a special case, since it may
298          *      fault if (for example) a sigreturn specifies bad segment
299          *      registers.  The fault is handled in trap.c.
300          */
301 doreti_exit:
302         MEXITCOUNT
303
304         .globl  doreti_popl_fs
305 doreti_popl_fs:
306         popl    %fs
307         .globl  doreti_popl_es
308 doreti_popl_es:
309         popl    %es
310         .globl  doreti_popl_ds
311 doreti_popl_ds:
312         popl    %ds
313         popal
314         addl    $8,%esp
315         .globl  doreti_iret
316 doreti_iret:
317         iret
318
319         /*
320          * doreti_iret_fault and friends.  Alternative return code for
321          * the case where we get a fault in the doreti_exit code
322          * above.  trap() (i386/i386/trap.c) catches this specific
323          * case, sends the process a signal and continues in the
324          * corresponding place in the code below.
325          */
326         ALIGN_TEXT
327         .globl  doreti_iret_fault
328 doreti_iret_fault:
329         subl    $8,%esp
330         pushal
331         pushl   %ds
332         .globl  doreti_popl_ds_fault
333 doreti_popl_ds_fault:
334         pushl   %es
335         .globl  doreti_popl_es_fault
336 doreti_popl_es_fault:
337         pushl   %fs
338         .globl  doreti_popl_fs_fault
339 doreti_popl_fs_fault:
340         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
341         movl    $T_PROTFLT,TF_TRAPNO(%esp)
342         jmp     alltraps_with_regs_pushed