Rename smpdetect.c to smp.c - the code does more than just cpu detection.
Don't probe cpu count on demand - schedule it during post.
Add logic to run wrmsr on all cpus.
Don't make mtrr setup specific to kvm - do it on all machines that
have mtrr and msrs.
Detect cpu signature/features automatically in mptable.
Also, make sure acpi structures are packed.
# Source files
SRCBOTH=output.c util.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
- serial.c clock.c pic.c cdrom.c ps2port.c smpdetect.c resume.c \
+ serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
pnpbios.c pirtable.c
SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c vgahooks.c font.c
SRC32=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
struct acpi_table_header /* ACPI common table header */
{
ACPI_TABLE_HEADER_DEF
-};
+} PACKED;
/*
* ACPI 1.0 Root System Description Table (RSDT)
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
u32 table_offset_entry [3]; /* Array of pointers to other */
/* ACPI tables */
-};
+} PACKED;
/*
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */
u32 reserved1 : 31; /* Must be 0 */
u8 resverved3 [40]; /* Reserved - must be zero */
-};
+} PACKED;
/*
#else
u32 flags;
#endif
-};
+} PACKED;
/*
* MADT values and structures
#else
u32 flags;
#endif
-};
+} PACKED;
/* Values for Type in APIC_HEADER_DEF */
#else
u32 flags;
#endif
-};
+} PACKED;
struct madt_io_apic
{
u32 address; /* APIC physical address */
u32 interrupt; /* Global system interrupt where INTI
* lines start */
-};
+} PACKED;
#if CONFIG_KVM
/* IRQs 5,9,10,11 */
{
u8 *ssdt_ptr = ssdt;
int i, length;
- int smp_cpus = smp_probe();
+ int smp_cpus = CountCPUs;
int acpi_cpus = smp_cpus > 0xff ? 0xff : smp_cpus;
ssdt_ptr[9] = 0; // checksum;
ssdt = (void *)(addr);
addr += acpi_build_processor_ssdt(ssdt);
- int smp_cpus = smp_probe();
+ int smp_cpus = CountCPUs;
addr = ALIGN(addr, 8);
madt_addr = addr;
madt_size = sizeof(*madt) +
dprintf(3, "init MPTable\n");
- int smp_cpus = smp_probe();
+ int smp_cpus = CountCPUs;
if (smp_cpus <= 1)
// Building an mptable on uniprocessor machines confuses some OSes.
return;
config->lapic = BUILD_APIC_ADDR;
// CPU definitions.
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
struct mpt_cpu *cpus = (void*)&config[1];
int i;
for (i = 0; i < smp_cpus; i++) {
cpu->apicver = 0x11;
/* cpu flags: enabled, bootstrap cpu */
cpu->cpuflag = (i == 0 ? 3 : 1);
- cpu->cpufeature = 0x600;
- cpu->featureflag = 0x201;
+ if (cpuid_signature) {
+ cpu->cpusignature = cpuid_signature;
+ cpu->featureflag = cpuid_features;
+ } else {
+ cpu->cpusignature = 0x600;
+ cpu->featureflag = 0x201;
+ }
}
/* isa bus */
u8 apicid;
u8 apicver;
u8 cpuflag;
- u32 cpufeature;
+ u32 cpusignature;
u32 featureflag;
u32 reserved[2];
} PACKED;
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
-static u64 rdmsr(u32 index)
-{
- u64 ret;
- asm ("rdmsr" : "=A"(ret) : "c"(index));
- return ret;
-}
-
-static void wrmsr(u32 index, u64 val)
-{
- asm volatile ("wrmsr" : : "c"(index), "A"(val));
-}
-
-static void wrmsr_smp(u32 index, u64 val)
-{
- // XXX - should run this on other CPUs also.
- wrmsr(index, val);
-}
-
void mtrr_setup(void)
{
- if (! CONFIG_KVM)
+ if (CONFIG_COREBOOT)
+ return;
+
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (!(cpuid_features & CPUID_MTRR))
+ return;
+ if (!(cpuid_features & CPUID_MSR))
return;
+
dprintf(3, "init mtrr\n");
int i, vcnt, fix, wc;
mathcp_setup();
smp_probe_setup();
-
memmap_setup();
ram_probe();
mtrr_setup();
+ smp_probe();
pnp_setup();
vga_setup();
add_struct(smbios_type_0_init(p));
add_struct(smbios_type_1_init(p));
add_struct(smbios_type_3_init(p));
- int smp_cpus = smp_probe();
+ int smp_cpus = CountCPUs;
for (cpu_num = 1; cpu_num <= smp_cpus; cpu_num++)
add_struct(smbios_type_4_init(p, cpu_num));
add_struct(smbios_type_16_init(p));
--- /dev/null
+// CPU count detection
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_BIOS_SMP_COUNT
+#include "farptr.h" // ASSERT32
+
+#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
+#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0)
+
+#define APIC_ENABLED 0x0100
+
+static inline void writel(void *addr, u32 val)
+{
+ *(volatile u32 *)addr = val;
+}
+
+static inline void writew(void *addr, u16 val)
+{
+ *(volatile u16 *)addr = val;
+}
+
+static inline void writeb(void *addr, u8 val)
+{
+ *(volatile u8 *)addr = val;
+}
+
+static inline u32 readl(const void *addr)
+{
+ return *(volatile const u32 *)addr;
+}
+
+static inline u16 readw(const void *addr)
+{
+ return *(volatile const u16 *)addr;
+}
+
+static inline u8 readb(const void *addr)
+{
+ return *(volatile const u8 *)addr;
+}
+
+struct { u32 ecx, eax, edx; } smp_mtrr[16] VAR16_32;
+u32 smp_mtrr_count VAR16_32;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+ wrmsr(index, val);
+ if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr))
+ return;
+ smp_mtrr[smp_mtrr_count].ecx = index;
+ smp_mtrr[smp_mtrr_count].eax = val;
+ smp_mtrr[smp_mtrr_count].edx = val >> 32;
+ smp_mtrr_count++;
+}
+
+u32 CountCPUs VAR16_32;
+extern void smp_ap_boot_code();
+ASM16(
+ " .global smp_ap_boot_code\n"
+ "smp_ap_boot_code:\n"
+
+ // Setup data segment
+ " movw $" __stringify(SEG_BIOS) ", %ax\n"
+ " movw %ax, %ds\n"
+
+ // MTRR setup
+ " movl $smp_mtrr, %esi\n"
+ " movl smp_mtrr_count, %ebx\n"
+ "1:testl %ebx, %ebx\n"
+ " jz 2f\n"
+ " movl 0(%esi), %ecx\n"
+ " movl 4(%esi), %eax\n"
+ " movl 8(%esi), %edx\n"
+ " wrmsr\n"
+ " addl $12, %esi\n"
+ " decl %ebx\n"
+ " jmp 1b\n"
+ "2:\n"
+
+ // Increment the cpu counter
+ " lock incl CountCPUs\n"
+
+ // Halt the processor.
+ "1:hlt\n"
+ " jmp 1b\n"
+ );
+
+// find and initialize the CPUs by launching a SIPI to them
+void
+smp_probe(void)
+{
+ ASSERT32();
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (! (cpuid_features & CPUID_APIC)) {
+ // No apic - only the main cpu is present.
+ CountCPUs= 1;
+ return;
+ }
+
+ // Init the counter.
+ writel(&CountCPUs, 1);
+
+ // Setup jump trampoline to counter code.
+ u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+ // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
+ u64 new = (0xea | ((u64)SEG_BIOS<<24)
+ | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
+ *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+ // enable local APIC
+ u32 val = readl(APIC_SVR);
+ writel(APIC_SVR, val | APIC_ENABLED);
+
+ // broadcast SIPI
+ writel(APIC_ICR_LOW, 0x000C4500);
+ u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
+ writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+ // Wait for other CPUs to process the SIPI.
+ if (CONFIG_COREBOOT)
+ mdelay(10);
+ else
+ while (inb_cmos(CMOS_BIOS_SMP_COUNT) + 1 != readl(&CountCPUs))
+ ;
+
+ // Restore memory.
+ *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+ dprintf(1, "Found %d cpu(s)\n", readl(&CountCPUs));
+}
+
+// Reset variables to zero
+void
+smp_probe_setup(void)
+{
+ CountCPUs = 0;
+ smp_mtrr_count = 0;
+}
+++ /dev/null
-// CPU count detection
-//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
-// Copyright (C) 2006 Fabrice Bellard
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "util.h" // dprintf
-#include "config.h" // CONFIG_*
-#include "cmos.h" // CMOS_BIOS_SMP_COUNT
-#include "farptr.h" // ASSERT32
-
-#define CPUID_APIC (1 << 9)
-
-#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
-#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0)
-
-#define APIC_ENABLED 0x0100
-
-static inline void writel(void *addr, u32 val)
-{
- *(volatile u32 *)addr = val;
-}
-
-static inline void writew(void *addr, u16 val)
-{
- *(volatile u16 *)addr = val;
-}
-
-static inline void writeb(void *addr, u8 val)
-{
- *(volatile u8 *)addr = val;
-}
-
-static inline u32 readl(const void *addr)
-{
- return *(volatile const u32 *)addr;
-}
-
-static inline u16 readw(const void *addr)
-{
- return *(volatile const u16 *)addr;
-}
-
-static inline u8 readb(const void *addr)
-{
- return *(volatile const u8 *)addr;
-}
-
-u32 smp_cpus VAR16_32;
-extern void smp_ap_boot_code();
-ASM16(
- " .global smp_ap_boot_code\n"
- "smp_ap_boot_code:\n"
- // Increment the cpu counter
- " movw $" __stringify(SEG_BIOS) ", %ax\n"
- " movw %ax, %ds\n"
- " lock incl smp_cpus\n"
- // Halt the processor.
- "1:hlt\n"
- " jmp 1b\n"
- );
-
-/* find the number of CPUs by launching a SIPI to them */
-int
-smp_probe(void)
-{
- ASSERT32();
- if (smp_cpus)
- return smp_cpus;
-
- u32 eax, ebx, ecx, cpuid_features;
- cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
- if (! (cpuid_features & CPUID_APIC)) {
- // No apic - only the main cpu is present.
- smp_cpus = 1;
- return 1;
- }
-
- // Init the counter.
- writel(&smp_cpus, 1);
-
- // Setup jump trampoline to counter code.
- u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
- // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
- u64 new = (0xea | ((u64)SEG_BIOS<<24)
- | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
- *(u64*)BUILD_AP_BOOT_ADDR = new;
-
- // enable local APIC
- u32 val = readl(APIC_SVR);
- writel(APIC_SVR, val | APIC_ENABLED);
-
- // broadcast SIPI
- writel(APIC_ICR_LOW, 0x000C4500);
- u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
- writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
-
- // Wait for other CPUs to process the SIPI.
- if (CONFIG_COREBOOT)
- mdelay(10);
- else
- while (inb_cmos(CMOS_BIOS_SMP_COUNT) + 1 != readl(&smp_cpus))
- ;
-
- // Restore memory.
- *(u64*)BUILD_AP_BOOT_ADDR = old;
-
- u32 count = readl(&smp_cpus);
- dprintf(1, "Found %d cpu(s)\n", count);
- return count;
-}
-
-// Reset smp_cpus to zero (forces a recheck on reboots).
-void
-smp_probe_setup(void)
-{
- smp_cpus = 0;
-}
asm volatile("wbinvd");
}
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
static inline void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
{
asm("cpuid"
: "0" (index));
}
+static inline u64 rdmsr(u32 index)
+{
+ u64 ret;
+ asm ("rdmsr" : "=A"(ret) : "c"(index));
+ return ret;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+ asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
static inline u64 rdtscll(void)
{
u64 val;
// smm.c
void smm_init();
-// smpdetect.c
-int smp_probe(void);
+// smp.c
+extern u32 CountCPUs VAR16_32;
+void wrmsr_smp(u32 index, u64 val);
+void smp_probe(void);
void smp_probe_setup(void);
// smbios.c