x86: IDT vector realignment (XCC)
[akaros.git] / kern / arch / x86 / apic.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  */
6
7 #ifdef __SHARC__
8 #pragma nosharc
9 #define SINIT(x) x
10 #endif
11
12 #include <arch/mmu.h>
13 #include <arch/x86.h>
14 #include <arch/arch.h>
15 #include <arch/apic.h>
16 #include <trap.h>
17 #include <time.h>
18 #include <assert.h>
19 #include <stdio.h>
20 #include <bitmask.h>
21 #include <arch/coreid.h>
22
23 bool core_id_ready = FALSE;
24
25 bool lapic_check_spurious(int trap_nr)
26 {
27         /* FYI: lapic_spurious is 255 on qemu and 15 on the nehalem..  We actually
28          * can set bits 4-7, and P6s have 0-3 hardwired to 0.  YMMV.
29          *
30          * The SDM recommends not using the spurious vector for any other IRQs (LVT
31          * or IOAPIC RTE), since the handlers don't send an EOI.  However, our check
32          * here allows us to use the vector since we can tell the diff btw a
33          * spurious and a real IRQ. */
34         uint8_t lapic_spurious = read_mmreg32(LAPIC_SPURIOUS) & 0xff;
35         /* Note the lapic's vectors are not shifted by an offset. */
36         if ((trap_nr == lapic_spurious) && !lapic_get_isr_bit(lapic_spurious)) {
37                 /* i'm still curious about these */
38                 printk("Spurious LAPIC irq %d, core %d!\n", lapic_spurious, core_id());
39                 lapic_print_isr();
40                 return TRUE;
41         }
42         return FALSE;
43 }
44
45 /* Debugging helper.  Note the ISR/IRR are 32 bits at a time, spaced every 16
46  * bytes in the LAPIC address space. */
47 void lapic_print_isr(void)
48 {
49         printk("LAPIC ISR on core %d\n--------------\n", core_id());
50         for (int i = 7; i >= 0; i--)
51                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
52                        *(uint32_t*)(LAPIC_ISR + i * 0x10));
53         printk("LAPIC IRR on core %d\n--------------\n", core_id());
54         for (int i = 7; i >= 0; i--)
55                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
56                        *(uint32_t*)(LAPIC_IRR + i * 0x10));
57 }
58
59 /* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
60  * pass in.  These registers consist of 8, 32 byte registers spaced every 16
61  * bytes from the base in the LAPIC. */
62 static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
63 {
64         int which_reg = vector >> 5;    /* 32 bits per reg */
65         uint32_t *lapic_reg = (uint32_t*)(base + which_reg * 0x10);     /* offset 16 */
66         return (*lapic_reg & (1 << (vector % 32)) ? 1 : 0);
67 }
68
69 bool lapic_get_isr_bit(uint8_t vector)
70 {
71         return __lapic_get_isrr_bit(LAPIC_ISR, vector);
72 }
73
74 bool lapic_get_irr_bit(uint8_t vector)
75 {
76         return __lapic_get_isrr_bit(LAPIC_IRR, vector);
77 }
78
79 /* This works for any interrupt that goes through the LAPIC, but not things like
80  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now (which only
81  * come via the APIC).
82  *
83  * We only check the ISR, due to how we send EOIs.  Since we don't send til
84  * after handlers return, the ISR will show pending for the current IRQ.  It is
85  * the EOI that clears the bit from the ISR. */
86 bool ipi_is_pending(uint8_t vector)
87 {
88         return lapic_get_isr_bit(vector);
89 }
90
91 /*
92  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
93  * clock freq is actually the bus clock, which we figure out during timer_init
94  * Unmasking is implied.  Ref SDM, 3A, 9.6.4
95  */
96 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
97 {
98 #ifdef CONFIG_LOUSY_LAPIC_TIMER
99         /* qemu without kvm seems to delay timer IRQs on occasion, and needs extra
100          * IRQs from any source to get them delivered.  periodic does the trick. */
101         periodic = TRUE;
102 #endif
103         // clears bottom bit and then set divider
104         write_mmreg32(LAPIC_TIMER_DIVIDE, (read_mmreg32(LAPIC_TIMER_DIVIDE) &~0xf) |
105                       (div & 0xf));
106         // set LVT with interrupt handling information
107         write_mmreg32(LAPIC_LVT_TIMER, vec | (periodic << 17));
108         write_mmreg32(LAPIC_TIMER_INIT, ticks);
109         // For debugging when we expand this
110         //cprintf("LAPIC LVT Timer: 0x%08x\n", read_mmreg32(LAPIC_LVT_TIMER));
111         //cprintf("LAPIC Init Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_INIT));
112         //cprintf("LAPIC Current Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_CURRENT));
113 }
114
115 void lapic_set_timer(uint32_t usec, bool periodic)
116 {
117         /* If we overflowed a uint32, send in the max timer possible.  The lapic can
118          * only handle a 32 bit.  We could muck with changing the divisor, but even
119          * then, we might not be able to match 4000 sec (based on the bus speed).
120          * The kernel alarm code can handle spurious timer interrupts, so we just
121          * set the timer for as close as we can get to the desired time. */
122         uint64_t ticks64 = (usec * system_timing.bus_freq) / LAPIC_TIMER_DIVISOR_VAL
123                             / 1000000;
124         uint32_t ticks32 = ((ticks64 >> 32) ? 0xffffffff : ticks64);
125         assert(ticks32 > 0);
126         __lapic_set_timer(ticks32, IdtLAPIC_TIMER, periodic,
127                           LAPIC_TIMER_DIVISOR_BITS);
128 }
129
130 uint32_t lapic_get_default_id(void)
131 {
132         uint32_t ebx;
133         cpuid(0x1, 0x0, 0, &ebx, 0, 0);
134         // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
135         return (ebx & 0xFF000000) >> 24;
136 }