1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
6 #include <cpu/x86/lapic.h>
7 #include <cpu/x86/lapic_def.h>
8 #include <cpu/x86/msr.h>
12 static bool quirk_x2apic_allowed
;
14 void enable_lapic_mode(bool try_set_x2apic
)
17 bool use_x2apic
= false;
20 msr
= rdmsr(LAPIC_BASE_MSR
);
21 if (!(msr
.lo
& LAPIC_BASE_MSR_ENABLE
)) {
23 msr
.lo
&= ~LAPIC_BASE_MSR_ADDR_MASK
;
24 msr
.lo
|= LAPIC_DEFAULT_BASE
;
25 msr
.lo
|= LAPIC_BASE_MSR_ENABLE
;
26 wrmsr(LAPIC_BASE_MSR
, msr
);
27 msr
= rdmsr(LAPIC_BASE_MSR
);
30 ASSERT(msr
.lo
& LAPIC_BASE_MSR_ENABLE
);
32 apic_base
= msr
.lo
& LAPIC_BASE_MSR_ADDR_MASK
;
33 ASSERT(apic_base
== LAPIC_DEFAULT_BASE
);
36 use_x2apic
= !!(cpu_get_feature_flags_ecx() & CPUID_X2APIC
);
38 if (use_x2apic
== !!(msr
.lo
& LAPIC_BASE_MSR_X2APIC_MODE
)) {
39 printk(BIOS_INFO
, "LAPIC 0x%x in %s mode.\n", lapicid(),
40 use_x2apic
? "X2APIC" : "XAPIC");
41 } else if (use_x2apic
) {
42 msr
.lo
|= LAPIC_BASE_MSR_X2APIC_MODE
;
43 wrmsr(LAPIC_BASE_MSR
, msr
);
44 msr
= rdmsr(LAPIC_BASE_MSR
);
45 ASSERT(!!(msr
.lo
& LAPIC_BASE_MSR_X2APIC_MODE
));
46 printk(BIOS_INFO
, "LAPIC 0x%x switched to X2APIC mode.\n", lapicid());
48 die("Switching from X2APIC to XAPIC mode is not implemented.");
51 if (CONFIG(X2APIC_LATE_WORKAROUND
) && use_x2apic
)
52 quirk_x2apic_allowed
= true;
55 void enable_lapic(void)
57 bool try_set_x2apic
= true;
59 if (CONFIG(XAPIC_ONLY
))
60 try_set_x2apic
= false;
61 else if (CONFIG(X2APIC_LATE_WORKAROUND
))
62 try_set_x2apic
= quirk_x2apic_allowed
;
64 enable_lapic_mode(try_set_x2apic
);
67 uintptr_t cpu_get_lapic_addr(void)
69 return LAPIC_DEFAULT_BASE
;
72 void setup_lapic_interrupts(void)
75 * Set Task Priority to 'accept all'.
77 lapic_update32(LAPIC_TASKPRI
, ~LAPIC_TPRI_MASK
, 0);
79 /* Set spurious interrupt vector to 0 and keep LAPIC enabled to
80 be able to clear LVT register mask bits. */
81 lapic_update32(LAPIC_SPIV
, ~LAPIC_VECTOR_MASK
, LAPIC_SPIV_ENABLE
);
83 /* Put the local APIC in virtual wire mode */
84 uint32_t mask
= LAPIC_LVT_MASKED
| LAPIC_LVT_LEVEL_TRIGGER
| LAPIC_INPUT_POLARITY
|
85 LAPIC_DELIVERY_MODE_MASK
;
88 lapic_update32(LAPIC_LVT0
, ~mask
, LAPIC_DELIVERY_MODE_EXTINT
);
90 lapic_update32(LAPIC_LVT0
, ~mask
, LAPIC_LVT_MASKED
|
91 LAPIC_DELIVERY_MODE_EXTINT
);
93 lapic_update32(LAPIC_LVT1
, ~mask
, LAPIC_DELIVERY_MODE_NMI
);