BXE: min->MIN, plus an spatch
[akaros.git] / kern / arch / x86 / 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 #include <arch/mmu.h>
15 #include <arch/x86.h>
16 #include <ros/trapframe.h>
17 #include <atomic.h>
18 #include <endian.h>
19
20 // Local APIC
21 /* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE.
22  * 64 bit note: it looks like this is mapped to the same place in 64 bit address
23  * spaces.  We just happen to have a slight 'hole' in addressable physical
24  * memory.  We can move the PBASE, but we're limited to 32 bit (physical)
25  * addresses. */
26 #define LAPIC_PBASE                                     0xfee00000      /* default *physical* address */
27 #define LAPIC_EOI                                       (LAPIC_BASE + 0x0b0)
28 #define LAPIC_SPURIOUS                          (LAPIC_BASE + 0x0f0)
29 #define LAPIC_VERSION                           (LAPIC_BASE + 0x030)
30 #define LAPIC_ERROR                                     (LAPIC_BASE + 0x280)
31 #define LAPIC_ID                                        (LAPIC_BASE + 0x020)
32 #define LAPIC_LOGICAL_ID                        (LAPIC_BASE + 0x0d0)
33 // LAPIC Local Vector Table
34 #define LAPIC_LVT_TIMER                         (LAPIC_BASE + 0x320)
35 #define LAPIC_LVT_THERMAL                       (LAPIC_BASE + 0x330)
36 #define LAPIC_LVT_PERFMON                       (LAPIC_BASE + 0x340)
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_MASK                          0x00010000
41 // LAPIC Timer
42 #define LAPIC_TIMER_INIT                        (LAPIC_BASE + 0x380)
43 #define LAPIC_TIMER_CURRENT                     (LAPIC_BASE + 0x390)
44 #define LAPIC_TIMER_DIVIDE                      (LAPIC_BASE + 0x3e0)
45 /* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
46  * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
47  * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
48  * and decreases the granularity of the timer.  Numbers are appx, based on 4
49  * billion ticks, vs 2^32 ticks.
50  * Ex:   1GHz bus, div 001:    4sec max,    1ns granularity
51  * Ex:   1GHz bus, div 128:  512sec max,  128ns granularity
52  * Ex: 100MHz bus, div 001:   40sec max,   10ns granularity
53  * Ex: 100MHz bus, div 128: 5120sec max, 1280ns granularity */
54 #define LAPIC_TIMER_DIVISOR_VAL         32      /* seems reasonable */
55 #define LAPIC_TIMER_DIVISOR_BITS        0x8     /* Div = 32 */
56
57 // IPI Interrupt Command Register
58 #define LAPIC_IPI_ICR_LOWER                     (LAPIC_BASE + 0x300)
59 #define LAPIC_IPI_ICR_UPPER                     (LAPIC_BASE + 0x310)
60 /* Interrupts being serviced (in-service) and pending (interrupt request reg).
61  * Note these registers are not normal bitmaps, but instead are 8 separate
62  * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
63  * space. */
64 #define LAPIC_ISR                                       (LAPIC_BASE + 0x100)
65 #define LAPIC_IRR                                       (LAPIC_BASE + 0x200)
66
67 struct irq_handler;     /* include loops */
68
69 bool lapic_check_spurious(int trap_nr);
70 bool lapic_get_isr_bit(uint8_t vector);
71 bool lapic_get_irr_bit(uint8_t vector);
72 void lapic_print_isr(void);
73 void lapic_mask_irq(struct irq_handler *unused, int apic_vector);
74 void lapic_unmask_irq(struct irq_handler *unused, int apic_vector);
75 bool ipi_is_pending(uint8_t vector);
76 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
77 void lapic_set_timer(uint32_t usec, bool periodic);
78 uint32_t lapic_get_default_id(void);
79 int apiconline(void);
80 void handle_lapic_error(struct hw_trapframe *hw_tf, void *data);
81
82 static inline void lapic_send_eoi(int unused);
83 static inline uint32_t lapic_get_version(void);
84 static inline uint32_t lapic_get_error(void);
85 static inline uint32_t lapic_get_id(void);
86 static inline void lapic_set_id(uint8_t id);    // Careful, may not actually work
87 static inline uint8_t lapic_get_logid(void);
88 static inline void lapic_set_logid(uint8_t id);
89 static inline void lapic_disable_timer(void);
90 static inline void lapic_disable(void);
91 static inline void lapic_enable(void);
92 static inline void lapic_wait_to_send(void);
93 static inline void send_init_ipi(void);
94 static inline void send_startup_ipi(uint8_t vector);
95 static inline void send_self_ipi(uint8_t vector);
96 static inline void send_broadcast_ipi(uint8_t vector);
97 static inline void send_all_others_ipi(uint8_t vector);
98 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector);
99 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
100 static inline void __send_nmi(uint8_t hw_coreid);
101
102 /* XXX: remove these */
103 #define mask_lapic_lvt(entry) \
104         write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
105 #define unmask_lapic_lvt(entry) \
106         write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
107
108 static inline void lapic_send_eoi(int unused)
109 {
110         write_mmreg32(LAPIC_EOI, 0);
111 }
112
113 static inline uint32_t lapic_get_version(void)
114 {
115         return read_mmreg32(LAPIC_VERSION);
116 }
117
118 static inline uint32_t lapic_get_error(void)
119 {
120         write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
121         return read_mmreg32(LAPIC_ERROR);
122 }
123
124 static inline uint32_t lapic_get_id(void)
125 {
126         return read_mmreg32(LAPIC_ID) >> 24;
127 }
128
129 static inline void lapic_set_id(uint8_t id)
130 {
131         write_mmreg32(LAPIC_ID, id << 24);
132 }
133
134 static inline uint8_t lapic_get_logid(void)
135 {
136         return read_mmreg32(LAPIC_LOGICAL_ID) >> 24;
137 }
138
139 static inline void lapic_set_logid(uint8_t id)
140 {
141         write_mmreg32(LAPIC_LOGICAL_ID, id << 24);
142 }
143
144 static inline void lapic_disable_timer(void)
145 {
146         write_mmreg32(LAPIC_LVT_TIMER, 0);
147 }
148
149 /* There are a couple ways to do it.  The MSR route doesn't seem to work
150  * in KVM.  It's also a somewhat permanent thing
151  */
152 static inline void lapic_disable(void)
153 {
154         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
155         //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
156 }
157
158 /* Spins until previous IPIs are delivered.  Not sure if we want it inlined
159  * Also not sure when we really need to do this. 
160  */
161 static inline void lapic_wait_to_send(void)
162 {
163         while (read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
164                 __cpu_relax();
165 }
166
167 static inline void lapic_enable(void)
168 {
169         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00000100);
170 }
171
172 static inline void send_init_ipi(void)
173 {
174         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
175         lapic_wait_to_send();
176 }
177
178 static inline void send_startup_ipi(uint8_t vector)
179 {
180         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
181         lapic_wait_to_send();
182 }
183
184 static inline void send_self_ipi(uint8_t vector)
185 {
186         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
187         lapic_wait_to_send();
188 }
189
190 static inline void send_broadcast_ipi(uint8_t vector)
191 {
192         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
193         lapic_wait_to_send();
194 }
195
196 static inline void send_all_others_ipi(uint8_t vector)
197 {
198         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
199         lapic_wait_to_send();
200 }
201
202 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
203 {
204         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
205         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | vector);
206         lapic_wait_to_send();
207 }
208
209 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
210 {
211         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_groupid << 24);
212         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004800 | vector);
213         lapic_wait_to_send();
214 }
215
216 static inline void __send_nmi(uint8_t hw_coreid)
217 {
218         if (hw_coreid == 255)
219                 return;
220         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
221         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004400);
222         lapic_wait_to_send();
223 }
224
225 /* To change the LAPIC Base (not recommended):
226         msr_val = read_msr(IA32_APIC_BASE);
227         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
228         write_msr(IA32_APIC_BASE, msr_val);
229 */
230
231 /* 
232  * This file is part of the UCB release of Plan 9. It is subject to the license
233  * terms in the LICENSE file found in the top-level directory of this
234  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
235  * part of the UCB release of Plan 9, including this file, may be copied,
236  * modified, propagated, or distributed except according to the terms contained
237  * in the LICENSE file.
238  */
239
240 /*
241  * There are 2 flavours of APIC, Local APIC and IOAPIC,
242  * Each I/O APIC has a unique physical address,
243  * Local APICs are all at the same physical address as they can only be
244  * accessed by the local CPU.  APIC ids are unique to the
245  * APIC type, so an IOAPIC and APIC both with id 0 is ok.
246  */
247
248 struct ioapic {
249         spinlock_t lock;                        /* IOAPIC: register access */
250         uintptr_t addr;                         /* IOAPIC: register base */
251         uintptr_t paddr;                        /* register base */
252         int nrdt;                                       /* IOAPIC: size of RDT */
253         int ibase;                                      /* global interrupt base */
254 };
255
256 struct lapic {
257         int machno;                                     /* similar to os_coreid, unused */
258
259         uint32_t lvt[8];
260         int nlvt;
261         int ver;
262 };
263
264 struct apic {
265         int useable;                            /* en */
266         struct ioapic;
267         struct lapic;
268 };
269
270 enum {
271         Nbus = 256,
272         Napic = 254,    /* xAPIC architectural limit */
273         Nrdt = 64,
274 };
275
276 /*
277  * Common bits for
278  *      IOAPIC Redirection Table Entry (RDT);
279  *      APIC Local Vector Table Entry (LVT);
280  *      APIC Interrupt Command Register (ICR).
281  * [10:8] Message Type
282  * [11] Destination Mode (RW)
283  * [12] Delivery Status (RO)
284  * [13] Interrupt Input Pin Polarity (RW)
285  * [14] Remote IRR (RO)
286  * [15] Trigger Mode (RW)
287  * [16] Interrupt Mask
288  */
289 enum {
290         MTf = 0x00000000,                       /* Fixed */
291         MTlp = 0x00000100,      /* Lowest Priority */
292         MTsmi = 0x00000200,     /* SMI */
293         MTrr = 0x00000300,      /* Remote Read */
294         MTnmi = 0x00000400,     /* NMI */
295         MTir = 0x00000500,      /* INIT/RESET */
296         MTsipi = 0x00000600,    /* Startup IPI */
297         MTei = 0x00000700,      /* ExtINT */
298
299         Pm = 0x00000000,        /* Physical Mode */
300         Lm = 0x00000800,        /* Logical Mode */
301
302         Ds = 0x00001000,        /* Delivery Status */
303         IPhigh = 0x00000000,    /* IIPP High */
304         IPlow = 0x00002000,     /* IIPP Low */
305         Rirr = 0x00004000,      /* Remote IRR */
306         TMedge = 0x00000000,    /* Trigger Mode Edge */
307         TMlevel = 0x00008000,   /* Trigger Mode Level */
308         Im = 0x00010000,        /* Interrupt Mask */
309 };
310
311 extern struct apic xlapic[Napic];
312 extern struct apic xioapic[Napic];
313
314 #include <arch/ioapic.h>
315
316 char *apicdump(char *, char *);
317 void apictimerenab(void);
318 void apicinit(int apicno, uintptr_t pa, int isbp);
319
320 #endif /* ROS_KERN_APIC_H */