diff options
author | Sergio Lopez <slp@redhat.com> | 2019-07-24 16:44:23 +0200 |
---|---|---|
committer | Paolo Bonzini <bonzini@gnu.org> | 2019-07-24 16:55:26 +0200 |
commit | e5b140b91be34886bce3a60146f9d7b3987049ed (patch) | |
tree | e5a4589521cd1fc69573b7f4091f1fab8043c104 | |
parent | 947bade3443facfb07f20ca10b4436bc9eb4ef27 (diff) | |
download | qboot-e5b140b91be34886bce3a60146f9d7b3987049ed.zip qboot-e5b140b91be34886bce3a60146f9d7b3987049ed.tar.gz qboot-e5b140b91be34886bce3a60146f9d7b3987049ed.tar.bz2 |
implement mptable generation
This is specially useful for machines lacking ACPI.
Signed-off-by: Sergio Lopez <slp@redhat.com>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | include/bios.h | 1 | ||||
-rw-r--r-- | include/mpspec_def.h | 182 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | mptable.c | 186 |
5 files changed, 371 insertions, 0 deletions
@@ -1,5 +1,6 @@ obj-y = code16.o entry.o main.o string.o printf.o cstart.o fw_cfg.o obj-y += linuxboot.o malloc.o pflash.o tables.o hwsetup.o pci.o code32seg.o +obj-y += mptable.o all-y = bios.bin all: $(all-y) diff --git a/include/bios.h b/include/bios.h index 1469cb6..f36638b 100644 --- a/include/bios.h +++ b/include/bios.h @@ -66,6 +66,7 @@ extern uint32_t pic_base(void); extern void setup_pci(void); extern bool setup_hw(void); extern bool setup_mmconfig(void); +extern void setup_mptable(void); extern void extract_acpi(void); extern void boot_from_fwcfg(void); diff --git a/include/mpspec_def.h b/include/mpspec_def.h new file mode 100644 index 0000000..6fb923a --- /dev/null +++ b/include/mpspec_def.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_MPSPEC_DEF_H +#define _ASM_X86_MPSPEC_DEF_H + +/* + * Structure definitions for SMP machines following the + * Intel Multiprocessing Specification 1.1 and 1.4. + */ + +/* + * This tag identifies where the SMP configuration + * information is. + */ + +#define SMP_MAGIC_IDENT (('_'<<24) | ('P'<<16) | ('M'<<8) | '_') + +#ifdef CONFIG_X86_32 +# define MAX_MPC_ENTRY 1024 +#endif + +/* Intel MP Floating Pointer Structure */ +struct mpf_intel { + char signature[4]; /* "_MP_" */ + unsigned int physptr; /* Configuration table address */ + unsigned char length; /* Our length (paragraphs) */ + unsigned char specification; /* Specification version */ + unsigned char checksum; /* Checksum (makes sum 0) */ + unsigned char feature1; /* Standard or configuration ? */ + unsigned char feature2; /* Bit7 set for IMCR|PIC */ + unsigned char feature3; /* Unused (0) */ + unsigned char feature4; /* Unused (0) */ + unsigned char feature5; /* Unused (0) */ +}; + +#define MPC_SIGNATURE "PCMP" + +struct mpc_table { + char signature[4]; + unsigned short length; /* Size of table */ + char spec; /* 0x01 */ + char checksum; + char oem[8]; + char productid[12]; + unsigned int oemptr; /* 0 if not present */ + unsigned short oemsize; /* 0 if not present */ + unsigned short oemcount; + unsigned int lapic; /* APIC address */ + unsigned int reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 +/* Used by IBM NUMA-Q to describe node locality */ +#define MP_TRANSLATION 192 + +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the boot CPU */ + +#define CPU_STEPPING_MASK 0x000F +#define CPU_MODEL_MASK 0x00F0 +#define CPU_FAMILY_MASK 0x0F00 + +struct mpc_cpu { + unsigned char type; + unsigned char apicid; /* Local APIC number */ + unsigned char apicver; /* Its versions */ + unsigned char cpuflag; + unsigned int cpufeature; + unsigned int featureflag; /* CPUID feature value */ + unsigned int reserved[2]; +}; + +struct mpc_bus { + unsigned char type; + unsigned char busid; + unsigned char bustype[6]; +}; + +/* List of Bus Type string values, Intel MP Spec. */ +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" /* Obsolete */ +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_CBUS "CBUS" +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_MBI "MBI" +#define BUSTYPE_MBII "MBII" +#define BUSTYPE_MPI "MPI" +#define BUSTYPE_MPSA "MPSA" +#define BUSTYPE_NUBUS "NUBUS" +#define BUSTYPE_TC "TC" +#define BUSTYPE_VME "VME" +#define BUSTYPE_XPRESS "XPRESS" + +#define MPC_APIC_USABLE 0x01 + +struct mpc_ioapic { + unsigned char type; + unsigned char apicid; + unsigned char apicver; + unsigned char flags; + unsigned int apicaddr; +}; + +struct mpc_intsrc { + unsigned char type; + unsigned char irqtype; + unsigned short irqflag; + unsigned char srcbus; + unsigned char srcbusirq; + unsigned char dstapic; + unsigned char dstirq; +}; + +enum mp_irq_source_types { + mp_INT = 0, + mp_NMI = 1, + mp_SMI = 2, + mp_ExtINT = 3 +}; + +#define MP_IRQPOL_DEFAULT 0x0 +#define MP_IRQPOL_ACTIVE_HIGH 0x1 +#define MP_IRQPOL_RESERVED 0x2 +#define MP_IRQPOL_ACTIVE_LOW 0x3 +#define MP_IRQPOL_MASK 0x3 + +#define MP_IRQTRIG_DEFAULT 0x0 +#define MP_IRQTRIG_EDGE 0x4 +#define MP_IRQTRIG_RESERVED 0x8 +#define MP_IRQTRIG_LEVEL 0xc +#define MP_IRQTRIG_MASK 0xc + +#define MP_APIC_ALL 0xFF + +struct mpc_lintsrc { + unsigned char type; + unsigned char irqtype; + unsigned short irqflag; + unsigned char srcbusid; + unsigned char srcbusirq; + unsigned char destapic; + unsigned char destapiclint; +}; + +#define MPC_OEM_SIGNATURE "_OEM" + +struct mpc_oemtable { + char signature[4]; + unsigned short length; /* Size of table */ + char rev; /* 0x01 */ + char checksum; + char mpc[8]; +}; + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + +enum mp_bustype { + MP_BUS_ISA = 1, + MP_BUS_EISA, + MP_BUS_PCI, +}; +#endif /* _ASM_X86_MPSPEC_DEF_H */ @@ -98,6 +98,7 @@ int __attribute__ ((section (".text.startup"))) main(void) fw_cfg_setup(); extract_acpi(); extract_e820(); + setup_mptable(); // extract_smbios(); boot_from_fwcfg(); panic(); 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; +} |