851c15f67357a9fafad67962aa9776ac6e7318aa
[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.17 2004/03/30 19:14:08 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         .text
73         /*
74          * GENERAL NOTES
75          *
76          *      - fast interrupts are always called with a critical section
77          *        held
78          *
79          *      - we release our critical section when scheduling interrupt
80          *        or softinterrupt threads in order so they can preempt
81          *        (unless we are called manually from a critical section, in
82          *        which case there will still be a critical section and
83          *        they won't preempt anyway).
84          *
85          *      - TD_NEST_COUNT prevents splz from nesting too deeply within
86          *        itself.  It is *not* actually an interrupt nesting count.
87          *        PCPU(intr_nesting_level) is an interrupt nesting count.
88          *
89          *      - We have to be careful in regards to local interrupts
90          *        occuring simultaniously with our doreti and splz 
91          *        processing.
92          */
93
94         /*
95          * DORETI
96          *
97          * Handle return from interrupts, traps and syscalls.  This function
98          * checks the cpl for unmasked pending interrupts (fast, normal, or
99          * soft) and schedules them if appropriate, then irets.
100          *
101          * If we are in a critical section we cannot run any pending ints
102          * nor can be play with mp_lock.
103          *
104          */
105         SUPERALIGN_TEXT
106         .type   doreti,@function
107 doreti:
108         FAKE_MCOUNT(bintr)              /* init "from" bintr -> doreti */
109         popl    %eax                    /* cpl to restore */
110         movl    PCPU(curthread),%ebx
111         cli                             /* interlock with TDPRI_CRIT */
112         cmpl    $0,PCPU(reqflags)       /* short cut if nothing to do */
113         je      5f
114         movl    %eax,TD_CPL(%ebx)       /* save cpl being restored */
115         cmpl    $TDPRI_CRIT,TD_PRI(%ebx) /* can't unpend if in critical sec */
116         jge     5f
117         addl    $TDPRI_CRIT,TD_PRI(%ebx) /* force all ints to pending */
118 doreti_next:
119         sti                             /* allow new interrupts */
120         movl    %eax,%ecx               /* cpl being restored */
121         notl    %ecx
122         cli                             /* disallow YYY remove */
123 #ifdef SMP
124         testl   $RQF_IPIQ,PCPU(reqflags)
125         jnz     doreti_ipiq
126 #endif
127         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
128         jnz     doreti_fast
129
130         testl   PCPU(ipending),%ecx
131         jnz     doreti_intr
132
133         testl   $RQF_AST_MASK,PCPU(reqflags) /* any pending ASTs? */
134         jz      2f
135         testl   $PSL_VM,TF_EFLAGS(%esp)
136         jz      1f
137         cmpl    $1,in_vm86call          /* YYY make per 'cpu'? */
138         jnz     doreti_ast
139 1:
140         /* ASTs are only applicable when returning to userland */
141         testb   $SEL_RPL_MASK,TF_CS(%esp)
142         jnz     doreti_ast
143 2:
144         /*
145          * Nothing left to do, finish up.  Interrupts are still disabled.
146          * If our temporary cpl mask is 0 then we have processed all pending
147          * fast and normal ints including those requiring the MP lock,
148          * and we have processed as many of the reqflags as possible based
149          * on whether we came from user mode or not.   So if %eax is 0 we
150          * can clear the interrupt-related reqflags.
151          */
152         subl    $TDPRI_CRIT,TD_PRI(%ebx)        /* interlocked with cli */
153         testl   %eax,%eax
154         jnz     5f
155         andl    $~RQF_INTPEND,PCPU(reqflags)
156 5:
157         MEXITCOUNT
158         .globl  doreti_popl_fs
159         .globl  doreti_popl_es
160         .globl  doreti_popl_ds
161         .globl  doreti_iret
162         .globl  doreti_syscall_ret
163 doreti_syscall_ret:
164 doreti_popl_fs:
165         popl    %fs
166 doreti_popl_es:
167         popl    %es
168 doreti_popl_ds:
169         popl    %ds
170         popal
171         addl    $8,%esp
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         /*
194          * FAST interrupt pending
195          */
196         ALIGN_TEXT
197 doreti_fast:
198         andl    PCPU(fpending),%ecx     /* only check fast ints */
199         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
200         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
201         jnc     doreti_next
202         pushl   %eax                    /* YYY cpl (expected by frame) */
203 #ifdef SMP
204         pushl   %ecx                    /* save ecx */
205         call    try_mplock
206         popl    %ecx
207         testl   %eax,%eax
208         jz      1f
209         /* MP lock successful */
210 #endif
211         incl    PCPU(intr_nesting_level)
212         call    *fastunpend(,%ecx,4)
213         decl    PCPU(intr_nesting_level)
214 #ifdef SMP
215         call    rel_mplock
216 #endif
217         popl    %eax
218         jmp     doreti_next
219 1:
220         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
221         popl    %eax                    /* add to temp. cpl mask to ignore */
222         orl     PCPU(fpending),%eax
223         jmp     doreti_next
224
225         /*
226          *  INTR interrupt pending
227          *
228          *  Temporarily back-out our critical section to allow an interrupt
229          *  preempt us when we schedule it.  Bump intr_nesting_level to
230          *  prevent the switch code from recursing via splz too deeply.
231          */
232         ALIGN_TEXT
233 doreti_intr:
234         andl    PCPU(ipending),%ecx     /* only check normal ints */
235         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
236         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
237         jnc     doreti_next
238         pushl   %eax
239         pushl   %ecx
240         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
241         subl    $TDPRI_CRIT,TD_PRI(%ebx) /* so we can preempt */
242         call    sched_ithd              /* YYY must pull in imasks */
243         addl    $TDPRI_CRIT,TD_PRI(%ebx)
244         decl    TD_NEST_COUNT(%ebx)
245         addl    $4,%esp
246         popl    %eax
247         jmp     doreti_next
248
249         /*
250          * AST pending.  We clear RQF_AST_SIGNAL automatically, the others
251          * are cleared by the trap as they are processed.
252          *
253          * Temporarily back-out our critical section because trap() can be
254          * a long-winded call, and we want to be more syscall-like.  
255          *
256          * YYY theoretically we can call lwkt_switch directly if all we need
257          * to do is a reschedule.
258          */
259 doreti_ast:
260         andl    $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags)
261         sti
262         movl    %eax,%esi               /* save cpl (can't use stack) */
263         movl    $T_ASTFLT,TF_TRAPNO(%esp)
264         subl    $TDPRI_CRIT,TD_PRI(%ebx)
265 1:      call    trap
266         addl    $TDPRI_CRIT,TD_PRI(%ebx)
267         movl    %esi,%eax               /* restore cpl for loop */
268         jmp     doreti_next
269
270 #ifdef SMP
271         /*
272          * IPIQ message pending.  We clear RQF_IPIQ automatically.
273          */
274 doreti_ipiq:
275         incl    PCPU(intr_nesting_level)
276         andl    $~RQF_IPIQ,PCPU(reqflags)
277         subl    $8,%esp                 /* add dummy vec and ppl */
278         call    lwkt_process_ipiq_frame
279         addl    $8,%esp
280         decl    PCPU(intr_nesting_level)
281         movl    TD_CPL(%ebx),%eax       /* retrieve cpl again for loop */
282         jmp     doreti_next
283
284 #endif
285
286         /*
287          * SPLZ() a C callable procedure to dispatch any unmasked pending
288          *        interrupts regardless of critical section nesting.  ASTs
289          *        are not dispatched.
290          *
291          *      YYY at the moment I leave us in a critical section so as
292          *      not to have to mess with the cpls which will soon be obsolete.
293          */
294         SUPERALIGN_TEXT
295
296 ENTRY(splz)
297         pushfl
298         pushl   %ebx
299         movl    PCPU(curthread),%ebx
300         movl    TD_CPL(%ebx),%eax
301         addl    $TDPRI_CRIT,TD_PRI(%ebx)
302
303 splz_next:
304         cli
305         movl    %eax,%ecx               /* ecx = ~CPL */
306         notl    %ecx
307 #ifdef SMP
308         testl   $RQF_IPIQ,PCPU(reqflags)
309         jnz     splz_ipiq
310 #endif
311         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
312         jnz     splz_fast
313
314         testl   PCPU(ipending),%ecx
315         jnz     splz_intr
316
317         subl    $TDPRI_CRIT,TD_PRI(%ebx)
318
319         /*
320          * Nothing left to do, finish up.  Interrupts are still disabled.
321          * If our temporary cpl mask is 0 then we have processed everything
322          * (including any pending fast ints requiring the MP lock), and
323          * we can clear RQF_INTPEND.
324          */
325         testl   %eax,%eax
326         jnz     5f
327         andl    $~RQF_INTPEND,PCPU(reqflags)
328 5:
329         popl    %ebx
330         popfl
331         ret
332
333         /*
334          * FAST interrupt pending
335          */
336         ALIGN_TEXT
337 splz_fast:
338         andl    PCPU(fpending),%ecx     /* only check fast ints */
339         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
340         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
341         jnc     splz_next
342         pushl   %eax
343 #ifdef SMP
344         pushl   %ecx
345         call    try_mplock
346         popl    %ecx
347         testl   %eax,%eax
348         jz      1f
349 #endif
350         incl    PCPU(intr_nesting_level)
351         call    *fastunpend(,%ecx,4)
352         decl    PCPU(intr_nesting_level)
353 #ifdef SMP
354         call    rel_mplock
355 #endif
356         popl    %eax
357         jmp     splz_next
358 1:
359         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
360         popl    %eax
361         orl     PCPU(fpending),%eax
362         jmp     splz_next
363
364         /*
365          *  INTR interrupt pending
366          *
367          *  Temporarily back-out our critical section to allow the interrupt
368          *  preempt us.
369          */
370         ALIGN_TEXT
371 splz_intr:
372         andl    PCPU(ipending),%ecx     /* only check normal ints */
373         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
374         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
375         jnc     splz_next
376         sti
377         pushl   %eax
378         pushl   %ecx
379         subl    $TDPRI_CRIT,TD_PRI(%ebx)
380         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
381         call    sched_ithd              /* YYY must pull in imasks */
382         addl    $TDPRI_CRIT,TD_PRI(%ebx)
383         decl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
384         addl    $4,%esp
385         popl    %eax
386         jmp     splz_next
387
388 #ifdef SMP
389 splz_ipiq:
390         andl    $~RQF_IPIQ,PCPU(reqflags)
391         pushl   %eax
392         call    lwkt_process_ipiq
393         popl    %eax
394         jmp     splz_next
395 #endif
396
397         /*
398          * APIC/ICU specific ipl functions provide masking and unmasking
399          * calls for userland.
400          */
401
402 #ifdef APIC_IO
403 #include "i386/isa/apic_ipl.s"
404 #else
405 #include "i386/isa/icu_ipl.s"
406 #endif /* APIC_IO */