2feb2376e49cee630673bff720087dd24ef97614
[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  */
41
42 #include <machine/asmacros.h>
43 #include <machine/segments.h>
44 #include <machine/ipl.h>
45 #include <machine/lock.h>
46 #include <machine/psl.h>
47 #include <machine/trap.h>
48  
49 #include "assym.s"
50
51 /*
52  * AT/386
53  * Vector interrupt control section
54  *
55  *  fpending    - Pending interrupts (set when a masked interrupt occurs)
56  *  spending    - Pending software interrupts
57  */
58         .data
59         ALIGN_DATA
60
61         .globl          fastunpend_count
62 fastunpend_count:       .long   0
63
64         .text
65         SUPERALIGN_TEXT
66
67         /*
68          * GENERAL NOTES
69          *
70          *      - fast interrupts are always called with a critical section
71          *        held
72          *
73          *      - we release our critical section when scheduling interrupt
74          *        or softinterrupt threads in order so they can preempt
75          *        (unless we are called manually from a critical section, in
76          *        which case there will still be a critical section and
77          *        they won't preempt anyway).
78          *
79          *      - TD_NEST_COUNT prevents splz from nesting too deeply within
80          *        itself.  It is *not* actually an interrupt nesting count.
81          *        PCPU(intr_nesting_level) is an interrupt nesting count.
82          *
83          *      - We have to be careful in regards to local interrupts
84          *        occuring simultaniously with our doreti and splz 
85          *        processing.
86          */
87
88         /*
89          * DORETI
90          *
91          * Handle return from interrupts, traps and syscalls.  This function
92          * checks the cpl for unmasked pending interrupts (fast, normal, or
93          * soft) and schedules them if appropriate, then irets.
94          *
95          * If we are in a critical section we cannot run any pending ints
96          * nor can be play with mp_lock.
97          *
98          * NOTE: Since SPLs no longer exist, all callers of this function
99          * push $0 for the CPL.  HOWEVER, we *STILL* use the cpl mask within
100          * this function to mark fast interrupts which could not be dispatched
101          * do to the unavailability of the BGL.
102          */
103         SUPERALIGN_TEXT
104         .globl  doreti
105         .type   doreti,@function
106 doreti:
107         FAKE_MCOUNT(bintr)              /* init "from" bintr -> doreti */
108         popl    %eax                    /* cpl to restore XXX */
109         movl    $0,%eax                 /* irq mask unavailable due to BGL */
110         movl    PCPU(curthread),%ebx
111         cli                             /* interlock with td_critcount */
112         cmpl    $0,PCPU(reqflags)       /* short cut if nothing to do */
113         je      5f
114         testl   $-1,TD_CRITCOUNT(%ebx)  /* can't unpend if in critical sec */
115         jne     5f
116         incl    TD_CRITCOUNT(%ebx)      /* force all ints to pending */
117 doreti_next:
118         cli                             /* re-assert cli on loop */
119         movl    %eax,%ecx               /* irq mask unavailable due to BGL */
120         notl    %ecx
121 #ifdef SMP
122         testl   $RQF_IPIQ,PCPU(reqflags)
123         jnz     doreti_ipiq
124         testl   $RQF_TIMER,PCPU(reqflags)
125         jnz     doreti_timer
126 #endif
127         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
128         jnz     doreti_fast
129
130         movl    PCPU(spending),%ecx     /* check for a pending software int */
131         cmpl    $0,%ecx
132         jnz     doreti_soft
133
134         testl   $RQF_AST_MASK,PCPU(reqflags) /* any pending ASTs? */
135         jz      2f
136         testl   $PSL_VM,TF_EFLAGS(%esp)
137         jz      1f
138         cmpl    $1,in_vm86call          /* YYY make per 'cpu'? */
139         jnz     doreti_ast
140 1:
141         /* ASTs are only applicable when returning to userland */
142         testb   $SEL_RPL_MASK,TF_CS(%esp)
143         jnz     doreti_ast
144 2:
145         /*
146          * Nothing left to do, finish up.  Interrupts are still disabled.
147          * %eax contains the mask of IRQ's that are not available due to
148          * BGL requirements.  We can only clear RQF_INTPEND if *ALL* pending
149          * interrupts have been processed.
150          */
151         decl    TD_CRITCOUNT(%ebx)      /* interlocked with cli */
152         testl   %eax,%eax
153         jnz     5f
154         andl    $~RQF_INTPEND,PCPU(reqflags)
155 5:
156         MEXITCOUNT
157
158         /*
159          * Restore the segment registers.  Since segment register values
160          * can be set from user mode, this can result in a kernel mode
161          * exception.  The trap code will revector to the *_fault code
162          * which then sets up a T_PROTFLT signal.  If the signal is
163          * sent to userland, sendsig() will automatically clean up all
164          * the segment registers to avoid a loop.
165          */
166         .globl  doreti_popl_gs
167         .globl  doreti_popl_fs
168         .globl  doreti_popl_es
169         .globl  doreti_popl_ds
170         .globl  doreti_iret
171         .globl  doreti_syscall_ret
172 doreti_syscall_ret:
173 doreti_popl_gs:
174         popl    %gs
175 doreti_popl_fs:
176         popl    %fs
177 doreti_popl_es:
178         popl    %es
179 doreti_popl_ds:
180         popl    %ds
181         popal
182         addl    $3*4,%esp       /* xflags, trap, err */
183 doreti_iret:
184         iret
185
186         /*
187          * Interrupts are likely disabled due to the above interlock
188          * between cli/iretq.  We must enable them before calling any
189          * high level function.
190          */
191         ALIGN_TEXT
192         .globl  doreti_iret_fault
193 doreti_iret_fault:
194         subl    $3*4,%esp       /* xflags, trap, err */
195         pushal
196         pushl   %ds
197         .globl  doreti_popl_ds_fault
198 doreti_popl_ds_fault:
199         pushl   %es
200         .globl  doreti_popl_es_fault
201 doreti_popl_es_fault:
202         pushl   %fs
203         .globl  doreti_popl_fs_fault
204 doreti_popl_fs_fault:
205         pushl   %gs
206         .globl  doreti_popl_gs_fault
207 doreti_popl_gs_fault:
208         sti
209         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
210         movl    $T_PROTFLT,TF_TRAPNO(%esp)
211         jmp     alltraps_with_regs_pushed
212
213         /*
214          * FAST interrupt pending.  NOTE: stack context holds frame structure
215          * for fast interrupt procedure, do not do random pushes or pops!
216          */
217         ALIGN_TEXT
218 doreti_fast:
219         andl    PCPU(fpending),%ecx     /* only check fast ints */
220         sti
221         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
222         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
223         jnc     doreti_next
224         pushl   %eax                    /* save IRQ mask unavailable for BGL */
225                                         /* NOTE: is also CPL in frame */
226         call    dofastunpend            /* unpend fast intr %ecx */
227         popl    %eax
228         jmp     doreti_next
229
230         /*
231          *  SOFT interrupt pending
232          *
233          *  Temporarily back-out our critical section to allow an interrupt
234          *  preempt us when we schedule it.  Bump intr_nesting_level to
235          *  prevent the switch code from recursing via splz too deeply.
236          */
237         ALIGN_TEXT
238 doreti_soft:
239         sti
240         bsfl    %ecx,%ecx               /* locate the next pending softint */
241         btrl    %ecx,PCPU(spending)     /* make sure its still pending */
242         jnc     doreti_next
243         addl    $FIRST_SOFTINT,%ecx     /* actual intr number */
244         pushl   %eax
245         pushl   %ecx
246         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
247         decl    TD_CRITCOUNT(%ebx)      /* so we can preempt */
248         call    sched_ithd              /* YYY must pull in imasks */
249         incl    TD_CRITCOUNT(%ebx)
250         decl    TD_NEST_COUNT(%ebx)
251         addl    $4,%esp
252         popl    %eax
253         jmp     doreti_next
254
255         /*
256          * AST pending.  We clear RQF_AST_SIGNAL automatically, the others
257          * are cleared by the trap as they are processed.
258          *
259          * Temporarily back-out our critical section because trap() can be
260          * a long-winded call, and we want to be more syscall-like.  
261          *
262          * YYY theoretically we can call lwkt_switch directly if all we need
263          * to do is a reschedule.
264          */
265 doreti_ast:
266         andl    $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags)
267         sti
268         movl    %eax,%esi               /* save cpl (can't use stack) */
269         movl    $T_ASTFLT,TF_TRAPNO(%esp)
270         pushl   %esp                    /* pass frame by reference */
271         decl    TD_CRITCOUNT(%ebx)
272         call    trap
273         incl    TD_CRITCOUNT(%ebx)
274         addl    $4,%esp
275         movl    %esi,%eax               /* restore cpl for loop */
276         jmp     doreti_next
277
278 #ifdef SMP
279         /*
280          * IPIQ message pending.  We clear RQF_IPIQ automatically.
281          */
282 doreti_ipiq:
283         movl    %eax,%esi               /* save cpl (can't use stack) */
284         incl    PCPU(intr_nesting_level)
285         andl    $~RQF_IPIQ,PCPU(reqflags)
286         sti
287         subl    $8,%esp                 /* add dummy vec and ppl */
288         pushl   %esp                    /* pass frame by reference */
289         call    lwkt_process_ipiq_frame
290         addl    $12,%esp
291         decl    PCPU(intr_nesting_level)
292         movl    %esi,%eax               /* restore cpl for loop */
293         jmp     doreti_next
294
295 doreti_timer:
296         movl    %eax,%esi               /* save cpl (can't use stack) */
297         incl    PCPU(intr_nesting_level)
298         andl    $~RQF_TIMER,PCPU(reqflags)
299         sti
300         subl    $8,%esp                 /* add dummy vec and ppl */
301         pushl   %esp                    /* pass frame by reference */
302         call    lapic_timer_process_frame
303         addl    $12,%esp
304         decl    PCPU(intr_nesting_level)
305         movl    %esi,%eax               /* restore cpl for loop */
306         jmp     doreti_next
307
308 #endif
309
310         /*
311          * SPLZ() a C callable procedure to dispatch any unmasked pending
312          *        interrupts regardless of critical section nesting.  ASTs
313          *        are not dispatched.
314          *
315          *        Use %eax to track those IRQs that could not be processed
316          *        due to BGL requirements.
317          */
318         SUPERALIGN_TEXT
319
320 ENTRY(splz)
321         pushfl
322         pushl   %ebx
323         movl    PCPU(curthread),%ebx
324         incl    TD_CRITCOUNT(%ebx)
325         movl    $0,%eax
326
327 splz_next:
328         cli
329         movl    %eax,%ecx               /* ecx = ~CPL */
330         notl    %ecx
331 #ifdef SMP
332         testl   $RQF_IPIQ,PCPU(reqflags)
333         jnz     splz_ipiq
334         testl   $RQF_TIMER,PCPU(reqflags)
335         jnz     splz_timer
336 #endif
337         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
338         jnz     splz_fast
339
340         movl    PCPU(spending),%ecx
341         cmpl    $0,%ecx
342         jnz     splz_soft
343
344         decl    TD_CRITCOUNT(%ebx)
345
346         /*
347          * Nothing left to do, finish up.  Interrupts are still disabled.
348          * If our mask of IRQs we couldn't process due to BGL requirements
349          * is 0 then there are no pending interrupt sources left and we
350          * can clear RQF_INTPEND.
351          */
352         testl   %eax,%eax
353         jnz     5f
354         andl    $~RQF_INTPEND,PCPU(reqflags)
355 5:
356         popl    %ebx
357         popfl
358         ret
359
360         /*
361          * FAST interrupt pending
362          */
363         ALIGN_TEXT
364 splz_fast:
365         andl    PCPU(fpending),%ecx     /* only check fast ints */
366         sti
367         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
368         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
369         jnc     splz_next
370         pushl   %eax
371         call    dofastunpend            /* unpend fast intr %ecx */
372         popl    %eax
373         jmp     splz_next
374
375         /*
376          *  SOFT interrupt pending
377          *
378          *  Temporarily back-out our critical section to allow the interrupt
379          *  preempt us.
380          */
381         ALIGN_TEXT
382 splz_soft:
383         sti
384         bsfl    %ecx,%ecx               /* locate the next pending softint */
385         btrl    %ecx,PCPU(spending)     /* make sure its still pending */
386         jnc     splz_next
387         addl    $FIRST_SOFTINT,%ecx     /* actual intr number */
388         pushl   %eax
389         pushl   %ecx
390         decl    TD_CRITCOUNT(%ebx)
391         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
392         call    sched_ithd              /* YYY must pull in imasks */
393         incl    TD_CRITCOUNT(%ebx)
394         decl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
395         addl    $4,%esp
396         popl    %eax
397         jmp     splz_next
398
399 #ifdef SMP
400 splz_ipiq:
401         andl    $~RQF_IPIQ,PCPU(reqflags)
402         sti
403         pushl   %eax
404         call    lwkt_process_ipiq
405         popl    %eax
406         jmp     splz_next
407
408 splz_timer:
409         andl    $~RQF_TIMER,PCPU(reqflags)
410         sti
411         pushl   %eax
412         call    lapic_timer_process
413         popl    %eax
414         jmp     splz_next
415 #endif
416
417         /*
418          * dofastunpend(%ecx:intr)
419          *
420          * A FAST interrupt previously made pending can now be run,
421          * execute it by pushing a dummy interrupt frame and 
422          * calling ithread_fast_handler to execute or schedule it.
423          * 
424          * ithread_fast_handler() returns 0 if it wants us to unmask
425          * further interrupts.
426          */
427 #define PUSH_DUMMY                                                      \
428         pushfl ;                /* phys int frame / flags */            \
429         pushl   %cs ;           /* phys int frame / cs */               \
430         pushl   12(%esp) ;      /* original caller eip */               \
431         pushl   $0 ;            /* dummy error code */                  \
432         pushl   $0 ;            /* dummy trap type */                   \
433         pushl   $0 ;            /* dummy xflags */                      \
434         subl    $13*4,%esp ;    /* pushal + 4 seg regs (dummy) + CPL */ \
435
436 #define POP_DUMMY                                                       \
437         addl    $19*4,%esp ;                                            \
438
439 dofastunpend:
440         pushl   %ebp                    /* frame for backtrace */
441         movl    %esp,%ebp
442         PUSH_DUMMY
443         pushl   %ecx                    /* last part of intrframe = intr */
444         incl    fastunpend_count
445         pushl   %esp                    /* pass frame by reference */
446         call    ithread_fast_handler    /* returns 0 to unmask */
447         addl    $4,%esp                 /* remove pointer, now intr on top */
448         cmpl    $0,%eax
449         jnz     1f
450         movl    MachIntrABI + MACHINTR_INTREN, %eax
451         call    *%eax                   /* MachIntrABI.intren(intr) */
452 1:
453         addl    $4,%esp
454         POP_DUMMY
455         popl    %ebp
456         ret
457