44b5c5385bf78f81fe66c6bce8be283da25cc21a
[dragonfly.git] / sys / i386 / isa / ipl.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  * This code is derived from software contributed to Berkeley by
7  * William Jolitz.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *      @(#)ipl.s
38  *
39  * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $
40  * $DragonFly: src/sys/i386/isa/Attic/ipl.s,v 1.3 2003/06/22 08:54:22 dillon Exp $
41  */
42
43
44 /*
45  * AT/386
46  * Vector interrupt control section
47  *
48  *  *_imask     - Interrupt masks for various spl*() functions
49  *  ipending    - Pending interrupts (set when a masked interrupt occurs)
50  */
51
52         .data
53         ALIGN_DATA
54
55 /* current priority (all off) */
56
57         .globl  _tty_imask
58 _tty_imask:     .long   SWI_TTY_MASK
59         .globl  _bio_imask
60 _bio_imask:     .long   SWI_CLOCK_MASK | SWI_CAMBIO_MASK
61         .globl  _net_imask
62 _net_imask:     .long   SWI_NET_MASK | SWI_CAMNET_MASK
63         .globl  _cam_imask
64 _cam_imask:     .long   SWI_CAMBIO_MASK | SWI_CAMNET_MASK
65         .globl  _soft_imask
66 _soft_imask:    .long   SWI_MASK
67         .globl  _softnet_imask
68 _softnet_imask: .long   SWI_NET_MASK
69         .globl  _softtty_imask
70 _softtty_imask: .long   SWI_TTY_MASK
71
72 /* pending interrupts blocked by splxxx() */
73         .globl  _ipending
74 _ipending:      .long   0
75
76 /* set with bits for which queue to service */
77         .globl  _netisr
78 _netisr:        .long   0
79
80         .globl _netisrs
81 _netisrs:
82         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
83         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
84         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
85         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
86         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
87         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
88         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
89         .long   dummynetisr, dummynetisr, dummynetisr, dummynetisr
90
91         .text
92
93 /*
94  * Handle return from interrupts, traps and syscalls.
95  */
96         SUPERALIGN_TEXT
97         .type   _doreti,@function
98 _doreti:
99         FAKE_MCOUNT(_bintr)             /* init "from" _bintr -> _doreti */
100         addl    $4,%esp                 /* discard unit number */
101         popl    %eax                    /* cpl or cml to restore */
102         movl    _curthread,%ebx 
103 doreti_next:
104         /*
105          * Check for pending HWIs and SWIs atomically with restoring cpl
106          * and exiting.  The check has to be atomic with exiting to stop
107          * (ipending & ~cpl) changing from zero to nonzero while we're
108          * looking at it (this wouldn't be fatal but it would increase
109          * interrupt latency).  Restoring cpl has to be atomic with exiting
110          * so that the stack cannot pile up (the nesting level of interrupt
111          * handlers is limited by the number of bits in cpl).
112          */
113 #ifdef SMP
114         cli                             /* early to prevent INT deadlock */
115 doreti_next2:
116 #endif
117         movl    %eax,%ecx
118         notl    %ecx                    /* set bit = unmasked level */
119 #ifndef SMP
120         cli
121 #endif
122         andl    _ipending,%ecx          /* set bit = unmasked pending INT */
123         jne     doreti_unpend
124         movl    %eax,TD_MACH+MTD_CPL(%ebx)
125         decb    _intr_nesting_level
126
127         /* Check for ASTs that can be handled now. */
128         testl   $AST_PENDING,_astpending
129         je      doreti_exit
130         testl   $PSL_VM,TF_EFLAGS(%esp)
131         jz      doreti_notvm86
132         cmpl    $1,_in_vm86call
133         jne     doreti_ast
134         jmp     doreti_exit     
135
136 doreti_notvm86:
137         testb   $SEL_RPL_MASK,TF_CS(%esp)
138         jnz     doreti_ast
139
140         /*
141          * doreti_exit -        release MP lock, pop registers, iret.
142          *
143          *      Note that the syscall trap shotcuts to doreti_syscall_ret.
144          *      The segment register pop is a special case, since it may
145          *      fault if (for example) a sigreturn specifies bad segment
146          *      registers.  The fault is handled in trap.c
147          */
148
149 doreti_exit:
150         MEXITCOUNT
151
152 #ifdef SMP
153         /* release the kernel lock */
154         movl    $_mp_lock, %edx         /* GIANT_LOCK */
155         call    _MPrellock_edx
156 #endif /* SMP */
157
158         .globl  doreti_popl_fs
159         .globl  doreti_syscall_ret
160 doreti_syscall_ret:
161 doreti_popl_fs:
162         popl    %fs
163         .globl  doreti_popl_es
164 doreti_popl_es:
165         popl    %es
166         .globl  doreti_popl_ds
167 doreti_popl_ds:
168         popl    %ds
169         popal
170         addl    $8,%esp
171         .globl  doreti_iret
172 doreti_iret:
173         iret
174
175         ALIGN_TEXT
176         .globl  doreti_iret_fault
177 doreti_iret_fault:
178         subl    $8,%esp
179         pushal
180         pushl   %ds
181         .globl  doreti_popl_ds_fault
182 doreti_popl_ds_fault:
183         pushl   %es
184         .globl  doreti_popl_es_fault
185 doreti_popl_es_fault:
186         pushl   %fs
187         .globl  doreti_popl_fs_fault
188 doreti_popl_fs_fault:
189         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
190         movl    $T_PROTFLT,TF_TRAPNO(%esp)
191         jmp     alltraps_with_regs_pushed
192
193         ALIGN_TEXT
194 doreti_unpend:
195         /*
196          * Enabling interrupts is safe because we haven't restored cpl yet.
197          * %ecx contains the next probable ready interrupt (~cpl & ipending)
198          */
199 #ifdef SMP
200         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
201         lock
202         btrl    %ecx, _ipending         /* is it really still pending? */
203         jnc     doreti_next2            /* some intr cleared memory copy */
204         sti                             /* late to prevent INT deadlock */
205 #else
206         sti
207         bsfl    %ecx,%ecx               /* slow, but not worth optimizing */
208         btrl    %ecx,_ipending
209         jnc     doreti_next             /* some intr cleared memory copy */
210 #endif /* SMP */
211         /*
212          * Execute handleable interrupt
213          *
214          * Set up JUMP to _ihandlers[%ecx] for HWIs.
215          * Set up CALL of _ihandlers[%ecx] for SWIs.
216          * This is a bit early for the SMP case - we have to push %ecx and
217          * %edx, but could push only %ecx and load %edx later.
218          */
219         movl    _ihandlers(,%ecx,4),%edx
220         cmpl    $NHWI,%ecx
221         jae     doreti_swi              /* software interrupt handling */
222         cli                             /* else hardware int handling */
223         movl    %eax,TD_MACH+MTD_CPL(%ebx) /* same as non-smp case right now */
224         MEXITCOUNT
225 #ifdef APIC_INTR_DIAGNOSTIC
226         lock
227         incl    CNAME(apic_itrace_doreti)(,%ecx,4)
228 #ifdef APIC_INTR_DIAGNOSTIC_IRQ 
229         cmpl    $APIC_INTR_DIAGNOSTIC_IRQ,%ecx
230         jne     9f
231         pushl   %eax
232         pushl   %ecx
233         pushl   %edx
234         pushl   $APIC_ITRACE_DORETI
235         call    log_intr_event
236         addl    $4,%esp
237         popl    %edx
238         popl    %ecx
239         popl    %eax
240 9:      
241 #endif
242 #endif
243         jmp     *%edx
244
245         ALIGN_TEXT
246 doreti_swi:
247         pushl   %eax
248         /*
249          * At least the SWI_CLOCK handler has to run at a possibly strictly
250          * lower cpl, so we have to restore
251          * all the h/w bits in cpl now and have to worry about stack growth.
252          * The worst case is currently (30 Jan 1994) 2 SWI handlers nested
253          * in dying interrupt frames and about 12 HWIs nested in active
254          * interrupt frames.  There are only 4 different SWIs and the HWI
255          * and SWI masks limit the nesting further.
256          *
257          * The SMP case is currently the same as the non-SMP case.
258          */
259         orl     imasks(,%ecx,4), %eax   /* or in imasks */
260         movl    %eax,TD_MACH+MTD_CPL(%ebx)      /* set cpl for call */
261
262         call    *%edx
263         popl    %eax                    /* cpl to restore */
264         jmp     doreti_next
265
266         ALIGN_TEXT
267 doreti_ast:
268         andl    $~AST_PENDING,_astpending
269         sti
270         movl    $T_ASTFLT,TF_TRAPNO(%esp)
271         call    _trap
272         subl    %eax,%eax               /* recover cpl|cml */
273         movb    $1,_intr_nesting_level  /* for doreti_next to decrement */
274         jmp     doreti_next
275
276         ALIGN_TEXT
277 swi_net:
278         MCOUNT
279         bsfl    _netisr,%eax
280         je      swi_net_done
281 swi_net_more:
282         btrl    %eax,_netisr
283         jnc     swi_net_next
284         call    *_netisrs(,%eax,4)
285 swi_net_next:
286         bsfl    _netisr,%eax
287         jne     swi_net_more
288 swi_net_done:
289         ret
290
291         ALIGN_TEXT
292 dummynetisr:
293         MCOUNT
294         ret     
295
296 /*
297  * The arg is in a nonstandard place, so swi_dispatcher() can't be called
298  * directly and swi_generic() can't use ENTRY() or MCOUNT.
299  */
300         ALIGN_TEXT
301         .globl  _swi_generic
302         .type   _swi_generic,@function
303 _swi_generic:
304         pushl   %ecx
305         FAKE_MCOUNT(4(%esp))
306         call    _swi_dispatcher
307         popl    %ecx
308         ret
309
310 ENTRY(swi_null)
311         ret
312
313 #ifdef APIC_IO
314 #include "i386/isa/apic_ipl.s"
315 #else
316 #include "i386/isa/icu_ipl.s"
317 #endif /* APIC_IO */