aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergio Lopez <slp@redhat.com>2019-07-24 16:44:23 +0200
committerPaolo Bonzini <bonzini@gnu.org>2019-07-24 16:55:26 +0200
commite5b140b91be34886bce3a60146f9d7b3987049ed (patch)
treee5a4589521cd1fc69573b7f4091f1fab8043c104
parent947bade3443facfb07f20ca10b4436bc9eb4ef27 (diff)
downloadqboot-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--Makefile1
-rw-r--r--include/bios.h1
-rw-r--r--include/mpspec_def.h182
-rw-r--r--main.c1
-rw-r--r--mptable.c186
5 files changed, 371 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index b96dd09..ee707a4 100644
--- a/Makefile
+++ b/Makefile
@@ -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 */
diff --git a/main.c b/main.c
index b20a7de..2f6fc78 100644
--- a/main.c
+++ b/main.c
@@ -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;
+}