Clarifies minor PIT comments
[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
21 system_timing_t RO system_timing = {0, 0, 0xffff, 0};
22 bool core_id_ready = FALSE;
23 spinlock_t piclock = SPINLOCK_INITIALIZER_IRQSAVE;
24
25 /* * Remaps the Programmable Interrupt Controller to use IRQs 32-47
26  * http://wiki.osdev.org/PIC
27  * Check osdev for a more thorough explanation/implementation.
28  * http://bochs.sourceforge.net/techspec/PORTS.LST  */
29 void pic_remap(void)
30 {
31         spin_lock_irqsave(&piclock);
32         /* start initialization (ICW1) */
33         outb(PIC1_CMD, 0x11);
34         outb(PIC2_CMD, 0x11);
35         /* set new offsets (ICW2) */
36         outb(PIC1_DATA, PIC1_OFFSET);
37         outb(PIC2_DATA, PIC2_OFFSET);
38         /* set up cascading (ICW3) */
39         outb(PIC1_DATA, 0x04);
40         outb(PIC2_DATA, 0x02);
41         /* other stuff (put in 8086/88 mode, or whatever) (ICW4) */
42         outb(PIC1_DATA, 0x01);
43         outb(PIC2_DATA, 0x01);
44         /* Init done, further data R/W access the interrupt mask */
45         /* set masks, defaulting to all masked for now */
46         outb(PIC1_DATA, 0xff);
47         outb(PIC2_DATA, 0xff);
48         spin_unlock_irqsave(&piclock);
49 }
50
51 void pic_mask_irq(uint8_t irq)
52 {
53         spin_lock_irqsave(&piclock);
54         if (irq > 7)
55                 outb(PIC2_DATA, inb(PIC2_DATA) | (1 << (irq - 8)));
56         else
57                 outb(PIC1_DATA, inb(PIC1_DATA) | (1 << irq));
58         spin_unlock_irqsave(&piclock);
59 }
60
61 void pic_unmask_irq(uint8_t irq)
62 {
63         spin_lock_irqsave(&piclock);
64         if (irq > 7) {
65                 outb(PIC2_DATA, inb(PIC2_DATA) & ~(1 << (irq - 8)));
66                 outb(PIC1_DATA, inb(PIC1_DATA) & 0xfb); // make sure irq2 is unmasked
67         } else
68                 outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
69         spin_unlock_irqsave(&piclock);
70 }
71
72 /* Aka, the IMR.  Simply reading the data port are OCW1s. */
73 uint16_t pic_get_mask(void)
74 {
75         uint16_t ret;
76         spin_lock_irqsave(&piclock);
77         ret = (inb(PIC2_DATA) << 8) | inb(PIC1_DATA);
78         spin_unlock_irqsave(&piclock);
79         return ret;
80 }
81
82 static uint16_t __pic_get_irq_reg(int ocw3)
83 {
84         uint16_t ret;
85         spin_lock_irqsave(&piclock);
86         /* OCW3 to PIC CMD to get the register values.  PIC2 is chained, and
87          * represents IRQs 8-15.  PIC1 is IRQs 0-7, with 2 being the chain */
88         outb(PIC1_CMD, ocw3);
89         outb(PIC2_CMD, ocw3);
90         ret = (inb(PIC2_CMD) << 8) | inb(PIC1_CMD);
91         spin_unlock_irqsave(&piclock);
92         return ret;
93 }
94
95 /* Returns the combined value of the cascaded PICs irq request register */
96 uint16_t pic_get_irr(void)
97 {
98         return __pic_get_irq_reg(PIC_READ_IRR);
99 }
100
101 /* Returns the combined value of the cascaded PICs irq service register */
102 uint16_t pic_get_isr(void)
103 {
104         return __pic_get_irq_reg(PIC_READ_ISR);
105 }
106
107 void pic_send_eoi(uint32_t irq)
108 {
109         spin_lock_irqsave(&piclock);
110         // all irqs beyond the first seven need to be chained to the slave
111         if (irq > 7)
112                 outb(PIC2_CMD, PIC_EOI);
113         outb(PIC1_CMD, PIC_EOI);
114         spin_unlock_irqsave(&piclock);
115 }
116
117 /* Debugging helper.  Note the ISR/IRR are 32 bits at a time, spaced every 16
118  * bytes in the LAPIC address space. */
119 void lapic_print_isr(void)
120 {
121         printk("LAPIC ISR on core %d\n--------------\n", core_id());
122         for (int i = 7; i >= 0; i--)
123                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
124                        *(uint32_t*)(LAPIC_ISR + i * 0x10));
125         printk("LAPIC IRR on core %d\n--------------\n", core_id());
126         for (int i = 7; i >= 0; i--)
127                 printk("%3d-%3d: %p\n", (i + 1) * 32 - 1, i * 32,
128                        *(uint32_t*)(LAPIC_IRR + i * 0x10));
129 }
130
131 /* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
132  * pass in.  These registers consist of 8, 32 byte registers spaced every 16
133  * bytes from the base in the LAPIC. */
134 static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
135 {
136         int which_reg = vector >> 5;    /* 32 bits per reg */
137         uint32_t *lapic_reg = (uint32_t*)(base + which_reg * 0x10);     /* offset 16 */
138         return (*lapic_reg & (1 << (vector % 32)) ? 1 : 0);
139 }
140
141 bool lapic_get_isr_bit(uint8_t vector)
142 {
143         return __lapic_get_isrr_bit(LAPIC_ISR, vector);
144 }
145
146 bool lapic_get_irr_bit(uint8_t vector)
147 {
148         return __lapic_get_isrr_bit(LAPIC_IRR, vector);
149 }
150
151 /* This works for any interrupt that goes through the LAPIC, but not things like
152  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now (which only
153  * come via the APIC).
154  *
155  * We only check the IRR, due to how we send EOIs.  Since we don't send til
156  * after handlers return, the ISR will show pending for the current IRQ.  It is
157  * the EOI that clears the bit from the ISR. */
158 bool ipi_is_pending(uint8_t vector)
159 {
160         return lapic_get_isr_bit(vector);
161 }
162
163 /*
164  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
165  * clock freq is actually the bus clock, which we figure out during timer_init
166  * Unmasking is implied.  Ref SDM, 3A, 9.6.4
167  */
168 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div)
169 {
170 #ifdef CONFIG_LOUSY_LAPIC_TIMER
171         /* qemu without kvm seems to delay timer IRQs on occasion, and needs extra
172          * IRQs from any source to get them delivered.  periodic does the trick. */
173         periodic = TRUE;
174 #endif
175         // clears bottom bit and then set divider
176         write_mmreg32(LAPIC_TIMER_DIVIDE, (read_mmreg32(LAPIC_TIMER_DIVIDE) &~0xf) |
177                       (div & 0xf));
178         // set LVT with interrupt handling information
179         write_mmreg32(LAPIC_LVT_TIMER, vec | (periodic << 17));
180         write_mmreg32(LAPIC_TIMER_INIT, ticks);
181         // For debugging when we expand this
182         //cprintf("LAPIC LVT Timer: 0x%08x\n", read_mmreg32(LAPIC_LVT_TIMER));
183         //cprintf("LAPIC Init Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_INIT));
184         //cprintf("LAPIC Current Count: 0x%08x\n", read_mmreg32(LAPIC_TIMER_CURRENT));
185 }
186
187 void lapic_set_timer(uint32_t usec, bool periodic)
188 {
189         /* If we overflowed a uint32, send in the max timer possible.  The lapic can
190          * only handle a 32 bit.  We could muck with changing the divisor, but even
191          * then, we might not be able to match 4000 sec (based on the bus speed).
192          * The kernel alarm code can handle spurious timer interrupts, so we just
193          * set the timer for as close as we can get to the desired time. */
194         uint64_t ticks64 = (usec * system_timing.bus_freq) / LAPIC_TIMER_DIVISOR_VAL
195                             / 1000000;
196         uint32_t ticks32 = ((ticks64 >> 32) ? 0xffffffff : ticks64);
197         assert(ticks32 > 0);
198         __lapic_set_timer(ticks32, LAPIC_TIMER_DEFAULT_VECTOR, periodic,
199                           LAPIC_TIMER_DIVISOR_BITS);
200 }
201
202 void set_core_timer(uint32_t usec, bool periodic)
203 {
204         if (usec)
205                 lapic_set_timer(usec, periodic);
206         else
207                 lapic_disable_timer();
208 }
209
210 uint32_t lapic_get_default_id(void)
211 {
212         uint32_t ebx;
213         cpuid(0x1, 0x0, 0, &ebx, 0, 0);
214         // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
215         return (ebx & 0xFF000000) >> 24;
216 }
217
218 // timer init calibrates both tsc timer and lapic timer using PIT
219 void timer_init(void){
220         /* some boards have this unmasked early on. */
221         pic_mask_irq(0);
222         uint64_t tscval[2];
223         long timercount[2];
224         pit_set_timer(0xffff, TIMER_RATEGEN);
225         // assume tsc exist
226         tscval[0] = read_tsc();
227         udelay_pit(1000000);
228         tscval[1] = read_tsc();
229         system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
230         cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
231         __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
232                           LAPIC_TIMER_DIVISOR_BITS);
233         // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
234         mask_lapic_lvt(LAPIC_LVT_TIMER);
235         timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
236         udelay_pit(1000000);
237         timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
238         system_timing.bus_freq = (timercount[0] - timercount[1])
239                                  * LAPIC_TIMER_DIVISOR_VAL;
240         /* The time base for the timer is derived from the processor's bus clock,
241          * divided by the value specified in the divide configuration register.
242          * Note we mult and div by the divisor, saving the actual freq (even though
243          * we don't use it yet). */
244         cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
245 }
246
247 void pit_set_timer(uint32_t divisor, uint32_t mode)
248 {
249         if (divisor & 0xffff0000)
250                 warn("Divisor too large!");
251         mode = TIMER_SEL0|TIMER_16BIT|mode;
252         outb(TIMER_MODE, mode); 
253         outb(TIMER_CNTR0, divisor & 0xff);
254         outb(TIMER_CNTR0, (divisor >> 8) );
255         system_timing.pit_mode = SINIT(mode);
256         system_timing.pit_divisor = SINIT(divisor);
257         // cprintf("timer mode set to %d, divisor %d\n",mode, divisor);
258 }
259
260 static int getpit()
261 {
262     int high, low;
263         // TODO: need a lock to protect access to PIT
264
265     /* Select counter 0 and latch counter value. */
266     outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
267     
268     low = inb(TIMER_CNTR0);
269     high = inb(TIMER_CNTR0);
270
271     return ((high << 8) | low);
272 }
273
274 // forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
275 void udelay(uint64_t usec)
276 {
277         #if !defined(__BOCHS__)
278         if (system_timing.tsc_freq != 0)
279         {
280                 uint64_t start, end, now;
281
282                 start = read_tsc();
283         end = start + usec2tsc(usec);
284         //cprintf("start %llu, end %llu\n", start, end);
285                 if (end == 0) cprintf("This is terribly wrong \n");
286                 do {
287             cpu_relax();
288             now = read_tsc();
289                         //cprintf("now %llu\n", now);
290                 } while (now < end || (now > start && end < start));
291         return;
292
293         } else
294         #endif
295         {
296                 udelay_pit(usec);
297         }
298 }
299
300 void udelay_pit(uint64_t usec)
301 {
302         
303         int64_t delta, prev_tick, tick, ticks_left;
304         prev_tick = getpit();
305         /*
306          * Calculate (n * (i8254_freq / 1e6)) without using floating point
307          * and without any avoidable overflows.
308          */
309         if (usec <= 0)
310                 ticks_left = 0;
311         // some optimization from bsd code
312         else if (usec < 256)
313                 /*
314                  * Use fixed point to avoid a slow division by 1000000.
315                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
316                  * 2^15 is the first power of 2 that gives exact results
317                  * for n between 0 and 256.
318                  */
319                 ticks_left = ((uint64_t)usec * 39099 + (1 << 15) - 1) >> 15;
320         else
321                 // round up the ticks left
322                 ticks_left = ((uint64_t)usec * (long long)PIT_FREQ+ 999999)
323                              / 1000000; 
324         while (ticks_left > 0) {
325                 tick = getpit();
326                 delta = prev_tick - tick;
327                 prev_tick = tick;
328                 if (delta < 0) {
329                         // counter looped around during the delta time period
330                         delta += system_timing.pit_divisor; // maximum count 
331                         if (delta < 0)
332                                 delta = 0;
333                 }
334                 ticks_left -= delta;
335         }
336 }
337
338 uint64_t gettimer(void)
339 {
340         return read_tsc();      
341 }
342
343 uint64_t getfreq(void)
344 {
345         return system_timing.tsc_freq;
346 }