/* * Copyright (c) 1996, by Steve Passe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the developer may NOT be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * mptable.c */ #define VMAJOR 2 #define VMINOR 0 #define VDELTA 15 /* * this will cause the raw mp table to be dumped to /tmp/mpdump * #define RAW_DUMP */ #define MP_SIG 0x5f504d5f /* _MP_ */ #define EXTENDED_PROCESSING_READY #define OEM_PROCESSING_READY_NOT #include #include #include #include #include #include #include #include #define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0])) #define SEP_LINE \ "\n-------------------------------------------------------------------------------\n" #define SEP_LINE2 \ "\n===============================================================================\n" /* EBDA is @ 40:0e in real-mode terms */ #define EBDA_POINTER 0x040e /* location of EBDA pointer */ /* CMOS 'top of mem' is @ 40:13 in real-mode terms */ #define TOPOFMEM_POINTER 0x0413 /* BIOS: base memory size */ #define DEFAULT_TOPOFMEM 0xa0000 #define BIOS_BASE 0xf0000 #define BIOS_BASE2 0xe0000 #define BIOS_SIZE 0x10000 #define ONE_KBYTE 1024 #define GROPE_AREA1 0x80000 #define GROPE_AREA2 0x90000 #define GROPE_SIZE 0x10000 #define PROCENTRY_FLAG_EN 0x01 #define PROCENTRY_FLAG_BP 0x02 #define IOAPICENTRY_FLAG_EN 0x01 #define MAXPNSTR 132 #define COREBOOT_MP_TABLE 0 enum busTypes { CBUS = 1, CBUSII = 2, EISA = 3, ISA = 6, PCI = 13, XPRESS = 18, MAX_BUSTYPE = 18, UNKNOWN_BUSTYPE = 0xff }; typedef struct BUSTYPENAME { uint8_t type; char name[7]; } busTypeName; static busTypeName busTypeTable[] = { {CBUS, "CBUS"}, {CBUSII, "CBUSII"}, {EISA, "EISA"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {ISA, "ISA"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {PCI, "PCI"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"}, {UNKNOWN_BUSTYPE, "---"} }; char *whereStrings[] = { "Extended BIOS Data Area", "BIOS top of memory", "Default top of memory", "BIOS", "Extended BIOS", "GROPE AREA #1", "GROPE AREA #2" }; typedef struct TABLE_ENTRY { uint8_t type; uint8_t length; char name[32]; } tableEntry; tableEntry basetableEntryTypes[] = { {0, 20, "Processor"}, {1, 8, "Bus"}, {2, 8, "I/O APIC"}, {3, 8, "I/O INT"}, {4, 8, "Local INT"} }; tableEntry extendedtableEntryTypes[] = { {128, 20, "System Address Space"}, {129, 8, "Bus Heirarchy"}, {130, 8, "Compatibility Bus Address"} }; /* MP Floating Pointer Structure */ typedef struct MPFPS { uint8_t signature[4]; uint32_t pap; uint8_t length; uint8_t spec_rev; uint8_t checksum; uint8_t mpfb1; uint8_t mpfb2; uint8_t mpfb3; uint8_t mpfb4; uint8_t mpfb5; } mpfps_t; /* MP Configuration Table Header */ typedef struct MPCTH { uint8_t signature[4]; uint16_t base_table_length; uint8_t spec_rev; uint8_t checksum; uint8_t oem_id[8]; uint8_t product_id[12]; uint32_t oem_table_pointer; uint16_t oem_table_size; uint16_t entry_count; uint32_t apic_address; uint16_t extended_table_length; uint8_t extended_table_checksum; uint8_t reserved; } mpcth_t; typedef struct PROCENTRY { uint8_t type; uint8_t apicID; uint8_t apicVersion; uint8_t cpuFlags; uint32_t cpuSignature; uint32_t featureFlags; uint32_t reserved1; uint32_t reserved2; } ProcEntry; typedef struct BUSENTRY { uint8_t type; uint8_t busID; uint8_t busType[6]; } BusEntry; typedef struct IOAPICENTRY { uint8_t type; uint8_t apicID; uint8_t apicVersion; uint8_t apicFlags; uint32_t apicAddress; } IOApicEntry; typedef struct INTENTRY { uint8_t type; uint8_t intType; uint16_t intFlags; uint8_t srcBusID; uint8_t srcBusIRQ; uint8_t dstApicID; uint8_t dstApicINT; } IntEntry; /* * extended entry type structures */ typedef struct SASENTRY { uint8_t type; uint8_t length; uint8_t busID; uint8_t addressType; uint64_t addressBase; uint64_t addressLength; } SasEntry; typedef struct BHDENTRY { uint8_t type; uint8_t length; uint8_t busID; uint8_t busInfo; uint8_t busParent; uint8_t reserved[3]; } BhdEntry; typedef struct CBASMENTRY { uint8_t type; uint8_t length; uint8_t busID; uint8_t addressMod; uint32_t predefinedRange; } CbasmEntry; typedef uint32_t vm_offset_t; static void apic_probe(vm_offset_t * paddr, int *where); static void MPConfigDefault(int featureByte); static void MPFloatingPointer(vm_offset_t paddr, int where, mpfps_t * mpfps); static void MPConfigTableHeader(uint32_t pap); static int readType(void); static void seekEntry(vm_offset_t addr); static void readEntry(void *entry, int size); static void processorEntry(void); static void busEntry(void); static void ioApicEntry(void); static void intEntry(void); static void lintEntry(void); static void sasEntry(void); static void bhdEntry(void); static void cbasmEntry(void); static void doOptionList(void); static void doDmesg(void); static void pnstr(uint8_t * s, int c); /* global data */ int pfd; /* physical /dev/mem fd */ int busses[32]; int apics[16]; int ncpu; int nbus; int napic; int nintr; int dmesg = 0; int grope = 0; int verbose = 0; int noisy = 0; /* preamble to the mptable. This is fixed for all coreboots */ char *preamble[] = { "#include ", "#include ", "#include ", "#include ", "#include ", "#include ", "", "#define INTA 0x00", "#define INTB 0x01", "#define INTC 0x02", "#define INTD 0x03", "", "static void *smp_write_config_table(void *v)", "{", " struct mp_config_table *mc;", "", " mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);", "", " mptable_init(mc, \"TODO \", LOCAL_APIC_ADDR);", "", " smp_write_processors(mc);", "", 0 }; char *postamble[] = { " /* Compute the checksums. */", " mc->mpe_checksum = smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length);", " mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length);", " printk(BIOS_DEBUG, \"Wrote the mp table end at: %p - %p\\n\",", " mc, smp_next_mpe_entry(mc));", " return smp_next_mpe_entry(mc);", "}", "", "unsigned long write_smp_table(unsigned long addr)", "{", " void *v;", " v = smp_write_floating_table(addr);", " return (unsigned long)smp_write_config_table(v);", "}", 0 }; static void usage(void) { fprintf(stderr, "usage: mptable [-dmesg] [-verbose] [-grope] [-help]\n"); exit(0); } void write_code(char **code) { while (*code) printf("%s\n", *code++); } /* * */ int main(int argc, char *argv[]) { vm_offset_t paddr; int where; mpfps_t mpfps; int defaultConfig; /* announce ourselves */ if (verbose) puts(SEP_LINE2); printf("/* generated by MPTable, version %d.%d.%d*/\n", VMAJOR, VMINOR, VDELTA); printf("/* as modified by RGM for coreboot */\n"); write_code(preamble); /* Ron hates getopt() */ for (argc--, argv++; argc; argc--, argv++) { if (strcmp(argv[0], "-dmesg") == 0) { dmesg = 1; } else if (strcmp(argv[0], "-help") == 0) { usage(); } else if (strcmp(argv[0], "-grope") == 0) { grope = 1; } else if (strcmp(argv[0], "-verbose") == 0) verbose = 1; else if (strcmp(argv[0], "-noisy") == 0) noisy = 1; else usage(); } /* open physical memory for access to MP structures */ if ((pfd = open("/dev/mem", O_RDONLY)) < 0) err(1, "mem open"); /* probe for MP structures */ apic_probe(&paddr, &where); if (where <= 0) { fprintf(stderr, "\n MP FPS NOT found,\n"); fprintf(stderr, " suggest trying -grope option!!!\n\n"); return 1; } if (verbose) printf("\n MP FPS found in %s @ physical addr: 0x%08x\n", whereStrings[where - 1], paddr); if (verbose) puts(SEP_LINE); /* analyze the MP Floating Pointer Structure */ MPFloatingPointer(paddr, where, &mpfps); if (verbose) puts(SEP_LINE); /* check whether an MP config table exists */ if ((defaultConfig = mpfps.mpfb1)) MPConfigDefault(defaultConfig); else MPConfigTableHeader(mpfps.pap); /* build "options" entries for the kernel config file */ if (noisy) doOptionList(); write_code(postamble); /* do a dmesg output */ if (dmesg) doDmesg(); if (verbose) puts(SEP_LINE2); return 0; } /* * set PHYSICAL address of MP floating pointer structure */ #define NEXT(X) ((X) += 4) static void apic_probe(vm_offset_t * paddr, int *where) { /* * c rewrite of apic_probe() by Jack F. Vogel */ int x; u_short segment; vm_offset_t target; u_int buffer[BIOS_SIZE / sizeof(int)]; if (verbose) printf("\n"); /* search Extended Bios Data Area, if present */ if (verbose) printf(" looking for EBDA pointer @ 0x%04x, ", EBDA_POINTER); seekEntry((vm_offset_t) EBDA_POINTER); readEntry(&segment, 2); if (segment) { /* search EBDA */ target = (vm_offset_t) segment << 4; if (verbose) printf("found, searching EBDA @ 0x%08x\n", target); seekEntry(target); readEntry(buffer, ONE_KBYTE); for (x = 0; x < ONE_KBYTE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 1; *paddr = (x * sizeof(unsigned int)) + target; return; } } } else { if (verbose) printf("NOT found\n"); } target = 0; segment = 0; if (verbose) printf(" searching for coreboot MP table @ 0x%08x (%dK)\n", target, segment); seekEntry(target); readEntry(buffer, ONE_KBYTE); for (x = 0; x < ONE_KBYTE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 2; *paddr = (x * sizeof(unsigned int)) + target; return; } } /* read CMOS for real top of mem */ seekEntry((vm_offset_t) TOPOFMEM_POINTER); readEntry(&segment, 2); --segment; /* less ONE_KBYTE */ target = segment * 1024; if (verbose) printf(" searching CMOS 'top of mem' @ 0x%08x (%dK)\n", target, segment); seekEntry(target); readEntry(buffer, ONE_KBYTE); for (x = 0; x < ONE_KBYTE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 2; *paddr = (x * sizeof(unsigned int)) + target; return; } } /* we don't necessarily believe CMOS, check base of the last 1K of 640K */ if (target != (DEFAULT_TOPOFMEM - 1024)) { target = (DEFAULT_TOPOFMEM - 1024); if (verbose) printf (" searching default 'top of mem' @ 0x%08x (%dK)\n", target, (target / 1024)); seekEntry(target); readEntry(buffer, ONE_KBYTE); for (x = 0; x < ONE_KBYTE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 3; *paddr = (x * sizeof(unsigned int)) + target; return; } } } /* search the BIOS */ if (verbose) printf(" searching BIOS @ 0x%08x\n", BIOS_BASE); seekEntry(BIOS_BASE); readEntry(buffer, BIOS_SIZE); for (x = 0; x < BIOS_SIZE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 4; *paddr = (x * sizeof(unsigned int)) + BIOS_BASE; return; } } /* search the extended BIOS */ if (verbose) printf(" searching extended BIOS @ 0x%08x\n", BIOS_BASE2); seekEntry(BIOS_BASE2); readEntry(buffer, BIOS_SIZE); for (x = 0; x < BIOS_SIZE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 5; *paddr = (x * sizeof(unsigned int)) + BIOS_BASE2; return; } } if (grope) { /* search additional memory */ target = GROPE_AREA1; if (verbose) printf(" groping memory @ 0x%08x\n", target); seekEntry(target); readEntry(buffer, GROPE_SIZE); for (x = 0; x < GROPE_SIZE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 6; *paddr = (x * sizeof(unsigned int)) + GROPE_AREA1; return; } } target = GROPE_AREA2; if (verbose) printf(" groping memory @ 0x%08x\n", target); seekEntry(target); readEntry(buffer, GROPE_SIZE); for (x = 0; x < GROPE_SIZE / sizeof(unsigned int); NEXT(x)) { if (buffer[x] == MP_SIG) { *where = 7; *paddr = (x * sizeof(unsigned int)) + GROPE_AREA2; return; } } } *where = 0; *paddr = (vm_offset_t) 0; } /* * */ static void MPFloatingPointer(vm_offset_t paddr, int where, mpfps_t * mpfps) { /* read in mpfps structure */ seekEntry(paddr); readEntry(mpfps, sizeof(mpfps_t)); /* show its contents */ if (verbose) { printf("MP Floating Pointer Structure:\n\n"); printf(" location:\t\t\t"); switch (where) { case 1: printf("EBDA\n"); break; case 2: printf("BIOS base memory\n"); break; case 3: printf("DEFAULT base memory (639K)\n"); break; case 4: printf("BIOS\n"); break; case 5: printf("Extended BIOS\n"); break; case 0: printf("NOT found!\n"); exit(1); default: printf("BOGUS!\n"); exit(1); } printf(" physical address:\t\t0x%08x\n", paddr); printf(" signature:\t\t\t'"); pnstr(mpfps->signature, 4); printf("'\n"); printf(" length:\t\t\t%d bytes\n", mpfps->length * 16); printf(" version:\t\t\t1.%1d\n", mpfps->spec_rev); printf(" checksum:\t\t\t0x%02x\n", mpfps->checksum); /* bits 0:6 are RESERVED */ if (mpfps->mpfb2 & 0x7f) { printf(" warning, MP feature byte 2: 0x%02x\n", mpfps->mpfb2); } /* bit 7 is IMCRP */ printf(" mode:\t\t\t\t%s\n", (mpfps->mpfb2 & 0x80) ? "PIC" : "Virtual Wire"); /* MP feature bytes 3-5 are expected to be ZERO */ if (mpfps->mpfb3) printf(" warning, MP feature byte 3 NONZERO!\n"); if (mpfps->mpfb4) printf(" warning, MP feature byte 4 NONZERO!\n"); if (mpfps->mpfb5) printf(" warning, MP feature byte 5 NONZERO!\n"); } } /* * */ static void MPConfigDefault(int featureByte) { printf(" MP default config type: %d\n\n", featureByte); switch (featureByte) { case 1: printf(" bus: ISA, APIC: 82489DX\n"); break; case 2: printf(" bus: EISA, APIC: 82489DX\n"); break; case 3: printf(" bus: EISA, APIC: 82489DX\n"); break; case 4: printf(" bus: MCA, APIC: 82489DX\n"); break; case 5: printf(" bus: ISA+PCI, APIC: Integrated\n"); break; case 6: printf(" bus: EISA+PCI, APIC: Integrated\n"); break; case 7: printf(" bus: MCA+PCI, APIC: Integrated\n"); break; default: printf(" future type\n"); break; } switch (featureByte) { case 1: case 2: case 3: case 4: nbus = 1; break; case 5: case 6: case 7: nbus = 2; break; default: printf(" future type\n"); break; } ncpu = 2; napic = 1; nintr = 16; } /* * */ static void MPConfigTableHeader(uint32_t pap) { vm_offset_t paddr; mpcth_t cth; int x; int totalSize; int count, c; int type; if (pap == 0) { printf("MP Configuration Table Header MISSING!\n"); exit(1); } /* convert physical address to virtual address */ paddr = (vm_offset_t) pap; /* read in cth structure */ seekEntry(paddr); readEntry(&cth, sizeof(cth)); if (verbose) { printf("MP Config Table Header:\n\n"); printf(" physical address:\t\t0x%08x\n", pap); printf(" signature:\t\t\t'"); pnstr(cth.signature, 4); printf("'\n"); printf(" base table length:\t\t%d\n", cth.base_table_length); printf(" version:\t\t\t1.%1d\n", cth.spec_rev); printf(" checksum:\t\t\t0x%02x\n", cth.checksum); printf(" OEM ID:\t\t\t'"); pnstr(cth.oem_id, 8); printf("'\n"); printf(" Product ID:\t\t\t'"); pnstr(cth.product_id, 12); printf("'\n"); printf(" OEM table pointer:\t\t0x%08x\n", cth.oem_table_pointer); printf(" OEM table size:\t\t%d\n", cth.oem_table_size); printf(" entry count:\t\t\t%d\n", cth.entry_count); printf(" local APIC address:\t\t0x%08x\n", cth.apic_address); printf(" extended table length:\t%d\n", cth.extended_table_length); printf(" extended table checksum:\t%d\n", cth.extended_table_checksum); } totalSize = cth.base_table_length - sizeof(struct MPCTH); count = cth.entry_count; if (verbose) { if (verbose) puts(SEP_LINE); printf("MP Config Base Table Entries:\n\n"); } /* initialze tables */ for(x = 0; x < ARRAY_SIZE(busses); x++) busses[x] = UNKNOWN_BUSTYPE; for(x = 0; x < ARRAY_SIZE(apics); x++) apics[x] = 0xff; ncpu = 0; nbus = 0; napic = 0; nintr = 0; /* process all the CPUs */ if (verbose) { printf("--\nProcessors:\tAPIC ID\tVersion\tState" "\t\tFamily\tModel\tStep\tFlags\n"); } for (c = count; c; c--) { if (readType() == 0) processorEntry(); totalSize -= basetableEntryTypes[0].length; } /* process all the busses */ printf("\t/* Bus: Bus ID Type */\n"); for (c = count; c; c--) { if (readType() == 1) busEntry(); totalSize -= basetableEntryTypes[1].length; } /* process all the apics */ printf("\t/* I/O APICs: APIC ID Version State Address */\n"); for (c = count; c; c--) { if (readType() == 2) ioApicEntry(); totalSize -= basetableEntryTypes[2].length; } /* process all the I/O Ints */ printf("\t/* I/O Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN#*/ \n"); for (c = count; c; c--) { if (readType() == 3) intEntry(); totalSize -= basetableEntryTypes[3].length; } /* process all the Local Ints */ printf ("\t/* Local Ints: Type Polarity Trigger Bus ID IRQ APIC ID PIN# */\n"); for (c = count; c; c--) { if (readType() == 4) lintEntry(); totalSize -= basetableEntryTypes[4].length; } #if defined( EXTENDED_PROCESSING_READY ) /* process any extended data */ if ((totalSize = cth.extended_table_length)) { if (verbose) puts(SEP_LINE); printf("MP Config Extended Table Entries:\n\n"); while (totalSize > 0) { switch (type = readType()) { case 128: sasEntry(); break; case 129: bhdEntry(); break; case 130: cbasmEntry(); break; default: printf("Extended Table HOSED!\n"); exit(1); } totalSize -= extendedtableEntryTypes[type - 128].length; } } #endif /* EXTENDED_PROCESSING_READY */ /* process any OEM data */ if (cth.oem_table_pointer && (cth.oem_table_size > 0)) { #if defined( OEM_PROCESSING_READY ) #error your on your own here! /* convert OEM table pointer to virtual address */ poemtp = (vm_offset_t) cth.oem_table_pointer; /* read in oem table structure */ if ((oemdata = (void *)malloc(cth.oem_table_size)) == NULL) err(1, "oem malloc"); seekEntry(poemtp); readEntry(oemdata, cth.oem_table_size); /** process it */ free(oemdata); #else printf ("\nyou need to modify the source to handle OEM data!\n\n"); #endif /* OEM_PROCESSING_READY */ } fflush(stdout); #if defined( RAW_DUMP ) { int ofd; u_char dumpbuf[4096]; ofd = open("/tmp/mpdump", O_CREAT | O_RDWR); seekEntry(paddr); readEntry(dumpbuf, 1024); write(ofd, dumpbuf, 1024); close(ofd); } #endif /* RAW_DUMP */ } /* * */ static int readType(void) { u_char type; if (read(pfd, &type, sizeof(u_char)) != sizeof(u_char)) err(1, "type read; pfd: %d", pfd); if (lseek(pfd, -1, SEEK_CUR) < 0) err(1, "type seek"); return (int)type; } /* * */ static void seekEntry(vm_offset_t addr) { if (lseek(pfd, (off_t) addr, SEEK_SET) < 0) err(1, "/dev/mem seek"); } /* * */ static void readEntry(void *entry, int size) { if (read(pfd, entry, size) != size) err(1, "readEntry"); } static void processorEntry(void) { ProcEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); /* count it */ ++ncpu; if (noisy) { printf("\t\t%2d", entry.apicID); printf("\t 0x%2x", entry.apicVersion); printf("\t %s, %s", (entry.cpuFlags & PROCENTRY_FLAG_BP) ? "BSP" : "AP", (entry. cpuFlags & PROCENTRY_FLAG_EN) ? "usable" : "unusable"); printf("\t %d\t %d\t %d", (entry.cpuSignature >> 8) & 0x0f, (entry.cpuSignature >> 4) & 0x0f, entry.cpuSignature & 0x0f); printf("\t 0x%04x\n", entry.featureFlags); } } /* * */ static int lookupBusType(char *name) { int x; for (x = 0; x < MAX_BUSTYPE; ++x) if (strcmp(busTypeTable[x].name, name) == 0) return busTypeTable[x].type; return UNKNOWN_BUSTYPE; } static void busEntry(void) { char name[8]; BusEntry entry; int i; /* read it into local memory */ readEntry(&entry, sizeof(entry)); /* count it */ ++nbus; if (verbose) { printf("\t\t%2d", entry.busID); printf("\t "); pnstr(entry.busType, 6); printf("\n"); } memset(name, '\0', sizeof(name)); for(i = 0; i < 6; i++) { switch(entry.busType[i]) { case ' ': case '\0': break; default: name[i] = entry.busType[i]; break; } } if (entry.busID > ARRAY_SIZE(busses)) { fprintf(stderr, "busses array to small!\n"); exit(1); } busses[entry.busID] = lookupBusType(name); printf("\tsmp_write_bus(mc, %d, \"", entry.busID); pnstr(entry.busType, 6); printf("\");\n"); } static void ioApicEntry(void) { IOApicEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); /* count it */ ++napic; if (noisy) { printf("\t\t%2d", entry.apicID); printf("\t 0x%02x", entry.apicVersion); printf("\t %s", (entry. apicFlags & IOAPICENTRY_FLAG_EN) ? "usable" : "unusable"); printf("\t\t 0x%x\n", entry.apicAddress); } apics[entry.apicID] = entry.apicID; if (entry.apicFlags & IOAPICENTRY_FLAG_EN) printf("\tsmp_write_ioapic(mc, 0x%x, 0x%x, 0x%x);\n", entry.apicID, entry.apicVersion, entry.apicAddress); } char *intTypes[] = { "mp_INT", "mp_NMI", "mp_SMI", "mp_ExtINT" }; char *polarityMode[] = { "MP_IRQ_POLARITY_DEFAULT", "MP_IRQ_POLARITY_HIGH", "reserved", "MP_IRQ_POLARITY_LOW" }; char *triggerMode[] = { "MP_IRQ_TRIGGER_DEFAULT", "MP_IRQ_TRIGGER_EDGE", "reserved", "MP_IRQ_TRIGGER_LEVEL" }; static void intEntry(void) { IntEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); /* count it */ if ((int)entry.type == 3) ++nintr; if (noisy) { printf("\n\t\t%s", intTypes[(int)entry.intType]); printf("\t%9s", polarityMode[(int)entry.intFlags & 0x03]); printf("%12s", triggerMode[((int)entry.intFlags >> 2) & 0x03]); printf("\t %5d", (int)entry.srcBusID); if (busses[(int)entry.srcBusID] == PCI) printf("\t%2d:%c", ((int)entry.srcBusIRQ >> 2) & 0x1f, ((int)entry.srcBusIRQ & 0x03) + 'A'); else printf("\t 0x%x:0x%x(0x%x)", (int)entry.srcBusIRQ >> 2, (int)entry.srcBusIRQ & 3, (int)entry.srcBusIRQ); printf("\t %6d", (int)entry.dstApicID); printf("\t %3d\n", (int)entry.dstApicINT); } if (busses[(int)entry.srcBusID] == PCI) { printf("\tsmp_write_intsrc(mc, %s, %s|%s, 0x%x, (0x%02x << 2) | INT%c, 0x%x, 0x%x);\n", intTypes[(int)entry.intType], triggerMode[((int)entry.intFlags >> 2) & 0x03], polarityMode[(int)entry.intFlags & 0x03], (int)entry.srcBusID, (int)entry.srcBusIRQ >> 2, ((int)entry.srcBusIRQ & 3) + 'A', (int)entry.dstApicID, (int)entry.dstApicINT); } else { printf("\tsmp_write_intsrc(mc, %s, %s|%s, 0x%x, 0x%x, 0x%x, 0x%x);\n", intTypes[(int)entry.intType], triggerMode[((int)entry.intFlags >> 2) & 0x03], polarityMode[(int)entry.intFlags & 0x03], (int)entry.srcBusID, (int)entry.srcBusIRQ, (int)entry.dstApicID, (int)entry.dstApicINT); } } static void lintEntry(void) { IntEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); /* count it */ if ((int)entry.type == 3) ++nintr; if (noisy) { printf("\t\t%s", intTypes[(int)entry.intType]); printf("\t%9s", polarityMode[(int)entry.intFlags & 0x03]); printf("%12s", triggerMode[((int)entry.intFlags >> 2) & 0x03]); printf("\t %5d", (int)entry.srcBusID); if (busses[(int)entry.srcBusID] == PCI) printf("\t%2d:%c", ((int)entry.srcBusIRQ >> 2) & 0x1f, ((int)entry.srcBusIRQ & 0x03) + 'A'); else printf("\t %3d", (int)entry.srcBusIRQ); printf("\t %6d", (int)entry.dstApicID); printf("\t %3d\n", (int)entry.dstApicINT); } printf ("\tsmp_write_lintsrc(mc, %s, %s|%s, 0x%x, 0x%x, MP_APIC_ALL, 0x%x);\n", intTypes[(int)entry.intType], triggerMode[((int)entry.intFlags >> 2) & 0x03], polarityMode[(int)entry.intFlags & 0x03], (int)entry.srcBusID, (int)entry.srcBusIRQ, (int)entry.dstApicINT); } static void sasEntry(void) { SasEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); printf("--\n%s\n", extendedtableEntryTypes[entry.type - 128].name); printf(" bus ID: %d", entry.busID); printf(" address type: "); switch (entry.addressType) { case 0: printf("I/O address\n"); break; case 1: printf("memory address\n"); break; case 2: printf("prefetch address\n"); break; default: printf("UNKNOWN type\n"); break; } printf(" address base: 0x%lx\n", entry.addressBase); printf(" address range: 0x%lx\n", entry.addressLength); } static void bhdEntry(void) { BhdEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); printf("--\n%s\n", extendedtableEntryTypes[entry.type - 128].name); printf(" bus ID: %d", entry.busID); printf(" bus info: 0x%02x", entry.busInfo); printf(" parent bus ID: %d", entry.busParent); } static void cbasmEntry(void) { CbasmEntry entry; /* read it into local memory */ readEntry(&entry, sizeof(entry)); printf("--\n%s\n", extendedtableEntryTypes[entry.type - 128].name); printf(" bus ID: %d", entry.busID); printf(" address modifier: %s\n", (entry.addressMod & 0x01) ? "subtract" : "add"); printf(" predefined range: 0x%08x", entry.predefinedRange); } /* * do a dmesg output */ static void doDmesg(void) { if (verbose) puts(SEP_LINE); printf("dmesg output:\n\n"); fflush(stdout); system("dmesg"); } /* * build "options" entries for the kernel config file */ static void doOptionList(void) { if (verbose) puts(SEP_LINE); printf("# SMP kernel config file options:\n\n"); printf("\n# Required:\n"); printf("options SMP\t\t\t# Symmetric MultiProcessor Kernel\n"); printf("options APIC_IO\t\t\t# Symmetric (APIC) I/O\n"); printf("\n# Optional (built-in defaults will work in most cases):\n"); printf("#options NCPU=%d\t\t\t# number of CPUs\n", ncpu); printf("#options NBUS=%d\t\t\t# number of busses\n", nbus); printf("#options NAPIC=%d\t\t\t# number of IO APICs\n", napic); printf("#options NINTR=%d\t\t# number of INTs\n", (nintr < 24) ? 24 : nintr); } /* * */ static void pnstr(uint8_t * s, int c) { uint8_t string[MAXPNSTR + 1]; if (c > MAXPNSTR) c = MAXPNSTR; strncpy((char *)string, (char *)s, c); string[c] = '\0'; printf("%s", string); }