| 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((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 void		lapic_init(void); | 
| 251 | extern void		lapic_configure(void); | 
| 252 | extern void		lapic_shutdown(void); | 
| 253 | extern void		lapic_smm_restore(void); | 
| 254 | extern boolean_t	lapic_probe(void); | 
| 255 | extern void		lapic_dump(void); | 
| 256 | extern void		lapic_cpu_map_dump(void); | 
| 257 | extern int		lapic_interrupt( | 
| 258 | 				int interrupt, x86_saved_state_t *state); | 
| 259 | extern void		lapic_end_of_interrupt(void); | 
| 260 | extern void		lapic_unmask_perfcnt_interrupt(void); | 
| 261 | extern void		lapic_set_perfcnt_interrupt_mask(boolean_t); | 
| 262 | extern void		lapic_send_ipi(int cpu, int interupt); | 
| 263 |  | 
| 264 | extern int		lapic_to_cpu[]; | 
| 265 | extern int		cpu_to_lapic[]; | 
| 266 | extern int		lapic_interrupt_base; | 
| 267 | extern void		lapic_cpu_map_init(void); | 
| 268 | extern void		lapic_cpu_map(int lapic, int cpu_num); | 
| 269 | extern uint32_t		ml_get_apicid(uint32_t cpu); | 
| 270 | extern uint32_t		ml_get_cpuid(uint32_t lapic_index); | 
| 271 |  | 
| 272 | extern void		lapic_config_timer( | 
| 273 | 				boolean_t		interrupt, | 
| 274 | 				lapic_timer_mode_t	mode, | 
| 275 | 				lapic_timer_divide_t 	divisor); | 
| 276 |  | 
| 277 | extern void		lapic_set_timer_fast( | 
| 278 | 				lapic_timer_count_t	initial_count); | 
| 279 |  | 
| 280 | extern void		lapic_set_timer( | 
| 281 | 				boolean_t		interrupt, | 
| 282 | 				lapic_timer_mode_t	mode, | 
| 283 | 				lapic_timer_divide_t 	divisor, | 
| 284 | 				lapic_timer_count_t	initial_count); | 
| 285 |  | 
| 286 | extern void		lapic_get_timer( | 
| 287 | 				lapic_timer_mode_t	*mode, | 
| 288 | 				lapic_timer_divide_t	*divisor, | 
| 289 | 				lapic_timer_count_t	*initial_count, | 
| 290 | 				lapic_timer_count_t	*current_count); | 
| 291 |  | 
| 292 | extern void		lapic_config_tsc_deadline_timer(void); | 
| 293 | extern void		lapic_set_tsc_deadline_timer(uint64_t deadline); | 
| 294 | extern uint64_t		lapic_get_tsc_deadline_timer(void); | 
| 295 |  | 
| 296 | typedef	int (*i386_intr_func_t)(x86_saved_state_t *state); | 
| 297 | extern void		lapic_set_intr_func(int intr, i386_intr_func_t func); | 
| 298 |  | 
| 299 | extern void		lapic_set_pmi_func(i386_intr_func_t); | 
| 300 |  | 
| 301 | static inline void	lapic_set_timer_func(i386_intr_func_t func) | 
| 302 | { | 
| 303 | 	lapic_set_intr_func(LAPIC_VECTOR(TIMER), func); | 
| 304 | } | 
| 305 | /* We don't support dynamic adjustment of the LAPIC timer base vector here | 
| 306 |  * it's effectively incompletely supported elsewhere as well. | 
| 307 |  */ | 
| 308 | static inline void	lapic_timer_swi(void) { | 
| 309 | 	__asm__ __volatile__("int %0"  :: "i" (LAPIC_DEFAULT_INTERRUPT_BASE + LAPIC_TIMER_INTERRUPT):"memory" ); | 
| 310 | } | 
| 311 |  | 
| 312 | static inline void	lapic_set_thermal_func(i386_intr_func_t func) | 
| 313 | { | 
| 314 | 	lapic_set_intr_func(LAPIC_VECTOR(THERMAL), func); | 
| 315 | } | 
| 316 | static inline void	lapic_set_cmci_func(i386_intr_func_t func) | 
| 317 | { | 
| 318 | 	lapic_set_intr_func(LAPIC_VECTOR(CMCI), func); | 
| 319 | } | 
| 320 | static inline void	lapic_set_pm_func(i386_intr_func_t func) | 
| 321 | { | 
| 322 | 	lapic_set_intr_func(LAPIC_VECTOR(PM), func); | 
| 323 | } | 
| 324 |  | 
| 325 | extern boolean_t	lapic_is_interrupt_pending(void); | 
| 326 | extern boolean_t	lapic_is_interrupting(uint8_t vector); | 
| 327 | extern void		lapic_interrupt_counts(uint64_t intrs[256]); | 
| 328 | extern void		lapic_disable_timer(void); | 
| 329 |  | 
| 330 | extern uint8_t		lapic_get_cmci_vector(void); | 
| 331 |  | 
| 332 | #define	MAX_LAPICIDS	(LAPIC_ID_MAX+1) | 
| 333 | #ifdef MP_DEBUG | 
| 334 | #define LAPIC_CPU_MAP_DUMP()	lapic_cpu_map_dump() | 
| 335 | #define LAPIC_DUMP()		lapic_dump() | 
| 336 | #else | 
| 337 | #define LAPIC_CPU_MAP_DUMP() | 
| 338 | #define LAPIC_DUMP() | 
| 339 | #endif /* MP_DEBUG */ | 
| 340 |  | 
| 341 | #endif /* ASSEMBLER */ | 
| 342 |  | 
| 343 | #endif /* _I386_LAPIC_H_ */ | 
| 344 |  | 
| 345 |  |