Unmap pages mapped during a failed fill_vmr()
[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 }
133
134 static inline void lapic_enable(void)
135 {
136         apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) | 0x00000100);
137 }
138
139 static inline void send_init_ipi(void)
140 {
141         apicsendipi(0xFFFFFFFF000c4500);
142 }
143
144 static inline void send_startup_ipi(uint8_t vector)
145 {
146         apicsendipi(0xFFFFFFFF000c4600ULL | vector);
147 }
148
149 static inline void send_self_ipi(uint8_t vector)
150 {
151         apicrput(MSR_LAPIC_SELF_IPI, 0x00000000 | vector);
152 }
153
154 static inline void send_broadcast_ipi(uint8_t vector)
155 {
156         apicsendipi(0xFFFFFFFF00084000ULL | vector);
157 }
158
159 static inline void send_all_others_ipi(uint8_t vector)
160 {
161         apicsendipi(0xFFFFFFFF000c4000ULL | vector);
162 }
163
164 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
165 {
166         apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004000 | vector);
167 }
168
169 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
170 {
171         apicsendipi(((uint64_t)hw_groupid << 32) | 0x00004800 | vector);
172 }
173
174 static inline void __send_nmi(uint8_t hw_coreid)
175 {
176         if (hw_coreid == 255)
177                 return;
178         apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004400);
179 }
180
181 /* To change the LAPIC Base (not recommended):
182         msr_val = read_msr(IA32_APIC_BASE);
183         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
184         write_msr(IA32_APIC_BASE, msr_val);
185 */
186
187 /*
188  * This file is part of the UCB release of Plan 9. It is subject to the license
189  * terms in the LICENSE file found in the top-level directory of this
190  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
191  * part of the UCB release of Plan 9, including this file, may be copied,
192  * modified, propagated, or distributed except according to the terms contained
193  * in the LICENSE file.
194  */
195
196 /*
197  * There are 2 flavours of APIC, Local APIC and IOAPIC,
198  * Each I/O APIC has a unique physical address,
199  * Local APICs are all at the same physical address as they can only be
200  * accessed by the local CPU.  APIC ids are unique to the
201  * APIC type, so an IOAPIC and APIC both with id 0 is ok.
202  */
203
204 struct ioapic {
205         spinlock_t lock;        /* IOAPIC: register access */
206         uintptr_t addr;         /* IOAPIC: register base */
207         uintptr_t paddr;        /* register base */
208         int nrdt;               /* IOAPIC: size of RDT */
209         int ibase;              /* global interrupt base */
210 };
211
212 struct lapic {
213         int machno;             /* similar to os_coreid, unused */
214
215         uint32_t lvt[8];
216         int nlvt;
217         int ver;
218 };
219
220 struct apic {
221         int useable;                            /* en */
222         struct ioapic;
223         struct lapic;
224 };
225
226 enum {
227         Nbus = 256,
228         Napic = 254,    /* xAPIC architectural limit */
229         Nrdt = 64,
230 };
231
232 /*
233  * Common bits for
234  *      IOAPIC Redirection Table Entry (RDT);
235  *      APIC Local Vector Table Entry (LVT);
236  *      APIC Interrupt Command Register (ICR).
237  * [10:8] Message Type
238  * [11] Destination Mode (RW)
239  * [12] Delivery Status (RO)
240  * [13] Interrupt Input Pin Polarity (RW)
241  * [14] Remote IRR (RO)
242  * [15] Trigger Mode (RW)
243  * [16] Interrupt Mask
244  */
245 enum {
246         MTf = 0x00000000,       /* Fixed */
247         MTlp = 0x00000100,      /* Lowest Priority */
248         MTsmi = 0x00000200,     /* SMI */
249         MTrr = 0x00000300,      /* Remote Read */
250         MTnmi = 0x00000400,     /* NMI */
251         MTir = 0x00000500,      /* INIT/RESET */
252         MTsipi = 0x00000600,    /* Startup IPI */
253         MTei = 0x00000700,      /* ExtINT */
254
255         Pm = 0x00000000,        /* Physical Mode */
256         Lm = 0x00000800,        /* Logical Mode */
257
258         Ds = 0x00001000,        /* Delivery Status */
259         IPhigh = 0x00000000,    /* IIPP High */
260         IPlow = 0x00002000,     /* IIPP Low */
261         Rirr = 0x00004000,      /* Remote IRR */
262         TMedge = 0x00000000,    /* Trigger Mode Edge */
263         TMlevel = 0x00008000,   /* Trigger Mode Level */
264         Im = 0x00010000,        /* Interrupt Mask */
265 };
266
267 extern struct apic xlapic[Napic];
268 extern struct apic xioapic[Napic];
269
270 #include <arch/ioapic.h>
271
272 char *apicdump(char *, char *);
273 void apictimerenab(void);
274 void apicinit(int apicno, uintptr_t pa, int isbp);