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