xref: /xnu-10002.61.3/osfmk/i386/lapic.h (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1 /*
2  * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  *
31  */
32 #ifndef _I386_LAPIC_H_
33 #define _I386_LAPIC_H_
34 
35 /*
36  * Legacy mode definitions.
37  * The register offsets are no longer used by XNU - see LAPIC_MMIO_OFFSET().
38  */
39 #define LAPIC_START                     0xFEE00000
40 #define LAPIC_SIZE                      0x00000400
41 
42 #define LAPIC_ID                        0x00000020
43 #define         LAPIC_ID_SHIFT          24
44 #define         LAPIC_ID_MASK           0xFF
45 #define LAPIC_VERSION                   0x00000030
46 #define         LAPIC_VERSION_MASK      0xFF
47 #define LAPIC_TPR                       0x00000080
48 #define         LAPIC_TPR_MASK          0xFF
49 #define LAPIC_APR                       0x00000090
50 #define         LAPIC_APR_MASK          0xFF
51 #define LAPIC_PPR                       0x000000A0
52 #define         LAPIC_PPR_MASK          0xFF
53 #define LAPIC_EOI                       0x000000B0
54 #define LAPIC_REMOTE_READ               0x000000C0
55 #define LAPIC_LDR                       0x000000D0
56 #define         LAPIC_LDR_SHIFT         24
57 #define LAPIC_DFR                       0x000000E0
58 #define         LAPIC_DFR_FLAT          0xFFFFFFFF
59 #define         LAPIC_DFR_CLUSTER       0x0FFFFFFF
60 #define         LAPIC_DFR_SHIFT         28
61 #define LAPIC_SVR                       0x000000F0
62 #define         LAPIC_SVR_MASK          0x0FF
63 #define         LAPIC_SVR_ENABLE        0x100
64 #define         LAPIC_SVR_FOCUS_OFF     0x200
65 #define LAPIC_ISR_BASE                  0x00000100
66 #define LAPIC_TMR_BASE                  0x00000180
67 #define LAPIC_IRR_BASE                  0x00000200
68 #define LAPIC_ERROR_STATUS              0x00000280
69 #define LAPIC_LVT_CMCI                  0x000002F0
70 #define LAPIC_ICR                       0x00000300
71 #define         LAPIC_ICR_VECTOR_MASK   0x000FF
72 #define         LAPIC_ICR_DM_MASK       0x00700
73 #define         LAPIC_ICR_DM_FIXED      0x00000
74 #define         LAPIC_ICR_DM_LOWEST     0x00100
75 #define         LAPIC_ICR_DM_SMI        0x00200
76 #define         LAPIC_ICR_DM_REMOTE     0x00300
77 #define         LAPIC_ICR_DM_NMI        0x00400
78 #define         LAPIC_ICR_DM_INIT       0x00500
79 #define         LAPIC_ICR_DM_STARTUP    0x00600
80 #define         LAPIC_ICR_DM_LOGICAL    0x00800
81 #define         LAPIC_ICR_DS_PENDING    0x01000
82 #define         LAPIC_ICR_LEVEL_ASSERT  0x04000
83 #define         LAPIC_ICR_TRIGGER_LEVEL 0x08000
84 #define         LAPIC_ICR_RR_MASK       0x30000
85 #define         LAPIC_ICR_RR_INVALID    0x00000
86 #define         LAPIC_ICR_RR_INPROGRESS 0x10000
87 #define         LAPIC_ICR_RR_VALID      0x20000
88 #define         LAPIC_ICR_DSS_MASK      0xC0000
89 #define         LAPIC_ICR_DSS_DEST      0x00000
90 #define         LAPIC_ICR_DSS_SELF      0x40000
91 #define         LAPIC_ICR_DSS_ALL       0x80000
92 #define         LAPIC_ICR_DSS_OTHERS    0xC0000
93 #define LAPIC_ICRD                      0x00000310
94 #define         LAPIC_ICRD_DEST_SHIFT   24
95 #define LAPIC_LVT_TIMER                 0x00000320
96 #define LAPIC_LVT_THERMAL               0x00000330
97 #define LAPIC_LVT_PERFCNT               0x00000340
98 #define LAPIC_LVT_LINT0                 0x00000350
99 #define LAPIC_LVT_LINT1                 0x00000360
100 #define LAPIC_LVT_ERROR                 0x00000370
101 #define         LAPIC_LVT_VECTOR_MASK   0x000FF
102 #define         LAPIC_LVT_DM_SHIFT      8
103 #define         LAPIC_LVT_DM_MASK       0x00007
104 #define         LAPIC_LVT_DM_FIXED      0x00000
105 #define         LAPIC_LVT_DM_NMI        0x00400
106 #define         LAPIC_LVT_DM_EXTINT     0x00700
107 #define         LAPIC_LVT_DS_PENDING    0x01000
108 #define         LAPIC_LVT_IP_PLRITY_LOW 0x02000
109 #define         LAPIC_LVT_REMOTE_IRR    0x04000
110 #define         LAPIC_LVT_TM_LEVEL      0x08000
111 #define         LAPIC_LVT_MASKED        0x10000
112 #define         LAPIC_LVT_PERIODIC      0x20000
113 #define         LAPIC_LVT_TSC_DEADLINE  0x40000
114 #define         LAPIC_LVT_TMR_SHIFT     17
115 #define         LAPIC_LVT_TMR_MASK      3
116 #define LAPIC_TIMER_INITIAL_COUNT       0x00000380
117 #define LAPIC_TIMER_CURRENT_COUNT       0x00000390
118 #define LAPIC_TIMER_DIVIDE_CONFIG       0x000003E0
119 /* divisor encoded by bits 0,1,3 with bit 2 always 0: */
120 #define         LAPIC_TIMER_DIVIDE_MASK 0x0000000F
121 #define         LAPIC_TIMER_DIVIDE_2    0x00000000
122 #define         LAPIC_TIMER_DIVIDE_4    0x00000001
123 #define         LAPIC_TIMER_DIVIDE_8    0x00000002
124 #define         LAPIC_TIMER_DIVIDE_16   0x00000003
125 #define         LAPIC_TIMER_DIVIDE_32   0x00000008
126 #define         LAPIC_TIMER_DIVIDE_64   0x00000009
127 #define         LAPIC_TIMER_DIVIDE_128  0x0000000A
128 #define         LAPIC_TIMER_DIVIDE_1    0x0000000B
129 
130 #define LAPIC_ID_MAX                    (LAPIC_ID_MASK)
131 
132 #define CPU_NUMBER(r)                           \
133 	movl	%gs:CPU_NUMBER_GS,r
134 
135 #ifndef ASSEMBLER
136 typedef enum {
137 	ID                      = 0x02,
138 	VERSION                 = 0x03,
139 	TPR                     = 0x08,
140 	APR                     = 0x09,
141 	PPR                     = 0x0A,
142 	EOI                     = 0x0B,
143 	REMOTE_READ             = 0x0C,
144 	LDR                     = 0x0D,
145 	DFR                     = 0x0E,
146 	SVR                     = 0x0F,
147 	ISR_BASE                = 0x10,
148 	TMR_BASE                = 0x18,
149 	IRR_BASE                = 0x20,
150 	ERROR_STATUS            = 0x28,
151 	LVT_CMCI                = 0x2F,
152 	ICR                     = 0x30,
153 	ICRD                    = 0x31,
154 	LVT_TIMER               = 0x32,
155 	LVT_THERMAL             = 0x33,
156 	LVT_PERFCNT             = 0x34,
157 	LVT_LINT0               = 0x35,
158 	LVT_LINT1               = 0x36,
159 	LVT_ERROR               = 0x37,
160 	TIMER_INITIAL_COUNT     = 0x38,
161 	TIMER_CURRENT_COUNT     = 0x39,
162 	TIMER_DIVIDE_CONFIG     = 0x3E,
163 } lapic_register_t;
164 
165 #define LAPIC_MMIO_PBASE        0xFEE00000      /* Default physical MMIO addr */
166 #define LAPIC_MMIO_VBASE        lapic_vbase     /* Actual virtual mapped addr */
167 #define LAPIC_MSR_BASE          0x800
168 
169 #define LAPIC_MMIO_OFFSET(reg)  (reg << 4)
170 #define LAPIC_MSR_OFFSET(reg)   (reg)
171 
172 #define LAPIC_MMIO(reg)         ((volatile uint32_t *) \
173 	                                (LAPIC_MMIO_VBASE + LAPIC_MMIO_OFFSET(reg)))
174 #define LAPIC_MSR(reg)          (LAPIC_MSR_BASE + LAPIC_MSR_OFFSET(reg))
175 
176 typedef struct {
177 	void            (*init)(void);
178 	uint32_t        (*read)(lapic_register_t);
179 	void            (*write)(lapic_register_t, uint32_t);
180 	uint64_t        (*read_icr)(void);
181 	void            (*write_icr)(uint32_t, uint32_t);
182 } lapic_ops_table_t;
183 extern  lapic_ops_table_t *lapic_ops;
184 
185 #define LAPIC_INIT()                    lapic_ops->init();
186 #define LAPIC_WRITE(reg, val)           lapic_ops->write(reg, val)
187 #define LAPIC_READ(reg)                 lapic_ops->read(reg)
188 #define LAPIC_READ_OFFSET(reg, off)     LAPIC_READ((lapic_register_t)((reg)+(off)))
189 #define LAPIC_READ_ICR()                lapic_ops->read_icr()
190 #define LAPIC_WRITE_ICR(dst, cmd)       lapic_ops->write_icr(dst, cmd)
191 
192 typedef enum {
193 	periodic,
194 	one_shot
195 } lapic_timer_mode_t;
196 typedef enum {
197 	divide_by_1   = LAPIC_TIMER_DIVIDE_1,
198 	divide_by_2   = LAPIC_TIMER_DIVIDE_2,
199 	divide_by_4   = LAPIC_TIMER_DIVIDE_4,
200 	divide_by_8   = LAPIC_TIMER_DIVIDE_8,
201 	divide_by_16  = LAPIC_TIMER_DIVIDE_16,
202 	divide_by_32  = LAPIC_TIMER_DIVIDE_32,
203 	divide_by_64  = LAPIC_TIMER_DIVIDE_64,
204 	divide_by_128 = LAPIC_TIMER_DIVIDE_128
205 } lapic_timer_divide_t;
206 typedef uint32_t lapic_timer_count_t;
207 
208 /*
209  * By default, use high vectors to leave vector space for systems
210  * with multiple I/O APIC's. However some systems that boot with
211  * local APIC disabled will hang in SMM when vectors greater than
212  * 0x5F are used. Those systems are not expected to have I/O APIC
213  * so 16 (0x50 - 0x40) vectors for legacy PIC support is perfect.
214  */
215 #define LAPIC_DEFAULT_INTERRUPT_BASE    0xD0
216 #define LAPIC_REDUCED_INTERRUPT_BASE    0x50
217 /*
218  * Specific lapic interrupts are relative to this base
219  * in priority order from high to low:
220  */
221 
222 #define LAPIC_PERFCNT_INTERRUPT         0xF
223 #define LAPIC_INTERPROCESSOR_INTERRUPT  0xE
224 #define LAPIC_TIMER_INTERRUPT           0xD
225 #define LAPIC_THERMAL_INTERRUPT         0xC
226 #define LAPIC_ERROR_INTERRUPT           0xB
227 #define LAPIC_SPURIOUS_INTERRUPT        0xA
228 #define LAPIC_CMCI_INTERRUPT            0x9
229 #define LAPIC_PMC_SW_INTERRUPT          0x8
230 #define LAPIC_PM_INTERRUPT              0x7
231 #define LAPIC_KICK_INTERRUPT            0x6
232 
233 #define LAPIC_PMC_SWI_VECTOR            (LAPIC_DEFAULT_INTERRUPT_BASE + LAPIC_PMC_SW_INTERRUPT)
234 #define LAPIC_TIMER_VECTOR              (LAPIC_DEFAULT_INTERRUPT_BASE + LAPIC_TIMER_INTERRUPT)
235 
236 /* The vector field is ignored for NMI interrupts via the LAPIC
237  * or otherwise, so this is not an offset from the interrupt
238  * base.
239  */
240 #define LAPIC_NMI_INTERRUPT             0x2
241 #define LAPIC_FUNC_TABLE_SIZE           (LAPIC_PERFCNT_INTERRUPT + 1)
242 
243 #define LAPIC_VECTOR(src) \
244 	(lapic_interrupt_base + LAPIC_##src##_INTERRUPT)
245 
246 #define LAPIC_ISR_IS_SET(base, src) \
247 	(LAPIC_READ_OFFSET(ISR_BASE,(base+LAPIC_##src##_INTERRUPT)/32) \
248 	        & (1 <<((base + LAPIC_##src##_INTERRUPT)%32)))
249 
250 extern uint32_t         lapic_safe_apicid(void);
251 extern void             lapic_init_slave(void);
252 extern void             lapic_init(void);
253 extern void             lapic_configure(bool for_wake);
254 extern void             lapic_shutdown(bool for_sleep);
255 extern void             lapic_smm_restore(void);
256 extern boolean_t        lapic_probe(void);
257 extern void             lapic_dump(void);
258 extern void             lapic_cpu_map_dump(void);
259 extern int              lapic_interrupt(
260 	int interrupt, x86_saved_state_t *state);
261 extern void             lapic_end_of_interrupt(void);
262 extern void             lapic_unmask_perfcnt_interrupt(void);
263 extern void             lapic_set_perfcnt_interrupt_mask(boolean_t);
264 extern void             lapic_send_ipi(int cpu, int interupt);
265 extern void             lapic_send_nmi(int cpu);
266 
267 extern int              lapic_to_cpu[];
268 extern int              cpu_to_lapic[];
269 extern int              lapic_interrupt_base;
270 extern void             lapic_cpu_map_init(void);
271 extern void             lapic_cpu_map(int lapic, int cpu_num);
272 extern uint32_t         ml_get_apicid(uint32_t cpu);
273 extern uint32_t         ml_get_cpuid(uint32_t lapic_index);
274 extern int              lapic_max_interrupt_cpunum;
275 
276 extern void             lapic_config_timer(
277 	boolean_t               interrupt,
278 	lapic_timer_mode_t      mode,
279 	lapic_timer_divide_t    divisor);
280 
281 extern void             lapic_set_timer_fast(
282 	lapic_timer_count_t     initial_count);
283 
284 extern void             lapic_set_timer(
285 	boolean_t               interrupt,
286 	lapic_timer_mode_t      mode,
287 	lapic_timer_divide_t    divisor,
288 	lapic_timer_count_t     initial_count);
289 
290 extern void             lapic_get_timer(
291 	lapic_timer_mode_t      *mode,
292 	lapic_timer_divide_t    *divisor,
293 	lapic_timer_count_t     *initial_count,
294 	lapic_timer_count_t     *current_count);
295 
296 extern void             lapic_config_tsc_deadline_timer(void);
297 extern void             lapic_set_tsc_deadline_timer(uint64_t deadline);
298 extern uint64_t         lapic_get_tsc_deadline_timer(void);
299 
300 typedef int (*i386_intr_func_t)(x86_saved_state_t *state);
301 extern void             lapic_set_intr_func(int intr, i386_intr_func_t func);
302 
303 extern void             lapic_set_pmi_func(i386_intr_func_t);
304 
305 static inline void
lapic_set_timer_func(i386_intr_func_t func)306 lapic_set_timer_func(i386_intr_func_t func)
307 {
308 	lapic_set_intr_func(LAPIC_VECTOR(TIMER), func);
309 }
310 /* We don't support dynamic adjustment of the LAPIC timer base vector here
311  * it's effectively incompletely supported elsewhere as well.
312  */
313 static inline void
lapic_timer_swi(void)314 lapic_timer_swi(void)
315 {
316 	__asm__ __volatile__ ("int %0" :: "i"(LAPIC_DEFAULT_INTERRUPT_BASE + LAPIC_TIMER_INTERRUPT):"memory");
317 }
318 
319 static inline void
lapic_set_thermal_func(i386_intr_func_t func)320 lapic_set_thermal_func(i386_intr_func_t func)
321 {
322 	lapic_set_intr_func(LAPIC_VECTOR(THERMAL), func);
323 }
324 static inline void
lapic_set_cmci_func(i386_intr_func_t func)325 lapic_set_cmci_func(i386_intr_func_t func)
326 {
327 	lapic_set_intr_func(LAPIC_VECTOR(CMCI), func);
328 }
329 static inline void
lapic_set_pm_func(i386_intr_func_t func)330 lapic_set_pm_func(i386_intr_func_t func)
331 {
332 	lapic_set_intr_func(LAPIC_VECTOR(PM), func);
333 }
334 
335 extern boolean_t        lapic_is_interrupt_pending(void);
336 extern boolean_t        lapic_is_interrupting(uint8_t vector);
337 extern void             lapic_interrupt_counts(uint64_t intrs[256]);
338 extern void             lapic_disable_timer(void);
339 
340 extern uint8_t          lapic_get_cmci_vector(void);
341 
342 #define MAX_LAPICIDS    (LAPIC_ID_MAX+1)
343 #ifdef MP_DEBUG
344 #define LAPIC_CPU_MAP_DUMP()    lapic_cpu_map_dump()
345 #define LAPIC_DUMP()            lapic_dump()
346 #else
347 #define LAPIC_CPU_MAP_DUMP()
348 #define LAPIC_DUMP()
349 #endif /* MP_DEBUG */
350 
351 #endif /* ASSEMBLER */
352 
353 #endif /* _I386_LAPIC_H_ */
354