7df5d35354f0e08288a1b8d93c8dc06285ecb59c
[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 <time.h>
17 #include <assert.h>
18 #include <stdio.h>
19 #include <bitmask.h>
20 #include <arch/coreid.h>
21 #include <arch/pic.h>
22
23 system_timing_t RO system_timing = {0, 0, 0xffff, 0};
24 bool core_id_ready = FALSE;
25
26 bool lapic_check_spurious(int trap_nr)
27 {
28         /* FYI: lapic_spurious is 255 on qemu and 15 on the nehalem..  We actually
29          * can set bits 4-7, and P6s have 0-3 hardwired to 0.  YMMV.
30          *
31          * The SDM recommends not using the spurious vector for any other IRQs (LVT
32          * or IOAPIC RTE), since the handlers don't send an EOI.  However, our check
33          * here allows us to use the vector since we can tell the diff btw a
34          * spurious and a real IRQ. */
35         uint8_t lapic_spurious = read_mmreg32(LAPIC_SPURIOUS) & 0xff;
36         /* Note the lapic's vectors are not shifted by an offset. */
37         if ((trap_nr == lapic_spurious) && !lapic_get_isr_bit(lapic_spurious)) {
38                 /* i'm still curious about these */
39                 printk("Spurious LAPIC irq %d, core %d!\n", lapic_spurious, core_id());
40                 lapic_print_isr();
41                 return TRUE;
42         }
43         return FALSE;
44 }
45
46 /* Debugging helper.  Note the ISR/IRR are 32 bits at a time, spaced every 16
47  * bytes in the LAPIC address space. */
48 void lapic_print_isr(void)
49 {
50         printk("LAPIC ISR on core %d\n--------------\n", core_id());
51         for (int i = 7; i >= 0; i--)
52                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
53                        *(uint32_t*)(LAPIC_ISR + i * 0x10));
54         printk("LAPIC IRR on core %d\n--------------\n", core_id());
55         for (int i = 7; i >= 0; i--)
56                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
57                        *(uint32_t*)(LAPIC_IRR + i * 0x10));
58 }
59
60 /* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
61  * pass in.  These registers consist of 8, 32 byte registers spaced every 16
62  * bytes from the base in the LAPIC. */
63 static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
64 {
65         int which_reg = vector >> 5;    /* 32 bits per reg */
66         uint32_t *lapic_reg = (uint32_t*)(base + which_reg * 0x10);     /* offset 16 */
67         return (*lapic_reg & (1 << (vector % 32)) ? 1 : 0);
68 }
69
70 bool lapic_get_isr_bit(uint8_t vector)
71 {
72         return __lapic_get_isrr_bit(LAPIC_ISR, vector);
73 }
74
75 bool lapic_get_irr_bit(uint8_t vector)
76 {
77         return __lapic_get_isrr_bit(LAPIC_IRR, vector);
78 }
79
80 /* This works for any interrupt that goes through the LAPIC, but not things like
81  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now (which only
82  * come via the APIC).
83  *
84  * We only check the ISR, due to how we send EOIs.  Since we don't send til
85  * after handlers return, the ISR will show pending for the current IRQ.  It is
86  * the EOI that clears the bit from the ISR. */
87 bool ipi_is_pending(uint8_t vector)
88 {
89         return lapic_get_isr_bit(vector);
90 }
91
92 /*
93  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
94  * clock freq is actually the bus clock, which we figure out during timer_init
95  * Unmasking is implied.  Ref SDM, 3A, 9.6.4
96  */
97 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
98 {
99 #ifdef CONFIG_LOUSY_LAPIC_TIMER
100         /* qemu without kvm seems to delay timer IRQs on occasion, and needs extra
101          * IRQs from any source to get them delivered.  periodic does the trick. */
102         periodic = TRUE;
103 #endif
104         // clears bottom bit and then set divider
105         write_mmreg32(LAPIC_TIMER_DIVIDE, (read_mmreg32(LAPIC_TIMER_DIVIDE) &~0xf) |
106                       (div & 0xf));
107         // set LVT with interrupt handling information
108         write_mmreg32(LAPIC_LVT_TIMER, vec | (periodic << 17));
109         write_mmreg32(LAPIC_TIMER_INIT, ticks);
110         // For debugging when we expand this
111         //cprintf("LAPIC LVT Timer: 0x%08x\n", read_mmreg32(LAPIC_LVT_TIMER));
112         //cprintf("LAPIC Init Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_INIT));
113         //cprintf("LAPIC Current Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_CURRENT));
114 }
115
116 void lapic_set_timer(uint32_t usec, bool periodic)
117 {
118         /* If we overflowed a uint32, send in the max timer possible.  The lapic can
119          * only handle a 32 bit.  We could muck with changing the divisor, but even
120          * then, we might not be able to match 4000 sec (based on the bus speed).
121          * The kernel alarm code can handle spurious timer interrupts, so we just
122          * set the timer for as close as we can get to the desired time. */
123         uint64_t ticks64 = (usec * system_timing.bus_freq) / LAPIC_TIMER_DIVISOR_VAL
124                             / 1000000;
125         uint32_t ticks32 = ((ticks64 >> 32) ? 0xffffffff : ticks64);
126         assert(ticks32 > 0);
127         __lapic_set_timer(ticks32, LAPIC_TIMER_DEFAULT_VECTOR, periodic,
128                           LAPIC_TIMER_DIVISOR_BITS);
129 }
130
131 void set_core_timer(uint32_t usec, bool periodic)
132 {
133         if (usec)
134                 lapic_set_timer(usec, periodic);
135         else
136                 lapic_disable_timer();
137 }
138
139 uint32_t lapic_get_default_id(void)
140 {
141         uint32_t ebx;
142         cpuid(0x1, 0x0, 0, &ebx, 0, 0);
143         // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
144         return (ebx & 0xFF000000) >> 24;
145 }
146
147 // timer init calibrates both tsc timer and lapic timer using PIT
148 void timer_init(void){
149         /* some boards have this unmasked early on. */
150         pic_mask_irq(0 + PIC1_OFFSET);
151         uint64_t tscval[2];
152         long timercount[2];
153         pit_set_timer(0xffff, TIMER_RATEGEN);
154         // assume tsc exist
155         tscval[0] = read_tsc();
156         udelay_pit(1000000);
157         tscval[1] = read_tsc();
158         system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
159         cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
160         __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
161                           LAPIC_TIMER_DIVISOR_BITS);
162         // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
163         mask_lapic_lvt(LAPIC_LVT_TIMER);
164         timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
165         udelay_pit(1000000);
166         timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
167         system_timing.bus_freq = (timercount[0] - timercount[1])
168                                  * LAPIC_TIMER_DIVISOR_VAL;
169         /* The time base for the timer is derived from the processor's bus clock,
170          * divided by the value specified in the divide configuration register.
171          * Note we mult and div by the divisor, saving the actual freq (even though
172          * we don't use it yet). */
173         cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
174 }
175
176 void pit_set_timer(uint32_t divisor, uint32_t mode)
177 {
178         if (divisor & 0xffff0000)
179                 warn("Divisor too large!");
180         mode = TIMER_SEL0|TIMER_16BIT|mode;
181         outb(TIMER_MODE, mode); 
182         outb(TIMER_CNTR0, divisor & 0xff);
183         outb(TIMER_CNTR0, (divisor >> 8) );
184         system_timing.pit_mode = SINIT(mode);
185         system_timing.pit_divisor = SINIT(divisor);
186         // cprintf("timer mode set to %d, divisor %d\n",mode, divisor);
187 }
188
189 static int getpit()
190 {
191     int high, low;
192         // TODO: need a lock to protect access to PIT
193
194     /* Select counter 0 and latch counter value. */
195     outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
196     
197     low = inb(TIMER_CNTR0);
198     high = inb(TIMER_CNTR0);
199
200     return ((high << 8) | low);
201 }
202
203 // forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
204 void udelay(uint64_t usec)
205 {
206         #if !defined(__BOCHS__)
207         if (system_timing.tsc_freq != 0)
208         {
209                 uint64_t start, end, now;
210
211                 start = read_tsc();
212         end = start + usec2tsc(usec);
213         //cprintf("start %llu, end %llu\n", start, end);
214                 if (end == 0) cprintf("This is terribly wrong \n");
215                 do {
216             cpu_relax();
217             now = read_tsc();
218                         //cprintf("now %llu\n", now);
219                 } while (now < end || (now > start && end < start));
220         return;
221
222         } else
223         #endif
224         {
225                 udelay_pit(usec);
226         }
227 }
228
229 void udelay_pit(uint64_t usec)
230 {
231         
232         int64_t delta, prev_tick, tick, ticks_left;
233         prev_tick = getpit();
234         /*
235          * Calculate (n * (i8254_freq / 1e6)) without using floating point
236          * and without any avoidable overflows.
237          */
238         if (usec <= 0)
239                 ticks_left = 0;
240         // some optimization from bsd code
241         else if (usec < 256)
242                 /*
243                  * Use fixed point to avoid a slow division by 1000000.
244                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
245                  * 2^15 is the first power of 2 that gives exact results
246                  * for n between 0 and 256.
247                  */
248                 ticks_left = ((uint64_t)usec * 39099 + (1 << 15) - 1) >> 15;
249         else
250                 // round up the ticks left
251                 ticks_left = ((uint64_t)usec * (long long)PIT_FREQ+ 999999)
252                              / 1000000; 
253         while (ticks_left > 0) {
254                 tick = getpit();
255                 delta = prev_tick - tick;
256                 prev_tick = tick;
257                 if (delta < 0) {
258                         // counter looped around during the delta time period
259                         delta += system_timing.pit_divisor; // maximum count 
260                         if (delta < 0)
261                                 delta = 0;
262                 }
263                 ticks_left -= delta;
264         }
265 }
266
267 uint64_t gettimer(void)
268 {
269         return read_tsc();      
270 }
271
272 uint64_t getfreq(void)
273 {
274         return system_timing.tsc_freq;
275 }