xref: /linux/tools/testing/selftests/kvm/lib/x86_64/apic.c (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021, Google LLC.
4  */
5 
6 #include "apic.h"
7 
8 void apic_disable(void)
9 {
10 	wrmsr(MSR_IA32_APICBASE,
11 	      rdmsr(MSR_IA32_APICBASE) &
12 		~(MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD));
13 }
14 
15 void xapic_enable(void)
16 {
17 	uint64_t val = rdmsr(MSR_IA32_APICBASE);
18 
19 	/* Per SDM: to enable xAPIC when in x2APIC must first disable APIC */
20 	if (val & MSR_IA32_APICBASE_EXTD) {
21 		apic_disable();
22 		wrmsr(MSR_IA32_APICBASE,
23 		      rdmsr(MSR_IA32_APICBASE) | MSR_IA32_APICBASE_ENABLE);
24 	} else if (!(val & MSR_IA32_APICBASE_ENABLE)) {
25 		wrmsr(MSR_IA32_APICBASE, val | MSR_IA32_APICBASE_ENABLE);
26 	}
27 
28 	/*
29 	 * Per SDM: reset value of spurious interrupt vector register has the
30 	 * APIC software enabled bit=0. It must be enabled in addition to the
31 	 * enable bit in the MSR.
32 	 */
33 	val = xapic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED;
34 	xapic_write_reg(APIC_SPIV, val);
35 }
36 
37 void x2apic_enable(void)
38 {
39 	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) |
40 	      MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD);
41 	x2apic_write_reg(APIC_SPIV,
42 			 x2apic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED);
43 }
44