Enabling X2APIC
[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 #pragma once
8
9 /*
10  * Functions and definitions for dealing with the APIC and PIC, specific to
11  * Intel.  Does not handle an x2APIC.
12  */
13 #include <arch/mmu.h>
14 #include <arch/x86.h>
15 #include <ros/trapframe.h>
16 #include <atomic.h>
17 #include <endian.h>
18 #include <arch/ros/msr-index.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_LVT_MASK                                  0x00010000
28
29 /* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
30  * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
31  * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
32  * and decreases the granularity of the timer.  Numbers are appx, based on 4
33  * billion ticks, vs 2^32 ticks.
34  * Ex:   1GHz bus, div 001:    4sec max,    1ns granularity
35  * Ex:   1GHz bus, div 128:  512sec max,  128ns granularity
36  * Ex: 100MHz bus, div 001:   40sec max,   10ns granularity
37  * Ex: 100MHz bus, div 128: 5120sec max, 1280ns granularity */
38 #define LAPIC_TIMER_DIVISOR_VAL         32      /* seems reasonable */
39 #define LAPIC_TIMER_DIVISOR_BITS        0x8     /* Div = 32 */
40
41 // IPI Interrupt Command Register
42 #define LAPIC_IPI_ICR_LOWER                             0x30
43 #define LAPIC_IPI_ICR_UPPER                             0x31
44 /* Interrupts being serviced (in-service) and pending (interrupt request reg).
45  * Note these registers are not normal bitmaps, but instead are 8 separate
46  * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
47  * space. */
48 #define LAPIC_ISR                                       0x10
49 #define LAPIC_IRR                                       0x20
50 #define LAPIC_DFR                                       0x0e
51
52 struct irq_handler;     /* include loops */
53
54 bool lapic_check_spurious(int trap_nr);
55 bool lapic_get_isr_bit(uint8_t vector);
56 bool lapic_get_irr_bit(uint8_t vector);
57 void lapic_print_isr(void);
58 void lapic_mask_irq(struct irq_handler *unused, int apic_vector);
59 void lapic_unmask_irq(struct irq_handler *unused, int apic_vector);
60 bool ipi_is_pending(uint8_t vector);
61 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
62 void lapic_set_timer(uint32_t usec, bool periodic);
63 uint32_t lapic_get_default_id(void);
64 int apiconline(void);
65 void handle_lapic_error(struct hw_trapframe *hw_tf, void *data);
66 uint32_t apicrget(uint64_t r);
67 void apicrput(uint64_t r, uint32_t data);
68 void apicsendipi(uint64_t data);
69 void apic_isr_dump(void);
70 void apic_irr_dump(void);
71
72 static inline void lapic_send_eoi(int unused);
73 static inline uint32_t lapic_get_version(void);
74 static inline uint32_t lapic_get_error(void);
75 static inline uint32_t lapic_get_id(void);
76 static inline uint8_t lapic_get_logid(void);
77 static inline void lapic_disable_timer(void);
78 static inline void lapic_disable(void);
79 static inline void lapic_enable(void);
80 static inline void send_init_ipi(void);
81 static inline void send_startup_ipi(uint8_t vector);
82 static inline void send_self_ipi(uint8_t vector);
83 static inline void send_broadcast_ipi(uint8_t vector);
84 static inline void send_all_others_ipi(uint8_t vector);
85 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector);
86 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
87 static inline void __send_nmi(uint8_t hw_coreid);
88
89 /* XXX: remove these */
90 #define mask_lapic_lvt(entry) \
91         apicrput(entry, apicrget(entry) | LAPIC_LVT_MASK)
92 #define unmask_lapic_lvt(entry) \
93         apicrput(entry, apicrget(entry) & ~LAPIC_LVT_MASK)
94
95 static inline void lapic_send_eoi(int unused)
96 {
97         apicrput(MSR_LAPIC_EOI, 0);
98 }
99
100 static inline uint32_t lapic_get_version(void)
101 {
102         return apicrget(MSR_LAPIC_VERSION);
103 }
104
105 static inline uint32_t lapic_get_error(void)
106 {
107         apicrput(MSR_LAPIC_ESR, 0xdeadbeef);
108         return apicrget(MSR_LAPIC_ESR);
109 }
110
111 static inline uint32_t lapic_get_id(void)
112 {
113         return apicrget(MSR_LAPIC_ID);
114 }
115
116 static inline uint8_t lapic_get_logid(void)
117 {
118         return apicrget(MSR_LAPIC_LDR);
119 }
120
121 static inline void lapic_disable_timer(void)
122 {
123         apicrput(MSR_LAPIC_LVT_TIMER, 0);
124 }
125
126 /* There are a couple ways to do it.  The MSR route doesn't seem to work
127  * in KVM.  It's also a somewhat permanent thing
128  */
129 static inline void lapic_disable(void)
130 {
131         apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) & 0xffffefff);
132         //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
133 }
134
135 static inline void lapic_enable(void)
136 {
137         apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) | 0x00000100);
138 }
139
140 static inline void send_init_ipi(void)
141 {
142         apicsendipi(0xFFFFFFFF000c4500);
143 }
144
145 static inline void send_startup_ipi(uint8_t vector)
146 {
147         apicsendipi(0xFFFFFFFF000c4600ULL | vector);
148 }
149
150 static inline void send_self_ipi(uint8_t vector)
151 {
152         apicrput(MSR_LAPIC_SELF_IPI, 0x00000000 | vector);
153 }
154
155 static inline void send_broadcast_ipi(uint8_t vector)
156 {
157         apicsendipi(0xFFFFFFFF00084000ULL | vector);
158 }
159
160 static inline void send_all_others_ipi(uint8_t vector)
161 {
162         apicsendipi(0xFFFFFFFF000c4000ULL | vector);
163 }
164
165 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
166 {
167         apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004000 | vector);
168 }
169
170 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
171 {
172         apicsendipi(((uint64_t)hw_groupid << 32) | 0x00004800 | vector);
173 }
174
175 static inline void __send_nmi(uint8_t hw_coreid)
176 {
177         if (hw_coreid == 255)
178                 return;
179         apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004400);
180 }
181
182 /* To change the LAPIC Base (not recommended):
183         msr_val = read_msr(IA32_APIC_BASE);
184         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
185         write_msr(IA32_APIC_BASE, msr_val);
186 */
187
188 /*
189  * This file is part of the UCB release of Plan 9. It is subject to the license
190  * terms in the LICENSE file found in the top-level directory of this
191  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
192  * part of the UCB release of Plan 9, including this file, may be copied,
193  * modified, propagated, or distributed except according to the terms contained
194  * in the LICENSE file.
195  */
196
197 /*
198  * There are 2 flavours of APIC, Local APIC and IOAPIC,
199  * Each I/O APIC has a unique physical address,
200  * Local APICs are all at the same physical address as they can only be
201  * accessed by the local CPU.  APIC ids are unique to the
202  * APIC type, so an IOAPIC and APIC both with id 0 is ok.
203  */
204
205 struct ioapic {
206         spinlock_t lock;                        /* IOAPIC: register access */
207         uintptr_t addr;                         /* IOAPIC: register base */
208         uintptr_t paddr;                        /* register base */
209         int nrdt;                                       /* IOAPIC: size of RDT */
210         int ibase;                                      /* global interrupt base */
211 };
212
213 struct lapic {
214         int machno;                                     /* similar to os_coreid, unused */
215
216         uint32_t lvt[8];
217         int nlvt;
218         int ver;
219 };
220
221 struct apic {
222         int useable;                            /* en */
223         struct ioapic;
224         struct lapic;
225 };
226
227 enum {
228         Nbus = 256,
229         Napic = 254,    /* xAPIC architectural limit */
230         Nrdt = 64,
231 };
232
233 /*
234  * Common bits for
235  *      IOAPIC Redirection Table Entry (RDT);
236  *      APIC Local Vector Table Entry (LVT);
237  *      APIC Interrupt Command Register (ICR).
238  * [10:8] Message Type
239  * [11] Destination Mode (RW)
240  * [12] Delivery Status (RO)
241  * [13] Interrupt Input Pin Polarity (RW)
242  * [14] Remote IRR (RO)
243  * [15] Trigger Mode (RW)
244  * [16] Interrupt Mask
245  */
246 enum {
247         MTf = 0x00000000,                       /* Fixed */
248         MTlp = 0x00000100,      /* Lowest Priority */
249         MTsmi = 0x00000200,     /* SMI */
250         MTrr = 0x00000300,      /* Remote Read */
251         MTnmi = 0x00000400,     /* NMI */
252         MTir = 0x00000500,      /* INIT/RESET */
253         MTsipi = 0x00000600,    /* Startup IPI */
254         MTei = 0x00000700,      /* ExtINT */
255
256         Pm = 0x00000000,        /* Physical Mode */
257         Lm = 0x00000800,        /* Logical Mode */
258
259         Ds = 0x00001000,        /* Delivery Status */
260         IPhigh = 0x00000000,    /* IIPP High */
261         IPlow = 0x00002000,     /* IIPP Low */
262         Rirr = 0x00004000,      /* Remote IRR */
263         TMedge = 0x00000000,    /* Trigger Mode Edge */
264         TMlevel = 0x00008000,   /* Trigger Mode Level */
265         Im = 0x00010000,        /* Interrupt Mask */
266 };
267
268 extern struct apic xlapic[Napic];
269 extern struct apic xioapic[Napic];
270
271 #include <arch/ioapic.h>
272
273 char *apicdump(char *, char *);
274 void apictimerenab(void);
275 void apicinit(int apicno, uintptr_t pa, int isbp);