1/*
2 * Copyright (c) 2008 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#include <mach/mach_types.h>
33#include <mach/kern_return.h>
34
35#include <kern/kern_types.h>
36#include <kern/cpu_number.h>
37#include <kern/cpu_data.h>
38#include <kern/assert.h>
39#include <kern/machine.h>
40
41#include <vm/vm_map.h>
42#include <vm/vm_kern.h>
43
44#include <i386/lapic.h>
45#include <i386/cpuid.h>
46#include <i386/proc_reg.h>
47#include <i386/machine_cpu.h>
48#include <i386/misc_protos.h>
49#include <i386/mp.h>
50#include <i386/mtrr.h>
51#include <i386/postcode.h>
52#include <i386/cpu_threads.h>
53#include <i386/trap.h>
54#include <i386/machine_routines.h>
55#include <i386/machine_check.h>
56
57#if MACH_KDB
58#include <machine/db_machdep.h>
59#endif
60
61#include <sys/kdebug.h>
62
63#if	MP_DEBUG
64#define PAUSE		delay(1000000)
65#define DBG(x...)	kprintf(x)
66#else
67#define DBG(x...)
68#define PAUSE
69#endif	/* MP_DEBUG */
70
71/* Initialize lapic_id so cpu_number() works on non SMP systems */
72unsigned long	lapic_id_initdata = 0;
73unsigned long	lapic_id = (unsigned long)&lapic_id_initdata;
74vm_offset_t	lapic_start;
75
76static i386_intr_func_t	lapic_intr_func[LAPIC_FUNC_TABLE_SIZE];
77
78/* TRUE if local APIC was enabled by the OS not by the BIOS */
79static boolean_t lapic_os_enabled = FALSE;
80
81static boolean_t lapic_errors_masked = FALSE;
82static uint64_t lapic_last_master_error = 0;
83static uint64_t lapic_error_time_threshold = 0;
84static unsigned lapic_master_error_count = 0;
85static unsigned lapic_error_count_threshold = 5;
86static boolean_t lapic_dont_panic = FALSE;
87
88extern int	debug_boot_arg;
89
90/* Base vector for local APIC interrupt sources */
91int lapic_interrupt_base = LAPIC_DEFAULT_INTERRUPT_BASE;
92
93int		lapic_to_cpu[MAX_CPUS];
94int		cpu_to_lapic[MAX_CPUS];
95
96static void
97lapic_cpu_map_init(void)
98{
99	int	i;
100
101	for (i = 0; i < MAX_CPUS; i++) {
102		lapic_to_cpu[i] = -1;
103		cpu_to_lapic[i] = -1;
104	}
105}
106
107void
108lapic_cpu_map(int apic_id, int cpu)
109{
110	cpu_to_lapic[cpu] = apic_id;
111	lapic_to_cpu[apic_id] = cpu;
112}
113
114/*
115 * Retrieve the local apic ID a cpu.
116 *
117 * Returns the local apic ID for the given processor.
118 * If the processor does not exist or apic not configured, returns -1.
119 */
120
121uint32_t
122ml_get_apicid(uint32_t cpu)
123{
124	if(cpu >= (uint32_t)MAX_CPUS)
125		return 0xFFFFFFFF;	/* Return -1 if cpu too big */
126
127	/* Return the apic ID (or -1 if not configured) */
128	return (uint32_t)cpu_to_lapic[cpu];
129
130}
131
132#ifdef MP_DEBUG
133static void
134lapic_cpu_map_dump(void)
135{
136	int	i;
137
138	for (i = 0; i < MAX_CPUS; i++) {
139		if (cpu_to_lapic[i] == -1)
140			continue;
141		kprintf("cpu_to_lapic[%d]: %d\n",
142			i, cpu_to_lapic[i]);
143	}
144	for (i = 0; i < MAX_CPUS; i++) {
145		if (lapic_to_cpu[i] == -1)
146			continue;
147		kprintf("lapic_to_cpu[%d]: %d\n",
148			i, lapic_to_cpu[i]);
149	}
150}
151#endif /* MP_DEBUG */
152
153void
154lapic_init(void)
155{
156	int		result;
157	vm_map_entry_t	entry;
158	uint32_t	lo;
159	uint32_t	hi;
160	boolean_t	is_boot_processor;
161	boolean_t	is_lapic_enabled;
162	vm_offset_t	lapic_base;
163
164	/* Examine the local APIC state */
165	rdmsr(MSR_IA32_APIC_BASE, lo, hi);
166	is_boot_processor = (lo & MSR_IA32_APIC_BASE_BSP) != 0;
167	is_lapic_enabled  = (lo & MSR_IA32_APIC_BASE_ENABLE) != 0;
168	lapic_base = (lo &  MSR_IA32_APIC_BASE_BASE);
169	kprintf("MSR_IA32_APIC_BASE 0x%x %s %s\n", lapic_base,
170		is_lapic_enabled ? "enabled" : "disabled",
171		is_boot_processor ? "BSP" : "AP");
172	if (!is_boot_processor || !is_lapic_enabled)
173		panic("Unexpected local APIC state\n");
174
175	/* Establish a map to the local apic */
176	lapic_start = vm_map_min(kernel_map);
177	result = vm_map_find_space(kernel_map,
178				   (vm_map_address_t *) &lapic_start,
179				   round_page(LAPIC_SIZE), 0,
180				   VM_MAKE_TAG(VM_MEMORY_IOKIT), &entry);
181	if (result != KERN_SUCCESS) {
182		panic("smp_init: vm_map_find_entry FAILED (err=%d)", result);
183	}
184	vm_map_unlock(kernel_map);
185/* Map in the local APIC non-cacheable, as recommended by Intel
186 * in section 8.4.1 of the "System Programming Guide".
187 */
188	pmap_enter(pmap_kernel(),
189			lapic_start,
190			(ppnum_t) i386_btop(lapic_base),
191			VM_PROT_READ|VM_PROT_WRITE,
192			VM_WIMG_IO,
193			TRUE);
194	lapic_id = (unsigned long)(lapic_start + LAPIC_ID);
195
196	if ((LAPIC_READ(VERSION)&LAPIC_VERSION_MASK) < 0x14) {
197		printf("Local APIC version 0x%x, 0x14 or greater expected\n",
198			(LAPIC_READ(VERSION)&LAPIC_VERSION_MASK));
199	}
200
201	/* Set up the lapic_id <-> cpu_number map and add this boot processor */
202	lapic_cpu_map_init();
203	lapic_cpu_map((LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK, 0);
204	kprintf("Boot cpu local APIC id 0x%x\n", cpu_to_lapic[0]);
205}
206
207
208static int
209lapic_esr_read(void)
210{
211	/* write-read register */
212	LAPIC_WRITE(ERROR_STATUS, 0);
213	return LAPIC_READ(ERROR_STATUS);
214}
215
216static void
217lapic_esr_clear(void)
218{
219	LAPIC_WRITE(ERROR_STATUS, 0);
220	LAPIC_WRITE(ERROR_STATUS, 0);
221}
222
223static const char *DM_str[8] = {
224	"Fixed",
225	"Lowest Priority",
226	"Invalid",
227	"Invalid",
228	"NMI",
229	"Reset",
230	"Invalid",
231	"ExtINT"};
232
233void
234lapic_dump(void)
235{
236	int	i;
237
238#define BOOL(a) ((a)?' ':'!')
239#define VEC(lvt) \
240	LAPIC_READ(lvt)&LAPIC_LVT_VECTOR_MASK
241#define	DS(lvt)	\
242	(LAPIC_READ(lvt)&LAPIC_LVT_DS_PENDING)?" SendPending" : "Idle"
243#define DM(lvt) \
244	DM_str[(LAPIC_READ(lvt)>>LAPIC_LVT_DM_SHIFT)&LAPIC_LVT_DM_MASK]
245#define MASK(lvt) \
246	BOOL(LAPIC_READ(lvt)&LAPIC_LVT_MASKED)
247#define TM(lvt) \
248	(LAPIC_READ(lvt)&LAPIC_LVT_TM_LEVEL)? "Level" : "Edge"
249#define IP(lvt) \
250	(LAPIC_READ(lvt)&LAPIC_LVT_IP_PLRITY_LOW)? "Low " : "High"
251
252	kprintf("LAPIC %d at 0x%x version 0x%x\n",
253		(LAPIC_READ(ID)>>LAPIC_ID_SHIFT)&LAPIC_ID_MASK,
254		lapic_start,
255		LAPIC_READ(VERSION)&LAPIC_VERSION_MASK);
256	kprintf("Priorities: Task 0x%x  Arbitration 0x%x  Processor 0x%x\n",
257		LAPIC_READ(TPR)&LAPIC_TPR_MASK,
258		LAPIC_READ(APR)&LAPIC_APR_MASK,
259		LAPIC_READ(PPR)&LAPIC_PPR_MASK);
260	kprintf("Destination Format 0x%x Logical Destination 0x%x\n",
261		LAPIC_READ(DFR)>>LAPIC_DFR_SHIFT,
262		LAPIC_READ(LDR)>>LAPIC_LDR_SHIFT);
263	kprintf("%cEnabled %cFocusChecking SV 0x%x\n",
264		BOOL(LAPIC_READ(SVR)&LAPIC_SVR_ENABLE),
265		BOOL(!(LAPIC_READ(SVR)&LAPIC_SVR_FOCUS_OFF)),
266		LAPIC_READ(SVR) & LAPIC_SVR_MASK);
267	if (mca_is_cmci_present())
268		kprintf("LVT_CMCI:    Vector 0x%02x [%s] %s %cmasked\n",
269			VEC(LVT_CMCI),
270			DM(LVT_CMCI),
271			DS(LVT_CMCI),
272			MASK(LVT_CMCI));
273	kprintf("LVT_TIMER:   Vector 0x%02x %s %cmasked %s\n",
274		VEC(LVT_TIMER),
275		DS(LVT_TIMER),
276		MASK(LVT_TIMER),
277		(LAPIC_READ(LVT_TIMER)&LAPIC_LVT_PERIODIC)?"Periodic":"OneShot");
278	kprintf("  Initial Count: 0x%08x \n", LAPIC_READ(TIMER_INITIAL_COUNT));
279	kprintf("  Current Count: 0x%08x \n", LAPIC_READ(TIMER_CURRENT_COUNT));
280	kprintf("  Divide Config: 0x%08x \n", LAPIC_READ(TIMER_DIVIDE_CONFIG));
281	kprintf("LVT_PERFCNT: Vector 0x%02x [%s] %s %cmasked\n",
282		VEC(LVT_PERFCNT),
283		DM(LVT_PERFCNT),
284		DS(LVT_PERFCNT),
285		MASK(LVT_PERFCNT));
286	kprintf("LVT_THERMAL: Vector 0x%02x [%s] %s %cmasked\n",
287		VEC(LVT_THERMAL),
288		DM(LVT_THERMAL),
289		DS(LVT_THERMAL),
290		MASK(LVT_THERMAL));
291	kprintf("LVT_LINT0:   Vector 0x%02x [%s][%s][%s] %s %cmasked\n",
292		VEC(LVT_LINT0),
293		DM(LVT_LINT0),
294		TM(LVT_LINT0),
295		IP(LVT_LINT0),
296		DS(LVT_LINT0),
297		MASK(LVT_LINT0));
298	kprintf("LVT_LINT1:   Vector 0x%02x [%s][%s][%s] %s %cmasked\n",
299		VEC(LVT_LINT1),
300		DM(LVT_LINT1),
301		TM(LVT_LINT1),
302		IP(LVT_LINT1),
303		DS(LVT_LINT1),
304		MASK(LVT_LINT1));
305	kprintf("LVT_ERROR:   Vector 0x%02x %s %cmasked\n",
306		VEC(LVT_ERROR),
307		DS(LVT_ERROR),
308		MASK(LVT_ERROR));
309	kprintf("ESR: %08x \n", lapic_esr_read());
310	kprintf("       ");
311	for(i=0xf; i>=0; i--)
312		kprintf("%x%x%x%x",i,i,i,i);
313	kprintf("\n");
314	kprintf("TMR: 0x");
315	for(i=7; i>=0; i--)
316		kprintf("%08x",LAPIC_READ_OFFSET(TMR_BASE, i*0x10));
317	kprintf("\n");
318	kprintf("IRR: 0x");
319	for(i=7; i>=0; i--)
320		kprintf("%08x",LAPIC_READ_OFFSET(IRR_BASE, i*0x10));
321	kprintf("\n");
322	kprintf("ISR: 0x");
323	for(i=7; i >= 0; i--)
324		kprintf("%08x",LAPIC_READ_OFFSET(ISR_BASE, i*0x10));
325	kprintf("\n");
326}
327
328#if MACH_KDB
329/*
330 *	Displays apic junk
331 *
332 *	da
333 */
334void
335db_apic(__unused db_expr_t addr,
336	__unused int have_addr,
337	__unused db_expr_t count,
338	__unused char *modif)
339{
340
341	lapic_dump();
342
343	return;
344}
345
346#endif
347
348boolean_t
349lapic_probe(void)
350{
351	uint32_t	lo;
352	uint32_t	hi;
353
354	if (cpuid_features() & CPUID_FEATURE_APIC)
355		return TRUE;
356
357	if (cpuid_family() == 6 || cpuid_family() == 15) {
358		/*
359		 * Mobile Pentiums:
360		 * There may be a local APIC which wasn't enabled by BIOS.
361		 * So we try to enable it explicitly.
362		 */
363		rdmsr(MSR_IA32_APIC_BASE, lo, hi);
364		lo &= ~MSR_IA32_APIC_BASE_BASE;
365		lo |= MSR_IA32_APIC_BASE_ENABLE | LAPIC_START;
366		lo |= MSR_IA32_APIC_BASE_ENABLE;
367		wrmsr(MSR_IA32_APIC_BASE, lo, hi);
368
369		/*
370		 * Re-initialize cpu features info and re-check.
371		 */
372		cpuid_set_info();
373		if (cpuid_features() & CPUID_FEATURE_APIC) {
374			printf("Local APIC discovered and enabled\n");
375			lapic_os_enabled = TRUE;
376			lapic_interrupt_base = LAPIC_REDUCED_INTERRUPT_BASE;
377			return TRUE;
378		}
379	}
380
381	return FALSE;
382}
383
384void
385lapic_shutdown(void)
386{
387	uint32_t lo;
388	uint32_t hi;
389	uint32_t value;
390
391	/* Shutdown if local APIC was enabled by OS */
392	if (lapic_os_enabled == FALSE)
393		return;
394
395	mp_disable_preemption();
396
397	/* ExtINT: masked */
398	if (get_cpu_number() == master_cpu) {
399		value = LAPIC_READ(LVT_LINT0);
400		value |= LAPIC_LVT_MASKED;
401		LAPIC_WRITE(LVT_LINT0, value);
402	}
403
404	/* Error: masked */
405	LAPIC_WRITE(LVT_ERROR, LAPIC_READ(LVT_ERROR) | LAPIC_LVT_MASKED);
406
407	/* Timer: masked */
408	LAPIC_WRITE(LVT_TIMER, LAPIC_READ(LVT_TIMER) | LAPIC_LVT_MASKED);
409
410	/* Perfmon: masked */
411	LAPIC_WRITE(LVT_PERFCNT, LAPIC_READ(LVT_PERFCNT) | LAPIC_LVT_MASKED);
412
413	/* APIC software disabled */
414	LAPIC_WRITE(SVR, LAPIC_READ(SVR) & ~LAPIC_SVR_ENABLE);
415
416	/* Bypass the APIC completely and update cpu features */
417	rdmsr(MSR_IA32_APIC_BASE, lo, hi);
418	lo &= ~MSR_IA32_APIC_BASE_ENABLE;
419	wrmsr(MSR_IA32_APIC_BASE, lo, hi);
420	cpuid_set_info();
421
422	mp_enable_preemption();
423}
424
425void
426lapic_configure(void)
427{
428	int	value;
429
430	if (lapic_error_time_threshold == 0 && cpu_number() == 0) {
431		nanoseconds_to_absolutetime(NSEC_PER_SEC >> 2, &lapic_error_time_threshold);
432		if (!PE_parse_boot_argn("lapic_dont_panic", &lapic_dont_panic, sizeof(lapic_dont_panic))) {
433			lapic_dont_panic = FALSE;
434		}
435	}
436
437	/* Set flat delivery model, logical processor id */
438	LAPIC_WRITE(DFR, LAPIC_DFR_FLAT);
439	LAPIC_WRITE(LDR, (get_cpu_number()) << LAPIC_LDR_SHIFT);
440
441	/* Accept all */
442	LAPIC_WRITE(TPR, 0);
443
444	LAPIC_WRITE(SVR, LAPIC_VECTOR(SPURIOUS) | LAPIC_SVR_ENABLE);
445
446	/* ExtINT */
447	if (get_cpu_number() == master_cpu) {
448		value = LAPIC_READ(LVT_LINT0);
449		value &= ~LAPIC_LVT_MASKED;
450		value |= LAPIC_LVT_DM_EXTINT;
451		LAPIC_WRITE(LVT_LINT0, value);
452	}
453
454	/* Timer: unmasked, one-shot */
455	LAPIC_WRITE(LVT_TIMER, LAPIC_VECTOR(TIMER));
456
457	/* Perfmon: unmasked */
458	LAPIC_WRITE(LVT_PERFCNT, LAPIC_VECTOR(PERFCNT));
459
460	/* Thermal: unmasked */
461	LAPIC_WRITE(LVT_THERMAL, LAPIC_VECTOR(THERMAL));
462
463	/* CMCI, if available */
464	if (mca_is_cmci_present())
465		LAPIC_WRITE(LVT_CMCI, LAPIC_VECTOR(CMCI));
466
467	if (((cpu_number() == master_cpu) && lapic_errors_masked == FALSE) ||
468		(cpu_number() != master_cpu)) {
469		lapic_esr_clear();
470		LAPIC_WRITE(LVT_ERROR, LAPIC_VECTOR(ERROR));
471	}
472}
473
474void
475lapic_set_timer(
476	boolean_t		interrupt,
477	lapic_timer_mode_t	mode,
478	lapic_timer_divide_t	divisor,
479	lapic_timer_count_t	initial_count)
480{
481	boolean_t	state;
482	uint32_t	timer_vector;
483
484	state = ml_set_interrupts_enabled(FALSE);
485	timer_vector = LAPIC_READ(LVT_TIMER);
486	timer_vector &= ~(LAPIC_LVT_MASKED|LAPIC_LVT_PERIODIC);;
487	timer_vector |= interrupt ? 0 : LAPIC_LVT_MASKED;
488	timer_vector |= (mode == periodic) ? LAPIC_LVT_PERIODIC : 0;
489	LAPIC_WRITE(LVT_TIMER, timer_vector);
490	LAPIC_WRITE(TIMER_DIVIDE_CONFIG, divisor);
491	LAPIC_WRITE(TIMER_INITIAL_COUNT, initial_count);
492	ml_set_interrupts_enabled(state);
493}
494
495void
496lapic_get_timer(
497	lapic_timer_mode_t	*mode,
498	lapic_timer_divide_t	*divisor,
499	lapic_timer_count_t	*initial_count,
500	lapic_timer_count_t	*current_count)
501{
502	boolean_t	state;
503
504	state = ml_set_interrupts_enabled(FALSE);
505	if (mode)
506		*mode = (LAPIC_READ(LVT_TIMER) & LAPIC_LVT_PERIODIC) ?
507				periodic : one_shot;
508	if (divisor)
509		*divisor = LAPIC_READ(TIMER_DIVIDE_CONFIG) & LAPIC_TIMER_DIVIDE_MASK;
510	if (initial_count)
511		*initial_count = LAPIC_READ(TIMER_INITIAL_COUNT);
512	if (current_count)
513		*current_count = LAPIC_READ(TIMER_CURRENT_COUNT);
514	ml_set_interrupts_enabled(state);
515}
516
517static inline void
518_lapic_end_of_interrupt(void)
519{
520	LAPIC_WRITE(EOI, 0);
521}
522
523void
524lapic_end_of_interrupt(void)
525{
526	_lapic_end_of_interrupt();
527}
528
529void
530lapic_set_intr_func(int vector, i386_intr_func_t func)
531{
532	if (vector > lapic_interrupt_base)
533		vector -= lapic_interrupt_base;
534
535	switch (vector) {
536	case LAPIC_NMI_INTERRUPT:
537	case LAPIC_INTERPROCESSOR_INTERRUPT:
538	case LAPIC_TIMER_INTERRUPT:
539	case LAPIC_THERMAL_INTERRUPT:
540	case LAPIC_PERFCNT_INTERRUPT:
541	case LAPIC_CMCI_INTERRUPT:
542		lapic_intr_func[vector] = func;
543		break;
544	default:
545		panic("lapic_set_intr_func(%d,%p) invalid vector\n",
546			vector, func);
547	}
548}
549
550int
551lapic_interrupt(int interrupt, x86_saved_state_t *state)
552{
553	int	retval = 0;
554	int 	esr = -1;
555
556	interrupt -= lapic_interrupt_base;
557	if (interrupt < 0) {
558		if (interrupt == (LAPIC_NMI_INTERRUPT - lapic_interrupt_base) &&
559		    lapic_intr_func[LAPIC_NMI_INTERRUPT] != NULL) {
560			retval = (*lapic_intr_func[LAPIC_NMI_INTERRUPT])(state);
561			_lapic_end_of_interrupt();
562			return retval;
563		}
564		else
565			return 0;
566	}
567
568	switch(interrupt) {
569	case LAPIC_TIMER_INTERRUPT:
570	case LAPIC_THERMAL_INTERRUPT:
571	case LAPIC_PERFCNT_INTERRUPT:
572	case LAPIC_INTERPROCESSOR_INTERRUPT:
573		if (lapic_intr_func[interrupt] != NULL)
574			(void) (*lapic_intr_func[interrupt])(state);
575		if (interrupt == LAPIC_PERFCNT_INTERRUPT)
576			/* Clear interrupt masked */
577			LAPIC_WRITE(LVT_PERFCNT, LAPIC_VECTOR(PERFCNT));
578		_lapic_end_of_interrupt();
579		retval = 1;
580		break;
581	case LAPIC_CMCI_INTERRUPT:
582		if (lapic_intr_func[interrupt] != NULL)
583			(void) (*lapic_intr_func[interrupt])(state);
584		/* return 0 for plaform expert to handle */
585		break;
586	case LAPIC_ERROR_INTERRUPT:
587		/* We treat error interrupts on APs as fatal.
588		 * The current interrupt steering scheme directs most
589		 * external interrupts to the BSP (HPET interrupts being
590		 * a notable exception); hence, such an error
591		 * on an AP may signify LVT corruption (with "may" being
592		 * the operative word). On the BSP, we adopt a more
593		 * lenient approach, in the interests of enhancing
594		 * debuggability and reducing fragility.
595		 * If "lapic_error_count_threshold" error interrupts
596		 * occur within "lapic_error_time_threshold" absolute
597		 * time units, we mask the error vector and log. The
598		 * error interrupts themselves are likely
599		 * side effects of issues which are beyond the purview of
600		 * the local APIC interrupt handler, however. The Error
601		 * Status Register value (the illegal destination
602		 * vector code is one observed in practice) indicates
603		 * the immediate cause of the error.
604		 */
605		esr = lapic_esr_read();
606		lapic_dump();
607
608		if ((debug_boot_arg && (lapic_dont_panic == FALSE)) ||
609			cpu_number() != master_cpu) {
610			panic("Local APIC error, ESR: %d\n", esr);
611		}
612
613		if (cpu_number() == master_cpu) {
614			uint64_t abstime = mach_absolute_time();
615			if ((abstime - lapic_last_master_error) < lapic_error_time_threshold) {
616				if (lapic_master_error_count++ > lapic_error_count_threshold) {
617					lapic_errors_masked = TRUE;
618					LAPIC_WRITE(LVT_ERROR, LAPIC_READ(LVT_ERROR) | LAPIC_LVT_MASKED);
619					printf("Local APIC: errors masked\n");
620				}
621			}
622			else {
623				lapic_last_master_error = abstime;
624				lapic_master_error_count = 0;
625			}
626			printf("Local APIC error on master CPU, ESR: %d, error count this run: %d\n", esr, lapic_master_error_count);
627		}
628
629		_lapic_end_of_interrupt();
630		retval = 1;
631		break;
632	case LAPIC_SPURIOUS_INTERRUPT:
633		kprintf("SPIV\n");
634		/* No EOI required here */
635		retval = 1;
636		break;
637	}
638
639	return retval;
640}
641
642void
643lapic_smm_restore(void)
644{
645	boolean_t state;
646
647	if (lapic_os_enabled == FALSE)
648		return;
649
650	state = ml_set_interrupts_enabled(FALSE);
651
652 	if (LAPIC_ISR_IS_SET(LAPIC_REDUCED_INTERRUPT_BASE, TIMER)) {
653		/*
654		 * Bogus SMI handler enables interrupts but does not know about
655		 * local APIC interrupt sources. When APIC timer counts down to
656		 * zero while in SMM, local APIC will end up waiting for an EOI
657		 * but no interrupt was delivered to the OS.
658 		 */
659		_lapic_end_of_interrupt();
660
661		/*
662		 * timer is one-shot, trigger another quick countdown to trigger
663		 * another timer interrupt.
664		 */
665		if (LAPIC_READ(TIMER_CURRENT_COUNT) == 0) {
666			LAPIC_WRITE(TIMER_INITIAL_COUNT, 1);
667		}
668
669		kprintf("lapic_smm_restore\n");
670	}
671
672	ml_set_interrupts_enabled(state);
673}
674
675