Hello build bot (Jenkins), Patrick Georgi, Paul Menzel, Alexandru Gagniuc,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/48322
to review the following change.
Change subject: Revert "util: Remove 'getpir' and 'mptable' tools" ......................................................................
Revert "util: Remove 'getpir' and 'mptable' tools"
This reverts commit 6c90f3334e65ff4b0ff4900df77bc33d53beb677.
Reason for revert: Although the output of these tools is indeed far from being perfect, still it could be used as a nice starting point.
Change-Id: Ieff7673387ae9275b8271f4a483926b774697a8d --- A util/getpir/Makefile A util/getpir/README A util/getpir/checkpir.c A util/getpir/checksum.c A util/getpir/checksum.h A util/getpir/code_gen.c A util/getpir/code_gen.h A util/getpir/getpir.c A util/getpir/pirq_routing.h A util/mptable/Makefile A util/mptable/mptable.c 11 files changed, 1,708 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/22/48322/1
diff --git a/util/getpir/Makefile b/util/getpir/Makefile new file mode 100644 index 0000000..94270f5 --- /dev/null +++ b/util/getpir/Makefile @@ -0,0 +1,24 @@ +# +# +# + +CC=gcc +CFLAGS=-O2 -D_GNU_SOURCE -DGETPIR -Wall + +all: getpir + +getpir: getpir.o checksum.o code_gen.o + $(CC) $(CFLAGS) -o getpir $^ + +checkpir: checkpir.c checksum.o irq_tables.o + $(CC) $(CFLAGS) -o checkpir $^ + +irq_tables.c: getpir + ./getpir + +clean: + rm -f getpir checkpir *.o *~ + +distclean: clean + rm -f irq_tables.o irq_tables.c + diff --git a/util/getpir/README b/util/getpir/README new file mode 100644 index 0000000..6514585 --- /dev/null +++ b/util/getpir/README @@ -0,0 +1,30 @@ +ABOUT: + +This utility will help to create irq_table.c file, that is very hard to create +manually, specialy when you are testing new motherboards, changing your +hardware often, placing new cards, etc.. + +USAGE: + +Steps +1. make distclean; +2. make getpir +3. ./getpir + + Will dump irq table to the file called irq_tables.c, ready to use with + coreboot. Just move the file to corresponding place in the coreboot tree. + + +4. CHECKING CUSTOM irq_tables.c: + + make checkpir + ./checkpir + + checkpir.c Will verify the irq_tables.c, currently it only checks the + checksum. In case of wrong checksum, a good value is proposed, so you can + edit irq_tables.c manualy and replace checksum. + + +Do not run make checkpir and ./checkpir directly because it needs to be linked +to irq_table.o first. + diff --git a/util/getpir/checkpir.c b/util/getpir/checkpir.c new file mode 100644 index 0000000..c9703c6 --- /dev/null +++ b/util/getpir/checkpir.c @@ -0,0 +1,31 @@ +/* checkpir.c : This software is released under GPL + * For coreboot use only + * Aug 26 2001 , Nikolai Vladychevski, niko@isl.net.mx + */ + +#include <stdio.h> +#include "pirq_routing.h" +#include "checksum.h" + +struct irq_routing_table *rt; + +int main(void) +{ + uint8_t sum, newsum; + + rt = (struct irq_routing_table *) &intel_irq_routing_table; + sum = calc_checksum(rt); + + printf("Validating checksum, file: irq_tables.c that was in ./ at compile time...\n"); + printf("(no other tests are done)\n"); + + if (!sum) { + printf("Checksum for IRQ Routing table is ok. You can use irq_tables.c in coreboot now.\n"); + } else { + newsum = rt->checksum - sum; + printf("BAD CHECKSUM for IRQ Routing table !!!!\n"); + printf("If you want to make it valid, change the checksum to: %#x\n", + newsum); + } + return 0; +} diff --git a/util/getpir/checksum.c b/util/getpir/checksum.c new file mode 100644 index 0000000..bcf3425 --- /dev/null +++ b/util/getpir/checksum.c @@ -0,0 +1,13 @@ +#include "pirq_routing.h" +#include "checksum.h" + +int calc_checksum(struct irq_routing_table *rt) +{ + long i; + uint8_t *addr, sum = 0; + + addr = (uint8_t *) rt; + for (i = 0; i < rt->size; i++) + sum += addr[i]; + return (sum); +} diff --git a/util/getpir/checksum.h b/util/getpir/checksum.h new file mode 100644 index 0000000..2acc433 --- /dev/null +++ b/util/getpir/checksum.h @@ -0,0 +1,6 @@ +#ifndef __CHECKSUM_H__ +#define __CHECKSUM_H__ + +int calc_checksum(struct irq_routing_table *rt); + +#endif /* __CHECKSUM_H__ */ diff --git a/util/getpir/code_gen.c b/util/getpir/code_gen.c new file mode 100644 index 0000000..d15715c --- /dev/null +++ b/util/getpir/code_gen.c @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <stdlib.h> +#include "pirq_routing.h" + +static char *preamble[] = { + + "/*\n", + " * This file is part of the coreboot project.\n", + " *\n", + " * Copyright (C) 200x TODO TODO@TODO\n", + " *\n", + " * This program is free software; you can redistribute it and/or modify\n", + " * it under the terms of the GNU General Public License as published by\n", + " * the Free Software Foundation; either version 2 of the License, or\n", + " * (at your option) any later version.\n", + " *\n", + " * This program is distributed in the hope that it will be useful,\n", + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n", + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n", + " * GNU General Public License for more details.\n", + " *\n", + " * You should have received a copy of the GNU General Public License\n", + " * along with this program; if not, write to the Free Software\n", + " * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", + " */\n\n", + "#ifdef GETPIR /* TODO: Drop this when copying to coreboot. */\n", + "#include "pirq_routing.h" /* TODO: Drop this when copying to coreboot. */\n", + "#else /* TODO: Drop this when copying to coreboot. */\n" + "#include <arch/pirq_routing.h>\n", + "#endif /* TODO: Drop this when copying to coreboot. */\n\n" + "const struct irq_routing_table intel_irq_routing_table = {\n", + "\tPIRQ_SIGNATURE, /* u32 signature */\n", + "\tPIRQ_VERSION, /* u16 version */\n", + 0 +}; + +void code_gen(char *filename, struct irq_routing_table *rt) +{ + char **code = preamble; + struct irq_info *se_arr = (struct irq_info *) ((char *) rt + 32); + int i, ts = (rt->size - 32) / 16; + FILE *fpir; + + if ((fpir = fopen(filename, "w")) == NULL) { + printf("Failed creating file!\n"); + exit(2); + } + + while (*code) + fprintf(fpir, "%s", *code++); + + fprintf(fpir, "\t32 + 16 * %d, /* Max. number of devices on the bus */\n", + ts); + fprintf(fpir, "\t0x%02x, /* Interrupt router bus */\n", + rt->rtr_bus); + fprintf(fpir, "\t(0x%02x << 3) | 0x%01x, /* Interrupt router dev */\n", + rt->rtr_devfn >> 3, rt->rtr_devfn & 7); + fprintf(fpir, "\t%#x, /* IRQs devoted exclusively to PCI usage */\n", + rt->exclusive_irqs); + fprintf(fpir, "\t%#x, /* Vendor */\n", rt->rtr_vendor); + fprintf(fpir, "\t%#x, /* Device */\n", rt->rtr_device); + fprintf(fpir, "\t%#x, /* Miniport */\n", + rt->miniport_data); + fprintf(fpir, "\t{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */\n"); + fprintf(fpir, "\t%#x, /* Checksum (has to be set to some value that\n * would give 0 after the sum of all bytes\n * for this structure (including checksum).\n */\n", + rt->checksum); + fprintf(fpir, "\t{\n"); + fprintf(fpir, "\t\t/* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */\n"); + for (i = 0; i < ts; i++) { + fprintf(fpir, "\t\t{0x%02x, (0x%02x << 3) | 0x%01x, {{0x%02x, 0x%04x}, {0x%02x, 0x%04x}, {0x%02x, 0x%04x}, {0x%02x, 0x%04x}}, 0x%x, 0x%x},\n", + (se_arr+i)->bus, (se_arr+i)->devfn >> 3, + (se_arr+i)->devfn & 7, (se_arr+i)->irq[0].link, + (se_arr+i)->irq[0].bitmap, (se_arr+i)->irq[1].link, + (se_arr+i)->irq[1].bitmap, (se_arr+i)->irq[2].link, + (se_arr+i)->irq[2].bitmap, (se_arr+i)->irq[3].link, + (se_arr+i)->irq[3].bitmap, (se_arr+i)->slot, + (se_arr+i)->rfu); + } + fprintf(fpir, "\t}\n"); + fprintf(fpir, "};\n"); + + fprintf(fpir, "\nunsigned long write_pirq_routing_table(unsigned long addr)\n"); + fprintf(fpir, "{\n"); + fprintf(fpir, "\treturn copy_pirq_routing_table(addr);\n"); + fprintf(fpir, "}\n"); + + fclose(fpir); +} diff --git a/util/getpir/code_gen.h b/util/getpir/code_gen.h new file mode 100644 index 0000000..93bdaec --- /dev/null +++ b/util/getpir/code_gen.h @@ -0,0 +1,6 @@ +#ifndef __CODE_GEN_H__ +#define __CODE_GEN_H__ + +void code_gen(char *filename, struct irq_routing_table *rt); + +#endif /* __CODE_GEN_H__ */ diff --git a/util/getpir/getpir.c b/util/getpir/getpir.c new file mode 100644 index 0000000..9853d7c --- /dev/null +++ b/util/getpir/getpir.c @@ -0,0 +1,189 @@ +/* getpir.c : This software is released under GPL + * For coreboot use only + * Aug 26 2001 , Nikolai Vladychevski, niko@isl.net.mx + * 2007.04.09 Jeremy Jackson jerj@coplanar.net + * updated for amd64 and general 64 bit portability + * 2010.04.24 Marc Bertens mbertens@xs4all.nl + * Added functionality to read a image file for checking the checksum of the PIR + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pirq_routing.h" +#include "checksum.h" +#include "code_gen.h" + +#if defined (__sun) && (defined(__i386) || defined(__amd64)) +# define MEM_DEV "/dev/xsvc" +#else +# define MEM_DEV "/dev/mem" +#endif + +/** + * The probe_table() is now called with the pointer to the memory, + * this is to handle both the assessing memory and a file. + * + * This function now dumps the table found to the stdout, with + * descriptions, it is special handy when building a PIRQ table + * for a board to check the checksum. + */ +static struct irq_routing_table *probe_table(char* ptr) +{ + /** + * Signature to search for $PIR<2-byte-version> + * + * this is to be sure that we find the correct table. + */ + char signature[] = "$PIR\x00\x01"; + /** cast the pointer */ + struct irq_routing_table *rt = (struct irq_routing_table *)ptr; + int size = 16; + int checksum_result; + do { + /** find the PIRQ table */ + rt = (struct irq_routing_table *) memmem(ptr + size, 16, signature, 6); + if (rt != NULL) { + /** found the table */ + int i, ts = (rt->size - 32) / 16; + struct irq_info *se_arr; + se_arr = (struct irq_info *) ((char *) rt + 32); + /** Dump the table information to the stdout */ + printf("Found PCI IRQ routing table signature at %p.\n", (void *) ((char *) rt - ptr + 0xf0000)); + printf("SIGNATURE = %s\n", (char*)&rt->signature); + printf("VERSION = %04x\n", rt->version); + printf("SIZE = %i\n", rt->size); + printf("MAX_DEVICES_ON_BUS = 32 + 16 * %d\n", ts); + printf("INT_ROUTER_BUS = 0x%02x\n", rt->rtr_bus); + printf("INT_ROUTER DEVICE = (0x%02x << 3) | 0x%01x\n", rt->rtr_devfn >> 3, rt->rtr_devfn & 7); + printf("IRQ_DEVOTED_TO_PCI = %#x\n", rt->exclusive_irqs); + printf("VENDOR = %#x\n", rt->rtr_vendor); + printf("DEVICE = %#x\n", rt->rtr_device); + printf("MINIPORT = %#x\n", rt->miniport_data); + printf("CHECKSUM = %#x\n", rt->checksum); + printf("\tbus , dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu\n"); + for (i = 0; i < ts; i++) { + printf("\t0x%02x, (0x%02x << 3) | 0x%01x, {{0x%02x, 0x%04x}, {0x%02x, 0x%04x}, {0x%02x, 0x%04x}, {0x%02x, 0x%04x}}, 0x%x, 0x%x},\n", + (se_arr+i)->bus, (se_arr+i)->devfn >> 3, + (se_arr+i)->devfn & 7, (se_arr+i)->irq[0].link, + (se_arr+i)->irq[0].bitmap, (se_arr+i)->irq[1].link, + (se_arr+i)->irq[1].bitmap, (se_arr+i)->irq[2].link, + (se_arr+i)->irq[2].bitmap, (se_arr+i)->irq[3].link, + (se_arr+i)->irq[3].bitmap, (se_arr+i)->slot, + (se_arr+i)->rfu); + } + /** A table should not be over 0x400 bytes */ + if (rt->size > 0x400) { + return NULL; + } + printf("Validating...\n"); + /** Calculate the checksum value */ + checksum_result = calc_checksum(rt); + /** Show the calculatedchecksum value */ + printf("CHECKSUM = %#x\n", 0x100-((checksum_result - rt->checksum) & 0xFF)); + /** and the result of the calculation */ + if (!checksum_result) { + printf("checksum is ok.\n"); + break; + } else { + printf("checksum is wrong.\n"); + } + } + size += 16; + } while (size < 0xFFFF); + if (size >= 0xFFFF) { + /** When the functions comes here there is no PIRQ table found. */ + printf("No PCI IRQ routing table signature found.\n"); + return NULL; + } + + return rt; +} + +int main(int argc, char* argv[]) +{ + char* ptr; + int fd_mem = -1; + struct irq_routing_table* rt = NULL; + void* bios_image = NULL; + if ( argc > 1 ) + { + /** there a paramater passed to the program, assume that it is a menory file */ + printf("Opening memory image file '%s'\n", argv[1]); + /** Open the file */ + fd_mem = open(argv[1], O_RDONLY); + if (fd_mem > 0) { + /** get tyhe size of the file */ + int file_size = lseek(fd_mem, 0, SEEK_END); + printf("Memory image '%i'\n", file_size); + /** get a memory block for it. */ + bios_image = malloc(file_size); + if (bios_image) { + /** Fill the created buffer */ + lseek(fd_mem, 0, SEEK_SET); + read(fd_mem, bios_image, file_size); + /** set the pointer for the probe function */ + ptr = (char*)bios_image; + } else { + /* no memory available ? */ + perror("Failed to open imagefile\n"); + return (-3); + } + } else { + /** An error occourd, just exit with a message */ + perror("Failed to open imagefile"); + return (-2); + } + } else { + /** No paramaters means that the program will access the system memory */ + printf("Accessing memory\n"); + if (getuid()) { + /** i'm not root message !!!! */ + fprintf(stderr, "Run me as root, I need access to " MEM_DEV ".\n"); + } + /** open the system memory */ + fd_mem = open(MEM_DEV, O_RDONLY); + if (fd_mem < 0) { + /** could not open the system memory, exit with a message */ + perror("Could not open " MEM_DEV ":"); + exit(1); + } + printf("Probing PIRQ table in memory.\n"); + ptr = mmap(0, 0x10000, PROT_READ, MAP_SHARED, fd_mem, (off_t)0xf0000); + if (ptr == MAP_FAILED) { + /** could not map the system memory, exit with a message */ + perror("Mapping system memory failed: "); + close(fd_mem); + return (1); + } + } + if (ptr) { + /** now do the actual probe function */ + rt = probe_table(ptr); + if (rt != NULL && bios_image == NULL) { + /** when probing system memory we write the 'irq_tables.c' code file */ + printf("Creating irq_tables.c ...\n"); + code_gen("irq_tables.c", rt); + printf("Done, you can move the file to the coreboot tree now.\n"); + } + } else { + printf("invalid memory pointer\n"); + } + if (bios_image) { + /** when we are reading from a file the memory must be released */ + free(bios_image); + } else { + /** when reading from the system memory, it must be unmapped */ + munmap(ptr, 0x10000); + } + /** Close the file handle */ + close(fd_mem); + /** return 0 as OK ) */ + return 0; +} diff --git a/util/getpir/pirq_routing.h b/util/getpir/pirq_routing.h new file mode 100644 index 0000000..88adc21 --- /dev/null +++ b/util/getpir/pirq_routing.h @@ -0,0 +1,55 @@ +#ifndef ARCH_PIRQ_ROUTING_H +#define ARCH_PIRQ_ROUTING_H + +#include <stdint.h> + +#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_VERSION 0x0100 + +struct irq_info { + uint8_t bus, devfn; /* Bus, device and function */ + struct { + uint8_t link; /* IRQ line ID, chipset dependent, 0=not routed */ + uint16_t bitmap; /* Available IRQs */ + } __attribute__((packed)) irq[4]; + uint8_t slot; /* Slot number, 0=onboard */ + uint8_t rfu; +} __attribute__((packed)); + +#if defined(CONFIG_IRQ_SLOT_COUNT) +#define IRQ_SLOTS_COUNT CONFIG_IRQ_SLOT_COUNT +#elif (__GNUC__ < 3) +#define IRQ_SLOTS_COUNT 1 +#else +#define IRQ_SLOTS_COUNT +#endif + +struct irq_routing_table { + uint32_t signature; /* PIRQ_SIGNATURE should be here */ + uint16_t version; /* PIRQ_VERSION */ + uint16_t size; /* Table size in bytes */ + uint8_t rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + uint16_t exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + uint16_t rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + uint32_t miniport_data; /* Miniport data */ + uint8_t rfu[11]; + uint8_t checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[IRQ_SLOTS_COUNT]; +} __attribute__((packed)); + +extern const struct irq_routing_table intel_irq_routing_table; + +#ifdef GETPIR +#define copy_pirq_routing_table(start) (start) +unsigned long write_pirq_routing_table(unsigned long start); +#else +#if CONFIG_HAVE_PIRQ_TABLE==1 +unsigned long copy_pirq_routing_table(unsigned long start); +unsigned long write_pirq_routing_table(unsigned long start); +#else +#define copy_pirq_routing_table(start) (start) +#define write_pirq_routing_table(start) (start) +#endif +#endif + +#endif /* ARCH_PIRQ_ROUTING_H */ diff --git a/util/mptable/Makefile b/util/mptable/Makefile new file mode 100644 index 0000000..f88367e --- /dev/null +++ b/util/mptable/Makefile @@ -0,0 +1,8 @@ +CC=gcc +CFLAGS=-O2 -Wall -Wextra -Wshadow -Wno-sign-compare + +mptable: mptable.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f mptable diff --git a/util/mptable/mptable.c b/util/mptable/mptable.c new file mode 100644 index 0000000..5b8a59d --- /dev/null +++ b/util/mptable/mptable.c @@ -0,0 +1,1258 @@ +/* + * 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 <sys/types.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> + +#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 <console/console.h>", + "#include <arch/smp/mpspec.h>", + "#include <arch/ioapic.h>", + "#include <device/pci.h>", + "#include <string.h>", + "#include <stdint.h>", + "", + "#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); +}