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