implement mptable generation

This is specially useful for machines lacking ACPI.

Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
Sergio Lopez
2019-07-24 16:44:23 +02:00
committed by Paolo Bonzini
parent 947bade344
commit e5b140b91b
5 changed files with 371 additions and 0 deletions

View File

@ -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)

View File

@ -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);

182
include/mpspec_def.h Normal file
View File

@ -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 */

1
main.c
View File

@ -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();

186
mptable.c Normal file
View File

@ -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;
}