From e5b140b91be34886bce3a60146f9d7b3987049ed Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Wed, 24 Jul 2019 16:44:23 +0200 Subject: implement mptable generation This is specially useful for machines lacking ACPI. Signed-off-by: Sergio Lopez --- mptable.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 mptable.c (limited to 'mptable.c') diff --git a/mptable.c b/mptable.c new file mode 100644 index 0000000..6d62cef --- /dev/null +++ b/mptable.c @@ -0,0 +1,186 @@ +#include "include/string.h" +#include "bios.h" +#include "fw_cfg.h" +#include "include/mpspec_def.h" + +#define MPTABLE_START 0x9fc00 +#define APIC_VERSION 0x14 +#define MPC_SPEC 0x4 + +#define MP_IRQDIR_DEFAULT 0 +#define MP_IRQDIR_HIGH 1 +#define MP_IRQDIR_LOW 3 + +static const char MPC_OEM[] = "QBOOT "; +static const char MPC_PRODUCT_ID[] = "000000000000"; +static const char BUS_TYPE_ISA[] = "ISA "; + +#define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000 +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 +#define APIC_VERSION 0x14 + +static int mptable_checksum(char *buf, int size) +{ + int i; + int sum = 0; + + for (i = 0; i < size; i++) { + sum += buf[i]; + } + + return sum; +} + +static void mptable_get_cpuid(int *signature, int *features) +{ + int ebx, ecx; + + asm("cpuid" + : "=a" (*signature), "=b" (ebx), "=c" (ecx), "=d" (*features) + : "0" (1)); +} + +void setup_mptable(void) +{ + struct mpf_intel *mpf; + struct mpc_table *table; + struct mpc_cpu *cpu; + struct mpc_bus *bus; + struct mpc_ioapic *ioapic; + struct mpc_intsrc *intsrc; + struct mpc_lintsrc *lintsrc; + const char mpc_signature[] = MPC_SIGNATURE; + const char smp_magic_ident[] = "_MP_"; + int cpuid_stepping, cpuid_features; + int irq0_override = 0; + int checksum = 0; + int offset = 0; + int num_cpus; + int ssize; + int i; + + ssize = sizeof(struct mpf_intel); + + mpf = (struct mpf_intel *) MPTABLE_START; + memset(mpf, 0, ssize); + memcpy(mpf->signature, smp_magic_ident, sizeof(smp_magic_ident) - 1); + mpf->length = 1; + mpf->specification = 4; + mpf->physptr = MPTABLE_START + ssize; + mpf->checksum -= mptable_checksum((char *) mpf, ssize); + + offset += ssize; + ssize = sizeof(struct mpc_table); + + table = (struct mpc_table *) (MPTABLE_START + offset); + memset(table, 0, ssize); + memcpy(table->signature, mpc_signature, sizeof(mpc_signature) - 1); + table->spec = MPC_SPEC; + memcpy(table->oem, MPC_OEM, sizeof(MPC_OEM) - 1); + memcpy(table->productid, MPC_PRODUCT_ID, sizeof(MPC_PRODUCT_ID) - 1); + table->lapic = APIC_DEFAULT_PHYS_BASE; + + offset += ssize; + ssize = sizeof(struct mpc_cpu); + + fw_cfg_select(FW_CFG_NB_CPUS); + num_cpus = fw_cfg_readl_le(); + mptable_get_cpuid(&cpuid_stepping, &cpuid_features); + + for (i = 0; i < num_cpus; i++) { + cpu = (struct mpc_cpu *) (MPTABLE_START + offset); + memset(cpu, 0, ssize); + cpu->type = MP_PROCESSOR; + cpu->apicid = i; + cpu->apicver = APIC_VERSION; + cpu->cpuflag = CPU_ENABLED; + if (i == 0) { + cpu->cpuflag |= CPU_BOOTPROCESSOR; + } + cpu->cpufeature = cpuid_stepping; + cpu->featureflag = cpuid_features; + checksum += mptable_checksum((char *) cpu, ssize); + offset += ssize; + } + + ssize = sizeof(struct mpc_bus); + + bus = (struct mpc_bus *) (MPTABLE_START + offset); + memset(bus, 0, ssize); + bus->type = MP_BUS; + bus->busid = 0; + memcpy(bus->bustype, BUS_TYPE_ISA, sizeof(BUS_TYPE_ISA) - 1); + checksum += mptable_checksum((char *) bus, ssize); + + offset += ssize; + ssize = sizeof(struct mpc_ioapic); + + ioapic = (struct mpc_ioapic *) (MPTABLE_START + offset); + memset(ioapic, 0, ssize); + ioapic->type = MP_IOAPIC; + ioapic->apicid = num_cpus + 1; + ioapic->apicver = APIC_VERSION; + ioapic->flags = MPC_APIC_USABLE; + ioapic->apicaddr = IO_APIC_DEFAULT_PHYS_BASE; + checksum += mptable_checksum((char *) ioapic, ssize); + + offset += ssize; + ssize = sizeof(struct mpc_intsrc); + + fw_cfg_select(FW_CFG_IRQ0_OVERRIDE); + irq0_override = fw_cfg_readl_le(); + + for (i = 0; i < 16; i++) { + intsrc = (struct mpc_intsrc *) (MPTABLE_START + offset); + memset(intsrc, 0, ssize); + intsrc->type = MP_INTSRC; + intsrc->irqtype = mp_INT; + intsrc->irqflag = MP_IRQDIR_DEFAULT; + intsrc->srcbus = 0; + intsrc->srcbusirq = i; + intsrc->dstapic = num_cpus + 1; + intsrc->dstirq = i; + if (irq0_override) { + if (i == 0) { + intsrc->dstirq = 2; + } else if (i == 2) { + // Don't update offset nor checksum + continue; + } + } + checksum += mptable_checksum((char *) intsrc, ssize); + offset += ssize; + } + + ssize = sizeof(struct mpc_lintsrc); + + lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); + memset(lintsrc, 0, ssize); + lintsrc->type = MP_LINTSRC; + lintsrc->irqtype = mp_ExtINT; + lintsrc->irqflag = MP_IRQDIR_DEFAULT; + lintsrc->srcbusid = 0; + lintsrc->srcbusirq = 0; + lintsrc->destapic = 0; + lintsrc->destapiclint = 0; + checksum += mptable_checksum((char *) lintsrc, ssize); + + offset += ssize; + + lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); + lintsrc->type = MP_LINTSRC; + lintsrc->irqtype = mp_NMI; + lintsrc->irqflag = MP_IRQDIR_DEFAULT; + lintsrc->srcbusid = 0; + lintsrc->srcbusirq = 0; + lintsrc->destapic = 0xFF; + lintsrc->destapiclint = 1; + checksum += mptable_checksum((char *) lintsrc, ssize); + + offset += ssize; + ssize = sizeof(struct mpc_table); + + table->length = offset - sizeof(struct mpf_intel); + checksum += mptable_checksum((char *) table, ssize); + table->checksum -= checksum; +} -- cgit v1.1