timer works in bochs and on physical machine. need global definition for bochs...
[akaros.git] / kern / apic.h
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * See LICENSE for details.
4  */
5
6 #ifndef ROS_KERN_APIC_H
7 #define ROS_KERN_APIC_H
8
9 /* 
10  * Functions and definitions for dealing with the APIC and PIC, specific to
11  * Intel.  Does not handle an x2APIC.
12  */
13
14 #include <inc/mmu.h>
15 #include <inc/x86.h>
16
17 // PIC
18 #define PIC1_CMD                                        0x20
19 #define PIC1_DATA                                       0x21
20 #define PIC2_CMD                                        0xA0
21 #define PIC2_DATA                                       0xA1
22 // These are also hardcoded into the IRQ_HANDLERs of kern/trapentry.S
23 #define PIC1_OFFSET                                     0x20
24 #define PIC2_OFFSET                                     0x28
25 #define PIC_EOI                                         0x20
26
27 // Local APIC
28 #define LAPIC_BASE                                      0xfee00000 // this is the default, can be changed
29 #define LAPIC_EOI                                       (LAPIC_BASE + 0x0b0)
30 #define LAPIC_SPURIOUS                          (LAPIC_BASE + 0x0f0)
31 #define LAPIC_VERSION                           (LAPIC_BASE + 0x030)
32 #define LAPIC_ERROR                                     (LAPIC_BASE + 0x280)
33 #define LAPIC_ID                                        (LAPIC_BASE + 0x020)
34 #define LAPIC_LOGICAL_ID                        (LAPIC_BASE + 0x0d0)
35 // LAPIC Local Vector Table
36 #define LAPIC_LVT_TIMER                         (LAPIC_BASE + 0x320)
37 #define LAPIC_LVT_LINT0                         (LAPIC_BASE + 0x350)
38 #define LAPIC_LVT_LINT1                         (LAPIC_BASE + 0x360)
39 #define LAPIC_LVT_ERROR                         (LAPIC_BASE + 0x370)
40 #define LAPIC_LVT_PERFMON                       (LAPIC_BASE + 0x340)
41 #define LAPIC_LVT_THERMAL                       (LAPIC_BASE + 0x330)
42 #define LAPIC_LVT_MASK                          0x00010000
43 // LAPIC Timer
44 #define LAPIC_TIMER_INIT                        (LAPIC_BASE + 0x380)
45 #define LAPIC_TIMER_CURRENT                     (LAPIC_BASE + 0x390)
46 #define LAPIC_TIMER_DIVIDE                      (LAPIC_BASE + 0x3e0)
47 // IPI Interrupt Command Register
48 #define LAPIC_IPI_ICR_LOWER                     (LAPIC_BASE + 0x300)
49 #define LAPIC_IPI_ICR_UPPER                     (LAPIC_BASE + 0x310)
50
51 // IOAPIC
52 #define IOAPIC_BASE                                     0xfec00000 // this is the default, can be changed
53
54 // PIT (Programmable Interval Timer)
55 #define TIMER_REG_CNTR0 0       /* timer 0 counter port */
56 #define TIMER_REG_CNTR1 1       /* timer 1 counter port */
57 #define TIMER_REG_CNTR2 2       /* timer 2 counter port */
58 #define TIMER_REG_MODE  3       /* timer mode port */
59 #define TIMER_SEL0      0x00    /* select counter 0 */
60 #define TIMER_SEL1      0x40    /* select counter 1 */
61 #define TIMER_SEL2      0x80    /* select counter 2 */
62 #define TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
63 #define TIMER_ONESHOT   0x02    /* mode 1, one shot */
64 #define TIMER_RATEGEN   0x04    /* mode 2, rate generator */
65 #define TIMER_SQWAVE    0x06    /* mode 3, square wave */
66 #define TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
67 #define TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
68 #define TIMER_LATCH     0x00    /* latch counter for reading */
69 #define TIMER_LSB       0x10    /* r/w counter LSB */
70 #define TIMER_MSB       0x20    /* r/w counter MSB */
71 #define TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
72 #define TIMER_BCD       0x01    /* count in BCD */
73
74 #define PIT_FREQ                                        1193182
75
76 #define IO_TIMER1   0x40        /* 8253 Timer #1 */
77 #define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
78 #define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
79 #define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
80 #define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
81
82 extern uint64_t tsc_freq;
83
84 void pic_remap(void);
85 void pic_mask_irq(uint8_t irq);
86 void pic_unmask_irq(uint8_t irq);
87 void lapic_set_timer(uint32_t ticks, uint8_t vector, bool periodic);
88 uint32_t lapic_get_default_id(void);
89 // PIT related
90 void pit_set_timer(uint32_t freq, uint32_t mode, bool periodic); // consider adding callback func
91 void timer_init(void);
92 void udelay(uint64_t usec);
93
94 static int getpit(void);
95 void udelay_pit(uint64_t usec);
96
97
98 static inline void pic_send_eoi(uint32_t irq);
99 static inline void lapic_send_eoi(void);
100 static inline uint32_t lapic_get_version(void);
101 static inline uint32_t lapic_get_error(void);
102 static inline uint32_t lapic_get_id(void);
103 static inline uint8_t lapic_get_logid(void);
104 static inline void lapic_set_logid(uint8_t id);
105 static inline void lapic_disable(void);
106 static inline void lapic_enable(void);
107 static inline void lapic_wait_to_send(void);
108 static inline void send_init_ipi(void);
109 static inline void send_startup_ipi(uint8_t vector);
110 static inline void send_self_ipi(uint8_t vector);
111 static inline void send_broadcast_ipi(uint8_t vector);
112 static inline void send_all_others_ipi(uint8_t vector);
113 static inline void send_ipi(uint8_t dest, bool logical_mode, uint8_t vector);
114
115 #define mask_lapic_lvt(entry) \
116         write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
117 #define unmask_lapic_lvt(entry) \
118         write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
119
120 static inline void pic_send_eoi(uint32_t irq)
121 {
122         // all irqs beyond the first seven need to be chained to the slave
123         if (irq > 7)
124                 outb(PIC2_CMD, PIC_EOI);
125         outb(PIC1_CMD, PIC_EOI);
126 }
127
128 static inline void lapic_send_eoi(void)
129 {
130         write_mmreg32(LAPIC_EOI, 0);
131 }
132
133 static inline uint32_t lapic_get_version(void)
134 {
135         return read_mmreg32(LAPIC_VERSION);     
136 }
137
138 static inline uint32_t lapic_get_error(void)
139 {
140         write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
141         return read_mmreg32(LAPIC_ERROR);
142 }
143
144 static inline uint32_t lapic_get_id(void)
145 {
146         return read_mmreg32(LAPIC_ID) >> 24;
147 }
148
149 static inline uint8_t lapic_get_logid(void)
150 {
151         return read_mmreg32(LAPIC_LOGICAL_ID) >> 24;
152 }
153
154 static inline void lapic_set_logid(uint8_t id)
155 {
156         write_mmreg32(LAPIC_LOGICAL_ID, id << 24);
157 }
158
159 /* There are a couple ways to do it.  The MSR route doesn't seem to work
160  * in KVM.  It's also a somewhat permanent thing
161  */
162 static inline void lapic_disable(void)
163 {
164         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
165         //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
166 }
167
168 /* Spins until previous IPIs are delivered.  Not sure if we want it inlined
169  * Also not sure when we really need to do this. 
170  */
171 static inline void lapic_wait_to_send(void)
172 {
173         while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
174                 cpu_relax();
175 }
176
177 static inline void lapic_enable(void)
178 {
179         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00000100);
180 }
181
182 static inline void send_init_ipi(void)
183 {
184         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
185 }
186
187 static inline void send_startup_ipi(uint8_t vector)
188 {
189         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
190 }
191
192 static inline void send_self_ipi(uint8_t vector)
193 {
194         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
195 }
196
197 static inline void send_broadcast_ipi(uint8_t vector)
198 {
199         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
200 }
201
202 static inline void send_all_others_ipi(uint8_t vector)
203 {
204         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
205 }
206
207 static inline void send_ipi(uint8_t dest, bool logical_mode, uint8_t vector)
208 {
209         write_mmreg32(LAPIC_IPI_ICR_UPPER, dest << 24);
210         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | (logical_mode << 11) | vector);
211 }
212
213 /* To change the LAPIC Base (not recommended):
214         msr_val = read_msr(IA32_APIC_BASE);
215         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
216         write_msr(IA32_APIC_BASE, msr_val);
217 */
218 #endif /* ROS_KERN_APIC_H */