NMIs and cross-core trapframe inspection
[akaros.git] / kern / arch / i686 / apic.h
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 #ifndef ROS_KERN_APIC_H
8 #define ROS_KERN_APIC_H
9
10 /* 
11  * Functions and definitions for dealing with the APIC and PIC, specific to
12  * Intel.  Does not handle an x2APIC.
13  */
14
15 #include <arch/mmu.h>
16 #include <arch/x86.h>
17 #include <arch/ioapic.h>
18
19 // PIC
20 #define PIC1_CMD                                        0x20
21 #define PIC1_DATA                                       0x21
22 #define PIC2_CMD                                        0xA0
23 #define PIC2_DATA                                       0xA1
24 // These are also hardcoded into the IRQ_HANDLERs of kern/trapentry.S
25 #define PIC1_OFFSET                                     0x20
26 #define PIC2_OFFSET                                     0x28
27 #define PIC_EOI                                         0x20
28
29 // Local APIC
30 #define LAPIC_BASE                                      0xfee00000 // this is the default, can be changed
31 #define LAPIC_EOI                                       (LAPIC_BASE + 0x0b0)
32 #define LAPIC_SPURIOUS                          (LAPIC_BASE + 0x0f0)
33 #define LAPIC_VERSION                           (LAPIC_BASE + 0x030)
34 #define LAPIC_ERROR                                     (LAPIC_BASE + 0x280)
35 #define LAPIC_ID                                        (LAPIC_BASE + 0x020)
36 #define LAPIC_LOGICAL_ID                        (LAPIC_BASE + 0x0d0)
37 // LAPIC Local Vector Table
38 #define LAPIC_LVT_TIMER                         (LAPIC_BASE + 0x320)
39 #define LAPIC_LVT_LINT0                         (LAPIC_BASE + 0x350)
40 #define LAPIC_LVT_LINT1                         (LAPIC_BASE + 0x360)
41 #define LAPIC_LVT_ERROR                         (LAPIC_BASE + 0x370)
42 #define LAPIC_LVT_PERFMON                       (LAPIC_BASE + 0x340)
43 #define LAPIC_LVT_THERMAL                       (LAPIC_BASE + 0x330)
44 #define LAPIC_LVT_MASK                          0x00010000
45 // LAPIC Timer
46 #define LAPIC_TIMER_INIT                        (LAPIC_BASE + 0x380)
47 #define LAPIC_TIMER_CURRENT                     (LAPIC_BASE + 0x390)
48 #define LAPIC_TIMER_DIVIDE                      (LAPIC_BASE + 0x3e0)
49 #define LAPIC_TIMER_DEFAULT_VECTOR      0xeb            /* Aka 235, IRQ203 */
50 #define LAPIC_TIMER_DEFAULT_DIVISOR     0xa // This is 128.  Ref SDM 3.a 9.6.4
51 // IPI Interrupt Command Register
52 #define LAPIC_IPI_ICR_LOWER                     (LAPIC_BASE + 0x300)
53 #define LAPIC_IPI_ICR_UPPER                     (LAPIC_BASE + 0x310)
54 // Interrupts being serviced (in-service) and pending (interrupt request reg)
55 #define LAPIC_ISR                                       (LAPIC_BASE + 0x170)
56 #define LAPIC_IRR                                       (LAPIC_BASE + 0x310)
57
58 // PIT (Programmable Interval Timer)
59 #define TIMER_REG_CNTR0 0       /* timer 0 counter port */
60 #define TIMER_REG_CNTR1 1       /* timer 1 counter port */
61 #define TIMER_REG_CNTR2 2       /* timer 2 counter port */
62 #define TIMER_REG_MODE  3       /* timer mode port */
63 #define TIMER_SEL0      0x00    /* select counter 0 */
64 #define TIMER_SEL1      0x40    /* select counter 1 */
65 #define TIMER_SEL2      0x80    /* select counter 2 */
66 #define TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
67 #define TIMER_ONESHOT   0x02    /* mode 1, one shot */
68 #define TIMER_RATEGEN   0x04    /* mode 2, rate generator */
69 #define TIMER_SQWAVE    0x06    /* mode 3, square wave */
70 #define TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
71 #define TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
72 #define TIMER_LATCH     0x00    /* latch counter for reading */
73 #define TIMER_LSB       0x10    /* r/w counter LSB */
74 #define TIMER_MSB       0x20    /* r/w counter MSB */
75 #define TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
76 #define TIMER_BCD       0x01    /* count in BCD */
77
78 #define PIT_FREQ                                        1193182
79
80 #define IO_TIMER1   0x40        /* 8253 Timer #1 */
81 #define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
82 #define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
83 #define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
84 #define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
85
86 typedef struct system_timing {
87         uint64_t tsc_freq;
88         uint64_t bus_freq;
89         uint16_t pit_divisor;
90         uint8_t pit_mode;
91 } system_timing_t;
92
93 extern system_timing_t system_timing;
94
95 void pic_remap(void);
96 void pic_mask_irq(uint8_t irq);
97 void pic_unmask_irq(uint8_t irq);
98 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
99 void lapic_set_timer(uint32_t usec, bool periodic);
100 uint32_t lapic_get_default_id(void);
101 // PIT related
102 void pit_set_timer(uint32_t freq, uint32_t mode);
103 void timer_init(void);
104 void udelay_pit(uint64_t usec);
105 // TODO: right now timer defaults to TSC
106 uint64_t gettimer(void);
107 uint64_t getfreq(void);
108
109 static inline void pic_send_eoi(uint32_t irq);
110 static inline void lapic_send_eoi(void);
111 static inline uint32_t lapic_get_version(void);
112 static inline uint32_t lapic_get_error(void);
113 static inline uint32_t lapic_get_id(void);
114 static inline void lapic_set_id(uint8_t id); // Careful, may not actually work
115 static inline uint8_t lapic_get_logid(void);
116 static inline void lapic_set_logid(uint8_t id);
117 static inline void lapic_disable_timer(void);
118 static inline void lapic_disable(void);
119 static inline void lapic_enable(void);
120 static inline void lapic_wait_to_send(void);
121 static inline void send_init_ipi(void);
122 static inline void send_startup_ipi(uint8_t vector);
123 static inline void send_self_ipi(uint8_t vector);
124 static inline void send_broadcast_ipi(uint8_t vector);
125 static inline void send_all_others_ipi(uint8_t vector);
126 static inline void send_ipi(uint8_t hw_coreid, uint8_t vector);
127 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
128 static inline void __send_nmi(uint8_t os_coreid);
129 static inline bool ipi_is_pending(uint8_t vector);
130
131 #define mask_lapic_lvt(entry) \
132         write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
133 #define unmask_lapic_lvt(entry) \
134         write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
135
136 static inline void pic_send_eoi(uint32_t irq)
137 {
138         // all irqs beyond the first seven need to be chained to the slave
139         if (irq > 7)
140                 outb(PIC2_CMD, PIC_EOI);
141         outb(PIC1_CMD, PIC_EOI);
142 }
143
144 static inline void lapic_send_eoi(void)
145 {
146         write_mmreg32(LAPIC_EOI, 0);
147 }
148
149 static inline uint32_t lapic_get_version(void)
150 {
151         return read_mmreg32(LAPIC_VERSION);     
152 }
153
154 static inline uint32_t lapic_get_error(void)
155 {
156         write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
157         return read_mmreg32(LAPIC_ERROR);
158 }
159
160 static inline uint32_t lapic_get_id(void)
161 {
162         return read_mmreg32(LAPIC_ID) >> 24;
163 }
164
165 static inline void lapic_set_id(uint8_t id)
166 {
167         write_mmreg32(LAPIC_ID, id << 24);
168 }
169
170 static inline uint8_t lapic_get_logid(void)
171 {
172         return read_mmreg32(LAPIC_LOGICAL_ID) >> 24;
173 }
174
175 static inline void lapic_set_logid(uint8_t id)
176 {
177         write_mmreg32(LAPIC_LOGICAL_ID, id << 24);
178 }
179
180 static inline void lapic_disable_timer(void)
181 {
182         write_mmreg32(LAPIC_LVT_TIMER, 0);
183 }
184
185 /* There are a couple ways to do it.  The MSR route doesn't seem to work
186  * in KVM.  It's also a somewhat permanent thing
187  */
188 static inline void lapic_disable(void)
189 {
190         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
191         //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
192 }
193
194 /* Spins until previous IPIs are delivered.  Not sure if we want it inlined
195  * Also not sure when we really need to do this. 
196  */
197 static inline void lapic_wait_to_send(void)
198 {
199         while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
200                 __cpu_relax();
201 }
202
203 static inline void lapic_enable(void)
204 {
205         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00000100);
206 }
207
208 static inline void send_init_ipi(void)
209 {
210         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
211         lapic_wait_to_send();
212 }
213
214 static inline void send_startup_ipi(uint8_t vector)
215 {
216         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
217         lapic_wait_to_send();
218 }
219
220 static inline void send_self_ipi(uint8_t vector)
221 {
222         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
223         lapic_wait_to_send();
224 }
225
226 static inline void send_broadcast_ipi(uint8_t vector)
227 {
228         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
229         lapic_wait_to_send();
230 }
231
232 static inline void send_all_others_ipi(uint8_t vector)
233 {
234         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
235         lapic_wait_to_send();
236 }
237
238 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
239 {
240         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
241         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | vector);
242         lapic_wait_to_send();
243 }
244
245 static inline void send_ipi(uint8_t hw_coreid, uint8_t vector)
246 {
247         /* 255 is a broadcast, which should use send_broadcast_ipi, and it is also
248          * what would come in if you tried sending an IPI to an os_coreid that
249          * doesn't exist (since they are initialized to -1). */
250         if (hw_coreid == 255)
251                 return;
252         __send_ipi(hw_coreid, vector);
253 }
254
255 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
256 {
257         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_groupid << 24);
258         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004800 | vector);
259         lapic_wait_to_send();
260 }
261
262 static inline void __send_nmi(uint8_t hw_coreid)
263 {
264         if (hw_coreid == 255)
265                 return;
266         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
267         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004400);
268         lapic_wait_to_send();
269 }
270
271 /* This works for any interrupt that goes through the LAPIC, but not things like
272  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now. */
273 static inline bool ipi_is_pending(uint8_t vector)
274 {
275         return (LAPIC_ISR & vector) || (LAPIC_IRR & vector);
276 }
277
278 /* To change the LAPIC Base (not recommended):
279         msr_val = read_msr(IA32_APIC_BASE);
280         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
281         write_msr(IA32_APIC_BASE, msr_val);
282 */
283 #endif /* ROS_KERN_APIC_H */