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