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