[SeaBIOS] [PATCH 3/4] support booting with more than 255 CPUs
Igor Mammedov
imammedo at redhat.com
Tue May 10 16:43:33 CEST 2016
SDM[*1] says that if there are CPUs with APIC ID
greater than 254, BIOS is to pass control to OS
in x2APIC mode. Use the fact that QEMU passes in
"etc/max-cpus" max possible "APIC ID + 1" to
detect need for x2APIC mode. Also instead of
CMOS_BIOS_SMP_COUNT which is limited to 256 CPUs
use a new rom file "etc/boot-cpus" that QEMU
supporting more than 256 CPUs will provide.
*1) SDM: Volume 3: EXTENDED XAPIC (X2APIC):
Initialization by System Software
Signed-off-by: Igor Mammedov <imammedo at redhat.com>
---
src/fw/smp.c | 40 ++++++++++++++++++++++++++++++++++------
src/x86.h | 1 +
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/src/fw/smp.c b/src/fw/smp.c
index ad98a5f..18a4c77 100644
--- a/src/fw/smp.c
+++ b/src/fw/smp.c
@@ -19,6 +19,9 @@
#define APIC_LINT1 ((u8*)BUILD_APIC_ADDR + 0x360)
#define APIC_ENABLED 0x0100
+#define MSR_IA32_APIC_BASE 0x01B
+#define MSR_LOCAL_APIC_ID 0x802
+#define MSR_IA32_APICBASE_EXTD (1ULL << 10) /* Enable x2APIC mode */
static struct { u32 index; u64 val; } smp_mtrr[32];
static u32 smp_mtrr_count;
@@ -49,23 +52,46 @@ int apic_id_is_present(u8 apic_id)
static int
count_cpu(void)
{
+ u32 apic_id;
CountCPUs++;
- // Track found apic id for use in legacy internal bios tables
u32 eax, ebx, ecx, cpuid_features;
cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
- u8 apic_id = ebx>>24;
- FoundAPICIDs[apic_id/32] |= 1 << (apic_id % 32);
+ apic_id = ebx>>24;
+ if (MaxCountCPUs < 256) { // xAPIC mode
+ // Track found apic id for use in legacy internal bios tables
+ FoundAPICIDs[apic_id/32] |= 1 << (apic_id % 32);
+ }
+ if (rdmsr(MSR_IA32_APIC_BASE) & MSR_IA32_APICBASE_EXTD) { // x2APIC mode
+ apic_id = rdmsr(MSR_LOCAL_APIC_ID);
+ }
return apic_id;
}
+static void
+handle_x2apic(void)
+{
+ if (MaxCountCPUs < 256)
+ return;
+
+ u32 eax, ebx, ecx, edx;
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+ if (!(ecx & CPUID_X2APIC))
+ return;
+
+ // switch to x2APIC mode
+ u64 apic_base = rdmsr(MSR_IA32_APIC_BASE);
+ wrmsr(MSR_IA32_APIC_BASE, apic_base | MSR_IA32_APICBASE_EXTD);
+}
+
void VISIBLE32FLAT
handle_smp(void)
{
if (!CONFIG_QEMU)
return;
+ handle_x2apic();
// Track this CPU and detect the apic_id
int apic_id = count_cpu();
dprintf(DEBUG_HDL_smp, "handle_smp: apic_id=%d\n", apic_id);
@@ -98,6 +124,7 @@ smp_setup(void)
return;
}
+ MaxCountCPUs = romfile_loadint("etc/max-cpus", 1);
// Detect initial boot cpu
count_cpu();
@@ -129,8 +156,9 @@ smp_setup(void)
writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
// Wait for other CPUs to process the SIPI.
- u8 cmos_smp_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
- while (cmos_smp_count != CountCPUs)
+ u16 boot_cpus_count = romfile_loadint("etc/boot-cpus",
+ rtc_read(CMOS_BIOS_SMP_COUNT) + 1);
+ while (boot_cpus_count != CountCPUs)
asm volatile(
// Release lock and allow other processors to use the stack.
" movl %%esp, %1\n"
@@ -146,7 +174,7 @@ smp_setup(void)
// Restore memory.
*(u64*)BUILD_AP_BOOT_ADDR = old;
- MaxCountCPUs = romfile_loadint("etc/max-cpus", 0);
+ handle_x2apic();
if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
MaxCountCPUs = CountCPUs;
diff --git a/src/x86.h b/src/x86.h
index 53378e9..a770e6f 100644
--- a/src/x86.h
+++ b/src/x86.h
@@ -68,6 +68,7 @@ static inline void wbinvd(void)
#define CPUID_MSR (1 << 5)
#define CPUID_APIC (1 << 9)
#define CPUID_MTRR (1 << 12)
+#define CPUID_X2APIC (1 << 21)
static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
{
asm("cpuid"
--
1.8.3.1
More information about the SeaBIOS
mailing list