186 lines
4.7 KiB
C
186 lines
4.7 KiB
C
#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;
|
|
}
|