07c42a81daff017c802630f345a01a8153b1f230
[dragonfly.git] / sys / platform / pc32 / apic / apic_vector.s
1 /*
2  *      from: vector.s, 386BSD 0.1 unknown origin
3  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
4  */
5
6 #include "opt_auto_eoi.h"
7
8 #include <machine/asmacros.h>
9 #include <machine/lock.h>
10 #include <machine/psl.h>
11 #include <machine/trap.h>
12
13 #include <machine_base/icu/icu.h>
14 #include <bus/isa/isa.h>
15
16 #include "assym.s"
17
18 #include "apicreg.h"
19 #include <machine_base/apic/ioapic_ipl.h>
20 #include <machine/intr_machdep.h>
21
22 /* convert an absolute IRQ# into bitmask */
23 #define IRQ_LBIT(irq_num)       (1 << ((irq_num) & 0x1f))
24
25 /* convert an absolute IRQ# into ipending index */
26 #define IRQ_LIDX(irq_num)       ((irq_num) >> 5)
27
28 #ifdef SMP
29 #define MPLOCKED     lock ;
30 #else
31 #define MPLOCKED
32 #endif
33
34 /*
35  * Push an interrupt frame in a format acceptable to doreti, reload
36  * the segment registers for the kernel.
37  */
38 #define PUSH_FRAME                                                      \
39         pushl   $0 ;            /* dummy error code */                  \
40         pushl   $0 ;            /* dummy trap type */                   \
41         pushl   $0 ;            /* dummy xflags type */                 \
42         pushal ;                                                        \
43         pushl   %ds ;           /* save data and extra segments ... */  \
44         pushl   %es ;                                                   \
45         pushl   %fs ;                                                   \
46         pushl   %gs ;                                                   \
47         cld ;                                                           \
48         mov     $KDSEL,%ax ;                                            \
49         mov     %ax,%ds ;                                               \
50         mov     %ax,%es ;                                               \
51         mov     %ax,%gs ;                                               \
52         mov     $KPSEL,%ax ;                                            \
53         mov     %ax,%fs ;                                               \
54
55 /*
56  * Warning: POP_FRAME can only be used if there is no chance of a
57  * segment register being changed (e.g. by procfs), which is why syscalls
58  * have to use doreti.
59  */
60 #define POP_FRAME                                                       \
61         popl    %gs ;                                                   \
62         popl    %fs ;                                                   \
63         popl    %es ;                                                   \
64         popl    %ds ;                                                   \
65         popal ;                                                         \
66         addl    $3*4,%esp ;     /* dummy xflags, trap & error codes */  \
67
68 #define IOAPICADDR(irq_num) \
69         CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_ADDR
70 #define REDIRIDX(irq_num) \
71         CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_ENTIDX
72 #define IOAPICFLAGS(irq_num) \
73         CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_FLAGS
74
75 #define MASK_IRQ(irq_num)                                               \
76         IOAPIC_IMASK_LOCK ;                     /* into critical reg */ \
77         testl   $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ;          \
78         jne     7f ;                    /* masked, don't mask */        \
79         orl     $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ;          \
80                                                 /* set the mask bit */  \
81         movl    IOAPICADDR(irq_num), %ecx ;     /* ioapic addr */       \
82         movl    REDIRIDX(irq_num), %eax ;       /* get the index */     \
83         movl    %eax, (%ecx) ;                  /* write the index */   \
84         orl     $IOART_INTMASK,IOAPIC_WINDOW(%ecx) ;/* set the mask */  \
85 7: ;                                            /* already masked */    \
86         IOAPIC_IMASK_UNLOCK ;                                           \
87
88 /*
89  * Test to see whether we are handling an edge or level triggered INT.
90  *  Level-triggered INTs must still be masked as we don't clear the source,
91  *  and the EOI cycle would cause redundant INTs to occur.
92  */
93 #define MASK_LEVEL_IRQ(irq_num)                                         \
94         testl   $IOAPIC_IM_FLAG_LEVEL, IOAPICFLAGS(irq_num) ;           \
95         jz      9f ;                            /* edge, don't mask */  \
96         MASK_IRQ(irq_num) ;                                             \
97 9: ;                                                                    \
98
99 /*
100  * Test to see if the source is currntly masked, clear if so.
101  */
102 #define UNMASK_IRQ(irq_num)                                             \
103         cmpl    $0,%eax ;                                               \
104         jnz     8f ;                                                    \
105         IOAPIC_IMASK_LOCK ;                     /* into critical reg */ \
106         testl   $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ;          \
107         je      7f ;                    /* bit clear, not masked */     \
108         andl    $~IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ;         \
109                                                 /* clear mask bit */    \
110         movl    IOAPICADDR(irq_num),%ecx ;      /* ioapic addr */       \
111         movl    REDIRIDX(irq_num), %eax ;       /* get the index */     \
112         movl    %eax,(%ecx) ;                   /* write the index */   \
113         andl    $~IOART_INTMASK,IOAPIC_WINDOW(%ecx) ;/* clear the mask */ \
114 7: ;                                                                    \
115         IOAPIC_IMASK_UNLOCK ;                                           \
116 8: ;                                                                    \
117
118 /*
119  * Interrupt call handlers run in the following sequence:
120  *
121  *      - Push the trap frame required by doreti
122  *      - Mask the interrupt and reenable its source
123  *      - If we cannot take the interrupt set its ipending bit and
124  *        doreti.
125  *      - If we can take the interrupt clear its ipending bit,
126  *        call the handler, then unmask and doreti.
127  *
128  * YYY can cache gd base opitner instead of using hidden %fs prefixes.
129  */
130
131 #define INTR_HANDLER(irq_num)                                           \
132         .text ;                                                         \
133         SUPERALIGN_TEXT ;                                               \
134 IDTVEC(ioapic_intr##irq_num) ;                                          \
135         PUSH_FRAME ;                                                    \
136         FAKE_MCOUNT(15*4(%esp)) ;                                       \
137         MASK_LEVEL_IRQ(irq_num) ;                                       \
138         movl    lapic,%eax ;                                            \
139         movl    $0,LA_EOI(%eax) ;                                       \
140         movl    PCPU(curthread),%ebx ;                                  \
141         movl    $0,%eax ;       /* CURRENT CPL IN FRAME (REMOVED) */    \
142         pushl   %eax ;                                                  \
143         testl   $-1,TD_NEST_COUNT(%ebx) ;                               \
144         jne     1f ;                                                    \
145         testl   $-1,TD_CRITCOUNT(%ebx) ;                                \
146         je      2f ;                                                    \
147 1: ;                                                                    \
148         /* in critical section, make interrupt pending */               \
149         /* set the pending bit and return, leave interrupt masked */    \
150         movl    $IRQ_LIDX(irq_num),%edx ;                               \
151         orl     $IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ;             \
152         orl     $RQF_INTPEND,PCPU(reqflags) ;                           \
153         jmp     5f ;                                                    \
154 2: ;                                                                    \
155         /* clear pending bit, run handler */                            \
156         movl    $IRQ_LIDX(irq_num),%edx ;                               \
157         andl    $~IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ;            \
158         pushl   $irq_num ;                                              \
159         pushl   %esp ;                   /* pass frame by reference */  \
160         incl    TD_CRITCOUNT(%ebx) ;                                    \
161         sti ;                                                           \
162         call    ithread_fast_handler ;   /* returns 0 to unmask */      \
163         decl    TD_CRITCOUNT(%ebx) ;                                    \
164         addl    $8, %esp ;                                              \
165         UNMASK_IRQ(irq_num) ;                                           \
166 5: ;                                                                    \
167         MEXITCOUNT ;                                                    \
168         jmp     doreti ;                                                \
169
170 /*
171  * Handle "spurious INTerrupts".
172  * Notes:
173  *  This is different than the "spurious INTerrupt" generated by an
174  *   8259 PIC for missing INTs.  See the APIC documentation for details.
175  *  This routine should NOT do an 'EOI' cycle.
176  */
177         .text
178         SUPERALIGN_TEXT
179         .globl Xspuriousint
180 Xspuriousint:
181
182         /* No EOI cycle used here */
183
184         iret
185
186
187 /*
188  * Handle TLB shootdowns.
189  *
190  * NOTE: Interrupts remain disabled.
191  */
192         .text
193         SUPERALIGN_TEXT
194         .globl  Xinvltlb
195 Xinvltlb:
196         PUSH_FRAME
197         movl    lapic,%eax
198         movl    $0,LA_EOI(%eax)         /* End Of Interrupt to APIC */
199         FAKE_MCOUNT(15*4(%esp))
200
201         subl    $8,%esp                 /* make same as interrupt frame */
202         pushl   %esp                    /* pass frame by reference */
203         call    smp_invltlb_intr
204         addl    $12,%esp
205
206         MEXITCOUNT
207         jmp     doreti_syscall_ret
208
209 /*
210  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
211  *
212  *  - Signals its receipt.
213  *  - Waits for permission to restart.
214  *  - Processing pending IPIQ events while waiting.
215  *  - Signals its restart.
216  */
217
218         .text
219         SUPERALIGN_TEXT
220         .globl Xcpustop
221 Xcpustop:
222         pushl   %ebp
223         movl    %esp, %ebp
224         pushl   %eax
225         pushl   %ecx
226         pushl   %edx
227         pushl   %ds                     /* save current data segment */
228         pushl   %fs
229
230         movl    $KDSEL, %eax
231         mov     %ax, %ds                /* use KERNEL data segment */
232         movl    $KPSEL, %eax
233         mov     %ax, %fs
234
235         movl    lapic, %eax
236         movl    $0, LA_EOI(%eax)        /* End Of Interrupt to APIC */
237
238         movl    PCPU(cpuid), %eax
239         imull   $PCB_SIZE, %eax
240         leal    CNAME(stoppcbs)(%eax), %eax
241         pushl   %eax
242         call    CNAME(savectx)          /* Save process context */
243         addl    $4, %esp
244         
245                 
246         movl    PCPU(cpuid), %eax
247
248         /*
249          * Indicate that we have stopped and loop waiting for permission
250          * to start again.  We must still process IPI events while in a
251          * stopped state.
252          *
253          * Interrupts must remain enabled for non-IPI'd per-cpu interrupts
254          * (e.g. Xtimer, Xinvltlb).
255          */
256         MPLOCKED
257         btsl    %eax, stopped_cpus      /* stopped_cpus |= (1<<id) */
258         sti
259 1:
260         andl    $~RQF_IPIQ,PCPU(reqflags)
261         pushl   %eax
262         call    lwkt_smp_stopped
263         popl    %eax
264         btl     %eax, started_cpus      /* while (!(started_cpus & (1<<id))) */
265         jnc     1b
266
267         MPLOCKED
268         btrl    %eax, started_cpus      /* started_cpus &= ~(1<<id) */
269         MPLOCKED
270         btrl    %eax, stopped_cpus      /* stopped_cpus &= ~(1<<id) */
271
272         test    %eax, %eax
273         jnz     2f
274
275         movl    CNAME(cpustop_restartfunc), %eax
276         test    %eax, %eax
277         jz      2f
278         movl    $0, CNAME(cpustop_restartfunc)  /* One-shot */
279
280         call    *%eax
281 2:
282         popl    %fs
283         popl    %ds                     /* restore previous data segment */
284         popl    %edx
285         popl    %ecx
286         popl    %eax
287         movl    %ebp, %esp
288         popl    %ebp
289         iret
290
291         /*
292          * For now just have one ipiq IPI, but what we really want is
293          * to have one for each source cpu to the APICs don't get stalled
294          * backlogging the requests.
295          */
296         .text
297         SUPERALIGN_TEXT
298         .globl Xipiq
299 Xipiq:
300         PUSH_FRAME
301         movl    lapic,%eax
302         movl    $0,LA_EOI(%eax)         /* End Of Interrupt to APIC */
303         FAKE_MCOUNT(15*4(%esp))
304
305         incl    PCPU(cnt) + V_IPI
306         movl    PCPU(curthread),%ebx
307         testl   $-1,TD_CRITCOUNT(%ebx)
308         jne     1f
309         subl    $8,%esp                 /* make same as interrupt frame */
310         pushl   %esp                    /* pass frame by reference */
311         incl    PCPU(intr_nesting_level)
312         incl    TD_CRITCOUNT(%ebx)
313         sti
314         call    lwkt_process_ipiq_frame
315         decl    TD_CRITCOUNT(%ebx)
316         decl    PCPU(intr_nesting_level)
317         addl    $12,%esp
318         pushl   $0                      /* CPL for frame (REMOVED) */
319         MEXITCOUNT
320         jmp     doreti
321 1:
322         orl     $RQF_IPIQ,PCPU(reqflags)
323         MEXITCOUNT
324         jmp     doreti_syscall_ret
325
326         .text
327         SUPERALIGN_TEXT
328         .globl Xtimer
329 Xtimer:
330         PUSH_FRAME
331         movl    lapic,%eax
332         movl    $0,LA_EOI(%eax)         /* End Of Interrupt to APIC */
333         FAKE_MCOUNT(15*4(%esp))
334
335         incl    PCPU(cnt) + V_TIMER
336         movl    PCPU(curthread),%ebx
337         testl   $-1,TD_CRITCOUNT(%ebx)
338         jne     1f
339         testl   $-1,TD_NEST_COUNT(%ebx)
340         jne     1f
341         subl    $8,%esp                 /* make same as interrupt frame */
342         pushl   %esp                    /* pass frame by reference */
343         incl    PCPU(intr_nesting_level)
344         incl    TD_CRITCOUNT(%ebx)
345         sti
346         call    lapic_timer_process_frame
347         decl    TD_CRITCOUNT(%ebx)
348         decl    PCPU(intr_nesting_level)
349         addl    $12,%esp
350         pushl   $0                      /* CPL for frame (REMOVED) */
351         MEXITCOUNT
352         jmp     doreti
353 1:
354         orl     $RQF_TIMER,PCPU(reqflags)
355         MEXITCOUNT
356         jmp     doreti_syscall_ret
357
358 MCOUNT_LABEL(bintr)
359         INTR_HANDLER(0)
360         INTR_HANDLER(1)
361         INTR_HANDLER(2)
362         INTR_HANDLER(3)
363         INTR_HANDLER(4)
364         INTR_HANDLER(5)
365         INTR_HANDLER(6)
366         INTR_HANDLER(7)
367         INTR_HANDLER(8)
368         INTR_HANDLER(9)
369         INTR_HANDLER(10)
370         INTR_HANDLER(11)
371         INTR_HANDLER(12)
372         INTR_HANDLER(13)
373         INTR_HANDLER(14)
374         INTR_HANDLER(15)
375         INTR_HANDLER(16)
376         INTR_HANDLER(17)
377         INTR_HANDLER(18)
378         INTR_HANDLER(19)
379         INTR_HANDLER(20)
380         INTR_HANDLER(21)
381         INTR_HANDLER(22)
382         INTR_HANDLER(23)
383         INTR_HANDLER(24)
384         INTR_HANDLER(25)
385         INTR_HANDLER(26)
386         INTR_HANDLER(27)
387         INTR_HANDLER(28)
388         INTR_HANDLER(29)
389         INTR_HANDLER(30)
390         INTR_HANDLER(31)
391         INTR_HANDLER(32)
392         INTR_HANDLER(33)
393         INTR_HANDLER(34)
394         INTR_HANDLER(35)
395         INTR_HANDLER(36)
396         INTR_HANDLER(37)
397         INTR_HANDLER(38)
398         INTR_HANDLER(39)
399         INTR_HANDLER(40)
400         INTR_HANDLER(41)
401         INTR_HANDLER(42)
402         INTR_HANDLER(43)
403         INTR_HANDLER(44)
404         INTR_HANDLER(45)
405         INTR_HANDLER(46)
406         INTR_HANDLER(47)
407         INTR_HANDLER(48)
408         INTR_HANDLER(49)
409         INTR_HANDLER(50)
410         INTR_HANDLER(51)
411         INTR_HANDLER(52)
412         INTR_HANDLER(53)
413         INTR_HANDLER(54)
414         INTR_HANDLER(55)
415         INTR_HANDLER(56)
416         INTR_HANDLER(57)
417         INTR_HANDLER(58)
418         INTR_HANDLER(59)
419         INTR_HANDLER(60)
420         INTR_HANDLER(61)
421         INTR_HANDLER(62)
422         INTR_HANDLER(63)
423         INTR_HANDLER(64)
424         INTR_HANDLER(65)
425         INTR_HANDLER(66)
426         INTR_HANDLER(67)
427         INTR_HANDLER(68)
428         INTR_HANDLER(69)
429         INTR_HANDLER(70)
430         INTR_HANDLER(71)
431         INTR_HANDLER(72)
432         INTR_HANDLER(73)
433         INTR_HANDLER(74)
434         INTR_HANDLER(75)
435         INTR_HANDLER(76)
436         INTR_HANDLER(77)
437         INTR_HANDLER(78)
438         INTR_HANDLER(79)
439         INTR_HANDLER(80)
440         INTR_HANDLER(81)
441         INTR_HANDLER(82)
442         INTR_HANDLER(83)
443         INTR_HANDLER(84)
444         INTR_HANDLER(85)
445         INTR_HANDLER(86)
446         INTR_HANDLER(87)
447         INTR_HANDLER(88)
448         INTR_HANDLER(89)
449         INTR_HANDLER(90)
450         INTR_HANDLER(91)
451         INTR_HANDLER(92)
452         INTR_HANDLER(93)
453         INTR_HANDLER(94)
454         INTR_HANDLER(95)
455         INTR_HANDLER(96)
456         INTR_HANDLER(97)
457         INTR_HANDLER(98)
458         INTR_HANDLER(99)
459         INTR_HANDLER(100)
460         INTR_HANDLER(101)
461         INTR_HANDLER(102)
462         INTR_HANDLER(103)
463         INTR_HANDLER(104)
464         INTR_HANDLER(105)
465         INTR_HANDLER(106)
466         INTR_HANDLER(107)
467         INTR_HANDLER(108)
468         INTR_HANDLER(109)
469         INTR_HANDLER(110)
470         INTR_HANDLER(111)
471         INTR_HANDLER(112)
472         INTR_HANDLER(113)
473         INTR_HANDLER(114)
474         INTR_HANDLER(115)
475         INTR_HANDLER(116)
476         INTR_HANDLER(117)
477         INTR_HANDLER(118)
478         INTR_HANDLER(119)
479         INTR_HANDLER(120)
480         INTR_HANDLER(121)
481         INTR_HANDLER(122)
482         INTR_HANDLER(123)
483         INTR_HANDLER(124)
484         INTR_HANDLER(125)
485         INTR_HANDLER(126)
486         INTR_HANDLER(127)
487         INTR_HANDLER(128)
488         INTR_HANDLER(129)
489         INTR_HANDLER(130)
490         INTR_HANDLER(131)
491         INTR_HANDLER(132)
492         INTR_HANDLER(133)
493         INTR_HANDLER(134)
494         INTR_HANDLER(135)
495         INTR_HANDLER(136)
496         INTR_HANDLER(137)
497         INTR_HANDLER(138)
498         INTR_HANDLER(139)
499         INTR_HANDLER(140)
500         INTR_HANDLER(141)
501         INTR_HANDLER(142)
502         INTR_HANDLER(143)
503         INTR_HANDLER(144)
504         INTR_HANDLER(145)
505         INTR_HANDLER(146)
506         INTR_HANDLER(147)
507         INTR_HANDLER(148)
508         INTR_HANDLER(149)
509         INTR_HANDLER(150)
510         INTR_HANDLER(151)
511         INTR_HANDLER(152)
512         INTR_HANDLER(153)
513         INTR_HANDLER(154)
514         INTR_HANDLER(155)
515         INTR_HANDLER(156)
516         INTR_HANDLER(157)
517         INTR_HANDLER(158)
518         INTR_HANDLER(159)
519         INTR_HANDLER(160)
520         INTR_HANDLER(161)
521         INTR_HANDLER(162)
522         INTR_HANDLER(163)
523         INTR_HANDLER(164)
524         INTR_HANDLER(165)
525         INTR_HANDLER(166)
526         INTR_HANDLER(167)
527         INTR_HANDLER(168)
528         INTR_HANDLER(169)
529         INTR_HANDLER(170)
530         INTR_HANDLER(171)
531         INTR_HANDLER(172)
532         INTR_HANDLER(173)
533         INTR_HANDLER(174)
534         INTR_HANDLER(175)
535         INTR_HANDLER(176)
536         INTR_HANDLER(177)
537         INTR_HANDLER(178)
538         INTR_HANDLER(179)
539         INTR_HANDLER(180)
540         INTR_HANDLER(181)
541         INTR_HANDLER(182)
542         INTR_HANDLER(183)
543         INTR_HANDLER(184)
544         INTR_HANDLER(185)
545         INTR_HANDLER(186)
546         INTR_HANDLER(187)
547         INTR_HANDLER(188)
548         INTR_HANDLER(189)
549         INTR_HANDLER(190)
550         INTR_HANDLER(191)
551 MCOUNT_LABEL(eintr)
552
553         .data
554
555 /* variables used by stop_cpus()/restart_cpus()/Xcpustop */
556         .globl stopped_cpus, started_cpus
557 stopped_cpus:
558         .long   0
559 started_cpus:
560         .long   0
561
562         .globl CNAME(cpustop_restartfunc)
563 CNAME(cpustop_restartfunc):
564         .long 0
565                 
566         .text
567