Lubomir Rintel has uploaded this change for review. ( https://review.coreboot.org/22256
Change subject: util/pirdump: add tool to dump PIR table ......................................................................
util/pirdump: add tool to dump PIR table
Signed-off-by: Lubomir Rintel lkundrak@v3.sk Change-Id: I9b0a2ae459bb98ed6854fef280d67f9c14a25314 --- A util/pirdump/Makefile A util/pirdump/pirdump.1 A util/pirdump/pirdump.c 3 files changed, 346 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/56/22256/1
diff --git a/util/pirdump/Makefile b/util/pirdump/Makefile new file mode 100644 index 0000000..7938c82 --- /dev/null +++ b/util/pirdump/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (C) 2017 Lubomir Rintel lkundrak@v3.sk +# +# Based on an inteltool Makefile: +# +# Copyright (C) 2008 by coresystems GmbH +# written by Stefan Reinauer stepan@coresystems.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +PROGRAM = pirdump + +all: $(PROGRAM) + +clean: + rm -f $(PROGRAM) *.o + +install: $(PROGRAM) + mkdir -p $(DESTDIR)$(PREFIX)/bin + install $(PROGRAM) $(DESTDIR)$(PREFIX)/bin + mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1 + install -p -m644 $(PROGRAM).1 $(DESTDIR)$(PREFIX)/share/man/man1 + +.PHONY: all clean diff --git a/util/pirdump/pirdump.1 b/util/pirdump/pirdump.1 new file mode 100644 index 0000000..6e61419 --- /dev/null +++ b/util/pirdump/pirdump.1 @@ -0,0 +1,56 @@ +.TH PIRDUMP 1 "October 29, 2017" +.SH NAME +pirdump - dump the PCI Interrupt Routing table +.SH SYNOPSIS +.B pirdump [format] [<dump file>] +.SH DESCRIPTION +.B pirdump +dumps the PIR table from memory or a dump file in a variety of formats. +.SH OPTIONS +.TP +.B "-d" | "--default" +Dump in human-readable format (default). +.TP +.B "-r" | "--raw" +Dump the raw (binary) table data. +.TP +.B "-c" | "--C" +Dump the C language snippet with coreboot's "struct +irq_routing_table" initializer. +.TP +.B "--" +Keeps the default format. This is useful if your dump file name starts with a +dash. +.TP +.B "<dump file>" +Look for the PIR table in the provided file instead of memory. +.SH EXAMPLES +.TP +.B "pirdump" +Look for the system's PIR table and print it in a human-readable form. +.TP +.B "pirdump --raw >dump.pir" +Dump the system's PIR table into a file. +.TP +.B "pirdump -c dump.pir" +Read a the PIR table dump from a file and print it in a C language form. +.B "pirdump build/ramstage/mainboard/hp/t5550/irq_tables.o" +Find the PIR table in an object file and print it in a human-readable form. +.SH BUGS +The checksum and table size is not checked for validity. +.P +Works only on little-endian systems. +.P +Please report any bugs to https://ticket.coreboot.org/projects/coreboot or the +coreboot mailing list at coreboot@coreboot.org. +.SH LICENCE +.B pirdump +is covered by the GNU General Public License (GPL), version 2 or (at your +option) any later version. +.SH SEE ALSO +.BR flashrom (1), +.BR abuild (1). +.SH COPYRIGHT +2017 Lubomir Rintel +.SH AUTHORS +2017 Lubomir Rintel lkundrak@v3.sk diff --git a/util/pirdump/pirdump.c b/util/pirdump/pirdump.c new file mode 100644 index 0000000..336b360 --- /dev/null +++ b/util/pirdump/pirdump.c @@ -0,0 +1,257 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Lubomir Rintel lkundrak@v3.sk + * + * Structure definitions were copied from + * src/arch/x86/include/arch/pirq_routing.h: + * + * Copyright (C) 2012 Alexandru Gagniuc mr.nuke.me@gmail.com + * Copyright (C) 2012 Patrick Georgi patrick@georgi-clan.de + * Copyright (C) 2010 Stefan Reinauer stepan@coreboot.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.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)); + +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/device ID of interrupt router */ + uint32_t miniport_data; + uint8_t rfu[11]; + uint8_t checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[1]; +} __attribute__((packed)); + +static int +dump (struct irq_routing_table *pir) +{ + int slot, irq; + + printf ("Signature: 0x%08x\n", pir->signature); + printf ("Version: 0x%04x\n", pir->version); + printf ("Size: 0x%04x\n", pir->size); + printf ("Interrupt router bus: 0x%02x\n", pir->rtr_bus); + printf ("Interrupt router device/function: 0x%02x\n", pir->rtr_devfn); + printf ("IRQs devoted exclusively to PCI usage: 0x%02x\n", pir->exclusive_irqs); + printf ("Interrupt router vendor: 0x%04x\n", pir->rtr_vendor); + printf ("Interrupt router device: 0x%04x\n", pir->rtr_device); + printf ("Miniport data: 0x%08x\n", pir->miniport_data); + printf ("Checksum: 0x%02x\n", pir->checksum); + + for (slot = 0; (void *)&pir->slots[slot] < (void *)pir + pir->size; slot++) { + printf ("Slot: %d\n", slot); + printf ("\tBus: 0x%02x\n", pir->slots[slot].bus); + printf ("\tDevice/function: 0x%02x\n", pir->slots[slot].devfn); + + for (irq = 0; irq < 4; irq++) { + printf ("\tIRQ: %d\n", irq); + printf ("\t\tLink: 0x%02x\n", pir->slots[slot].irq[irq].link); + printf ("\t\tBitmap: 0x%04x\n", pir->slots[slot].irq[irq].bitmap); + } + + printf ("\tSlot number: 0x%02x\n", pir->slots[slot].slot); + } + + return 0; +} + +static int +dumpc (struct irq_routing_table *pir) +{ + int i, slot, irq; + + puts ("const struct irq_routing_table table = {"); + + putchar ('\t'); + if (pir->signature == PIRQ_SIGNATURE) + printf ("PIRQ_SIGNATURE"); + else + printf ("0x%08x", pir->signature); + printf (",\t\t/* u32 signature */\n"); + + putchar ('\t'); + if (pir->version == PIRQ_VERSION) + printf ("PIRQ_VERSION"); + else + printf ("0x%08x", pir->signature); + printf (",\t\t/* u16 version */\n"); + + putchar ('\t'); + if ((pir->size - 32) % 16 == 0) + printf ("32 + 16 * %d", (pir->size - 32) / 16); + else + printf ("%d", pir->size); + printf (",\t\t/* Max. number of devices on the bus */\n"); + + printf ("\t0x%02x,\t\t\t/* Interrupt router bus */\n", pir->rtr_bus); + printf ("\t(0x%02x << 3) | 0x%x,\t/* Interrupt router dev */\n", pir->rtr_devfn >> 3, pir->rtr_devfn & 7); + printf ("\t0x%x,\t\t\t/* IRQs devoted exclusively for PCI */\n", pir->exclusive_irqs); + printf ("\t0x%04x,\t\t\t/* Vendor */\n", pir->rtr_vendor); + printf ("\t0x%04x,\t\t\t/* Device */\n", pir->rtr_device); + printf ("\t0x%04x,\t\t\t/* Miniport */\n", pir->miniport_data); + printf ("\t{"); + for (i = 0; i < 11; i++) { + printf (" %d", pir->rfu[i]); + if (i < 10) + printf (","); + } + printf (" }, /* u8 rfu[11] */\n"); + printf ("\t0x%02x,\t\t\t/* Checksum (has to be set to some value that\n", pir->checksum); + puts ("\t\t\t\t * would give 0 after the sum of all bytes"); + puts ("\t\t\t\t * for this structure (including checksum). */"); + puts ("\t{"); + + printf ("\t\t/* bus, dev | fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */\n"); + for (slot = 0; (void *)&pir->slots[slot] < (void *)pir + pir->size; slot++) { + printf ("\t\t{0x%02x, ", pir->slots[slot].bus); + printf ("(0x%02x << 3) | 0x%x, {", pir->slots[slot].devfn >> 3, pir->slots[slot].devfn & 7); + for (irq = 0; irq < 4; irq++) { + printf ("{0x%02x, 0x%04x}", pir->slots[slot].irq[irq].link, pir->slots[slot].irq[irq].bitmap); + if (irq < 3) + printf (", "); + } + printf ("}, 0x%x, 0x%x},\n", pir->slots[slot].slot, pir->slots[slot].rfu); + } + puts ("\t}\n};"); + + return 0; +} + +static int +dumpr (struct irq_routing_table *pir) +{ + int written = 0; + int ret; + + do { + ret = write (STDOUT_FILENO, pir + written, pir->size - written); + switch (ret) { + case -1: + perror ("write"); + /* fallthrough */ + case 0: + return 1; + default: + written += ret; + } + } while (written < pir->size); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + int fd; + void *mem; + struct irq_routing_table *pir; + const char *pathname; + size_t size, offset, step; + struct stat statbuf; + enum { DEFAULT, C, RAW } format = DEFAULT; + int arg = 1; + + if (argc > arg && argv[arg][0] == '-') { + if ( strcmp (argv[arg], "--default") == 0 + || strcmp (argv[arg], "-d") == 0) { + format = DEFAULT; + } else if ( strcasecmp (argv[arg], "--c") == 0 + || strcasecmp (argv[arg], "-c") == 0) { + format = C; + } else if ( strcmp (argv[arg], "--raw") == 0 + || strcmp (argv[arg], "-r") == 0) { + format = RAW; + } else if (strcmp (argv[arg], "--") != 0) { + fprintf (stderr, "Bad argument: %s\n", argv[arg]); + return 1; + } + arg++; + } + + if (argc > arg) { + if (stat (argv[arg], &statbuf) == -1) { + perror (argv[arg]); + return 1; + } + + pathname = argv[arg]; + offset = 0; + size = statbuf.st_size; + step = 4; + arg++; + } else { + pathname = "/dev/mem"; + offset = 0xf0000; + size = 0x10000; + step = 16; + } + + if (argc > arg) { + fprintf (stderr, "Extra argument: %s\n", argv[arg]); + return 1; + } + + fd = open (pathname, O_RDONLY); + if (fd == -1) { + perror (pathname); + return 1; + } + + mem = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, offset); + if (mem == MAP_FAILED) { + perror ("mmap"); + return 1; + } + + for (pir = mem; (void *)pir < mem + size; pir = (void *)pir + step) { + if (pir->signature == PIRQ_SIGNATURE) + break; + } + if (pir == mem + size) { + fprintf (stderr, "$PIR signature not found\n"); + return 1; + } + + switch (format) { + case DEFAULT: + return dump (pir); + case RAW: + return dumpr (pir); + case C: + return dumpc (pir); + } +}