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