x86: Always use legacy xAPIC to get APIC ID during TSS setup
Force use of xAPIC to retrieve the APIC ID during TSS setup to fix an
issue where an AP can switch apic_ops to point at x2apic_ops before
setup_tss() completes, leading to a #GP and triple fault due to trying
to read an x2APIC MSR without x2APIC being enabled.
A future patch will make apic_ops a per-cpu pointer, but that's not of
any help for 32-bit, which uses the APIC ID to determine the GS selector,
i.e. 32-bit KUT has a chicken-and-egg problem. All setup_tss() callers
ensure the local APIC is in xAPIC mode, so just force use of xAPIC in
this case.
Fixes: 7e33895 ("x86: Move 32-bit GDT and TSS to desc.c")
Fixes: dbd3800 ("x86: Move 64-bit GDT and TSS to desc.c")
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20220121231852.1439917-2-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/lib/x86/apic.c b/lib/x86/apic.c
index da8f301..b404d58 100644
--- a/lib/x86/apic.c
+++ b/lib/x86/apic.c
@@ -48,6 +48,11 @@
return xapic_read(APIC_ID) >> 24;
}
+uint32_t pre_boot_apic_id(void)
+{
+ return xapic_id();
+}
+
static const struct apic_ops xapic_ops = {
.reg_read = xapic_read,
.reg_write = xapic_write,
diff --git a/lib/x86/apic.h b/lib/x86/apic.h
index c482171..7844324 100644
--- a/lib/x86/apic.h
+++ b/lib/x86/apic.h
@@ -53,6 +53,8 @@
void apic_write(unsigned reg, uint32_t val);
void apic_icr_write(uint32_t val, uint32_t dest);
uint32_t apic_id(void);
+uint32_t pre_boot_apic_id(void);
+
int enable_x2apic(void);
void disable_apic(void);
diff --git a/lib/x86/setup.c b/lib/x86/setup.c
index 0044b64..8a4fa3c 100644
--- a/lib/x86/setup.c
+++ b/lib/x86/setup.c
@@ -109,7 +109,7 @@
u32 id;
tss64_t *tss_entry;
- id = apic_id();
+ id = pre_boot_apic_id();
/* Runtime address of current TSS */
tss_entry = &tss[id];
@@ -129,7 +129,7 @@
u32 id;
tss32_t *tss_entry;
- id = apic_id();
+ id = pre_boot_apic_id();
/* Runtime address of current TSS */
tss_entry = &tss[id];