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