2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2002-2006 Bruce M. Simpson.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Bruce M. Simpson nor the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY BRUCE M. SIMPSON AND AFFILIATES
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
38 #include <sys/memrange.h>
40 #include <machine/endian.h>
52 #define _PATH_DEVMEM "/dev/mem"
56 pir_table_t *find_pir_table(unsigned char *base);
57 void dump_pir_table(pir_table_t *pir, char *map_addr);
58 void pci_print_irqmask(uint16_t irqs);
59 void print_irq_line(int entry, pir_entry_t *p, char line, uint8_t link,
61 char *lookup_southbridge(uint32_t id);
63 char *progname = NULL;
66 main(int argc, char *argv[])
71 pir_table_t *pir = NULL;
72 void *map_addr = MAP_FAILED;
75 progname = basename(argv[0]);
76 while ((ch = getopt(argc, argv, "h")) != -1)
90 * Map the PIR region into our process' linear space.
92 if ((mem_fd = open(_PATH_DEVMEM, O_RDONLY)) == -1) {
96 map_addr = mmap(NULL, PIR_SIZE, PROT_READ, MAP_SHARED, mem_fd,
98 if (map_addr == MAP_FAILED) {
103 * Find and print the PIR table.
105 if ((pir = find_pir_table(map_addr)) == NULL) {
106 fprintf(stderr, "PIR table signature not found.\r\n");
108 dump_pir_table(pir, map_addr);
113 if (map_addr != MAP_FAILED)
114 munmap(map_addr, PIR_SIZE);
118 exit ((err == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
125 fprintf(stderr, "usage: %s [-h]\r\n", progname);
126 fprintf(stderr, "-h\tdisplay this message\r\n", progname);
134 fprintf(stderr, "PIRTOOL (c) 2002-2006 Bruce M. Simpson\r\n");
136 "---------------------------------------------\r\n\r\n");
140 find_pir_table(unsigned char *base)
142 unsigned int csum = 0;
143 unsigned char *p, *pend;
144 pir_table_t *pir = NULL;
147 * From Microsoft's PCI IRQ Routing Table Specification 1.0:
149 * The PCI IRQ Routing Table can be detected by searching the
150 * system memory from F0000h to FFFFFh at every 16-byte boundary
151 * for the PCI IRQ routing signature ("$PIR").
153 pend = base + PIR_SIZE;
154 for (p = base; p < pend; p += 16) {
155 if (strncmp(p, "$PIR", 4) == 0) {
156 pir = (pir_table_t *)p;
162 * Now validate the table:
163 * Version: Must be 1.0.
164 * Table size: Must be larger than 32 and must be a multiple of 16.
165 * Checksum: The entire structure's checksum must be 0.
167 if (pir && (pir->major == 1) && (pir->minor == 0) &&
168 (pir->size > 32) && ((pir->size % 16) == 0)) {
169 p = (unsigned char *)pir;
170 pend = p + pir->size;
175 if ((csum % 256) != 0)
177 "WARNING: PIR table checksum is invalid.\n");
180 return ((pir_table_t *)pir);
184 pci_print_irqmask(uint16_t irqs)
193 for (i = 0; i < 16; i++, irqs >>= 1)
204 dump_pir_table(pir_table_t *pir, char *map_addr)
207 pir_entry_t *p, *pend;
209 num_slots = (pir->size - offsetof(pir_table_t, entry[0])) / 16;
211 printf( "PCI Interrupt Routing Table at 0x%08lX\r\n"
212 "-----------------------------------------\r\n"
213 "0x%02x: Signature: %c%c%c%c\r\n"
214 "0x%02x: Version: %u.%u\r\n"
215 "0x%02x: Size: %u bytes (%u entries)\r\n"
216 "0x%02x: Device: %u:%u:%u\r\n",
217 (uint32_t)(((char *)pir - map_addr) + PIR_BASE),
218 offsetof(pir_table_t, signature),
219 ((char *)&pir->signature)[0],
220 ((char *)&pir->signature)[1],
221 ((char *)&pir->signature)[2],
222 ((char *)&pir->signature)[3],
223 offsetof(pir_table_t, minor),
224 pir->major, pir->minor,
225 offsetof(pir_table_t, size),
228 offsetof(pir_table_t, bus),
230 PIR_DEV(pir->devfunc),
231 PIR_FUNC(pir->devfunc));
233 "0x%02x: PCI Exclusive IRQs: ",
234 offsetof(pir_table_t, excl_irqs));
235 pci_print_irqmask(pir->excl_irqs);
237 "0x%02x: Compatible with: 0x%08X %s\r\n"
238 "0x%02x: Miniport Data: 0x%08X\r\n"
239 "0x%02x: Checksum: 0x%02X\r\n"
241 offsetof(pir_table_t, compatible),
243 lookup_southbridge(pir->compatible),
244 offsetof(pir_table_t, miniport_data),
246 offsetof(pir_table_t, checksum),
249 p = pend = &pir->entry[0];
251 printf("Entry Location Bus Device Pin Link IRQs\n");
252 for (i = 0; p < pend; i++, p++) {
253 print_irq_line(i, p, 'A', p->inta_link, p->inta_irqs);
254 print_irq_line(i, p, 'B', p->intb_link, p->intb_irqs);
255 print_irq_line(i, p, 'C', p->intc_link, p->intc_irqs);
256 print_irq_line(i, p, 'D', p->intd_link, p->intd_irqs);
261 * Print interrupt map for a given PCI interrupt line.
264 print_irq_line(int entry, pir_entry_t *p, char line, uint8_t link,
271 printf("%3d ", entry);
275 printf("slot %-3d ", p->slot);
277 printf(" %3d %3d %c 0x%02x ", p->bus, PIR_DEV(p->devfunc),
279 pci_print_irqmask(irqs);
284 * Lookup textual descriptions for commonly-used south-bridges.
287 lookup_southbridge(uint32_t id)
292 return ("ALi M1573 (Hypertransport)");
294 return ("VIA VT82C686/686A/686B (Apollo)");
296 return ("Intel 82371FB (Triton I/PIIX)");
298 return ("Intel 82801FBM (ICH6M)");
300 return ("Intel 82371SB (Natoma/Triton II/PIIX3)");
302 return ("unknown chipset");