On Tue, May 10, 2016 at 04:43:33PM +0200, Igor Mammedov wrote:
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@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);
+}
Can we integrate handle_x2apic() into count_cpu() as in:
static int count_cpu(void) { CountCPUs++;
u32 eax, ebx, ecx, cpuid_features; cpuid(1, &eax, &ebx, &ecx, &cpuid_features); if (MaxCountCPUs < 256) { // xAPIC mode // Track found apic id for use in legacy internal bios tables FoundAPICIDs[apic_id/32] |= 1 << (apic_id % 32); return ebx>>24; }
// x2APIC mode if (!(ecx & CPUID_X2APIC)) return -1; u64 apic_base = rdmsr(MSR_IA32_APIC_BASE); wrmsr(MSR_IA32_APIC_BASE, apic_base | MSR_IA32_APICBASE_EXTD); return rdmsr(MSR_LOCAL_APIC_ID); }
count_cpu may be a poor choice of name, but if we could put all the apic stuff in one function and call it from both handle_smp() and smp_setup() I think it would make the code a little easier to understand.
-Kevin