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