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