Overhaul lock_test.R
[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 #include <arch/mmu.h>
8 #include <arch/x86.h>
9 #include <arch/arch.h>
10 #include <arch/apic.h>
11 #include <trap.h>
12 #include <time.h>
13 #include <assert.h>
14 #include <stdio.h>
15 #include <bitmask.h>
16 #include <arch/topology.h>
17 #include <ros/procinfo.h>
18
19 bool lapic_check_spurious(int trap_nr)
20 {
21         /* FYI: lapic_spurious is 255 on qemu and 15 on the nehalem..  We
22          * actually can set bits 4-7, and P6s have 0-3 hardwired to 0.  YMMV.
23          * NxM seems to say the lower 3 bits are usually 1.  We'll see if the
24          * assert trips.
25          *
26          * The SDM recommends not using the spurious vector for any other IRQs
27          * (LVT or IOAPIC RTE), since the handlers don't send an EOI.  However,
28          * our check here allows us to use the vector since we can tell the diff
29          * btw a spurious and a real IRQ. */
30         assert(IdtLAPIC_SPURIOUS == (apicrget(MSR_LAPIC_SPURIOUS) & 0xff));
31         /* Note the lapic's vectors are not shifted by an offset. */
32         if ((trap_nr == IdtLAPIC_SPURIOUS) &&
33              !lapic_get_isr_bit(IdtLAPIC_SPURIOUS)) {
34                 /* i'm still curious about these */
35                 printk("Spurious LAPIC irq %d, core %d!\n", IdtLAPIC_SPURIOUS,
36                        core_id());
37                 lapic_print_isr();
38                 return TRUE;
39         }
40         return FALSE;
41 }
42
43 /* Debugging helper.  Note the ISR/IRR are 32 bits at a time, spaced every 16
44  * bytes in the LAPIC address space. */
45 void lapic_print_isr(void)
46 {
47         printk("LAPIC ISR on core %d\n--------------\n", core_id());
48         for (int i = 7; i >= 0; i--)
49                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
50                         apicrget(MSR_LAPIC_ISR_START + i));
51         printk("LAPIC IRR on core %d\n--------------\n", core_id());
52         for (int i = 7; i >= 0; i--)
53                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
54                         apicrget(MSR_LAPIC_IRR_START + i));
55 }
56
57 /* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
58  * pass in.  These registers consist of 8, 32 byte registers spaced every 16
59  * bytes from the base in the LAPIC. */
60 static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
61 {
62         int which_reg = vector >> 5;    /* 32 bits per reg */
63         uintptr_t lapic_reg = base + which_reg;
64
65         return (apicrget(lapic_reg) & (1 << (vector % 32)) ? 1 : 0);
66 }
67
68 bool lapic_get_isr_bit(uint8_t vector)
69 {
70         return __lapic_get_isrr_bit(MSR_LAPIC_ISR_START, vector);
71 }
72
73 bool lapic_get_irr_bit(uint8_t vector)
74 {
75         return __lapic_get_isrr_bit(MSR_LAPIC_IRR_START, vector);
76 }
77
78 void lapic_mask_irq(struct irq_handler *unused, int apic_vector)
79 {
80         uintptr_t mm_reg;
81
82         if (apic_vector < IdtLAPIC || IdtLAPIC + 4 < apic_vector) {
83                 warn("Bad apic vector %d\n", apic_vector);
84                 return;
85         }
86         mm_reg = MSR_LAPIC_LVT_TIMER + (apic_vector - IdtLAPIC);
87         apicrput(mm_reg, apicrget(mm_reg) | LAPIC_LVT_MASK);
88 }
89
90 void lapic_unmask_irq(struct irq_handler *unused, int apic_vector)
91 {
92         uintptr_t mm_reg;
93
94         if (apic_vector < IdtLAPIC || IdtLAPIC + 4 < apic_vector) {
95                 warn("Bad apic vector %d\n", apic_vector);
96                 return;
97         }
98         mm_reg = MSR_LAPIC_LVT_TIMER + (apic_vector - IdtLAPIC);
99         apicrput(mm_reg, apicrget(mm_reg) & ~LAPIC_LVT_MASK);
100 }
101
102 /* This works for any interrupt that goes through the LAPIC, but not things like
103  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now (which only
104  * come via the APIC).
105  *
106  * We only check the ISR, due to how we send EOIs.  Since we don't send til
107  * after handlers return, the ISR will show pending for the current IRQ.  It is
108  * the EOI that clears the bit from the ISR. */
109 bool ipi_is_pending(uint8_t vector)
110 {
111         return lapic_get_isr_bit(vector);
112 }
113
114 /*
115  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
116  * clock freq is actually the bus clock, which we figure out during timer_init
117  * Unmasking is implied.  Ref SDM, 3A, 9.6.4
118  */
119 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
120 {
121 #ifdef CONFIG_LOUSY_LAPIC_TIMER
122         /* qemu without kvm seems to delay timer IRQs on occasion, and needs
123          * extra IRQs from any source to get them delivered.  periodic does the
124          * trick. */
125         periodic = TRUE;
126 #endif
127         // clears bottom bit and then set divider
128         apicrput(MSR_LAPIC_DIVIDE_CONFIG_REG,
129                  (apicrget(MSR_LAPIC_DIVIDE_CONFIG_REG) & ~0xf) | (div & 0xf));
130         // set LVT with interrupt handling information.  also unmasks.
131         apicrput(MSR_LAPIC_LVT_TIMER, vec | (periodic << 17));
132         apicrput(MSR_LAPIC_INITIAL_COUNT, ticks);
133 }
134
135 void lapic_set_timer(uint32_t usec, bool periodic)
136 {
137         /* If we overflowed a uint32, send in the max timer possible.  The lapic
138          * can only handle a 32 bit.  We could muck with changing the divisor,
139          * but even then, we might not be able to match 4000 sec (based on the
140          * bus speed).  The kernel alarm code can handle spurious timer
141          * interrupts, so we just set the timer for as close as we can get to
142          * the desired time. */
143         uint64_t ticks64 = (usec * __proc_global_info.bus_freq)
144                            / LAPIC_TIMER_DIVISOR_VAL / 1000000;
145         uint32_t ticks32 = ((ticks64 >> 32) ? 0xffffffff : ticks64);
146
147         assert(ticks32 > 0);
148         __lapic_set_timer(ticks32, IdtLAPIC_TIMER, periodic,
149                           LAPIC_TIMER_DIVISOR_BITS);
150 }
151
152 uint32_t lapic_get_default_id(void)
153 {
154         uint32_t ebx;
155         
156         cpuid(0x1, 0x0, 0, &ebx, 0, 0);
157         // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
158         return (ebx & 0xFF000000) >> 24;
159 }