aboutsummaryrefslogtreecommitdiff
path: root/mptable.c
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 /mptable.c
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>
Diffstat (limited to 'mptable.c')
-rw-r--r--mptable.c186
1 files changed, 186 insertions, 0 deletions
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;
+}