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