]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/pirtool/pirtool.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / pirtool / pirtool.c
1 /*
2  * Copyright (c) 2002-2006 Bruce M. Simpson.
3  * All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of Bruce M. Simpson nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY BRUCE M. SIMPSON AND AFFILIATES
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
36 #include <sys/memrange.h>
37 #include <sys/stat.h>
38 #include <machine/endian.h>
39
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <libgen.h>
44 #include <fcntl.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "pirtable.h"
49
50 #define _PATH_DEVMEM    "/dev/mem"
51
52 void usage(void);
53 void banner(void);
54 pir_table_t *find_pir_table(unsigned char *base);
55 void dump_pir_table(pir_table_t *pir, char *map_addr);
56 void pci_print_irqmask(uint16_t irqs);
57 void print_irq_line(int entry, pir_entry_t *p, char line, uint8_t link,
58     uint16_t irqs);
59 char *lookup_southbridge(uint32_t id);
60
61 char *progname = NULL;
62
63 int
64 main(int argc, char *argv[])
65 {
66         int ch, r;
67         int err = -1;
68         int mem_fd = -1;
69         pir_table_t *pir = NULL;
70         void *map_addr = MAP_FAILED;
71         char *real_pir;
72
73         progname = basename(argv[0]);
74         while ((ch = getopt(argc, argv, "h")) != -1)
75                 switch (ch) {
76                 case 'h':
77                 default:
78                         usage();
79         }
80         argc -= optind;
81         argv += optind;
82
83         if (argc > 0)
84                 usage();
85
86         banner();
87         /*
88          * Map the PIR region into our process' linear space.
89          */
90         if ((mem_fd = open(_PATH_DEVMEM, O_RDONLY)) == -1) {
91                 perror("open");
92                 goto cleanup;
93         }
94         map_addr = mmap(NULL, PIR_SIZE, PROT_READ, MAP_SHARED, mem_fd,
95             PIR_BASE);
96         if (map_addr == MAP_FAILED) {
97                 perror("mmap");
98                 goto cleanup;
99         }
100         /*
101          * Find and print the PIR table.
102          */
103         if ((pir = find_pir_table(map_addr)) == NULL) {
104                 fprintf(stderr, "PIR table signature not found.\r\n");
105         } else {
106                 dump_pir_table(pir, map_addr);
107                 err = 0;
108         }
109
110 cleanup:
111         if (map_addr != MAP_FAILED)
112                 munmap(map_addr, PIR_SIZE);
113         if (mem_fd != -1)
114                 close(mem_fd);
115
116         exit ((err == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
117 }
118
119 void
120 usage(void)
121 {
122
123         fprintf(stderr, "usage: %s [-h]\r\n", progname);
124         fprintf(stderr, "-h\tdisplay this message\r\n", progname);
125         exit(EXIT_FAILURE);
126 }
127
128 void
129 banner(void)
130 {
131
132         fprintf(stderr, "PIRTOOL (c) 2002-2006 Bruce M. Simpson\r\n");
133         fprintf(stderr,
134             "---------------------------------------------\r\n\r\n");
135 }
136
137 pir_table_t *
138 find_pir_table(unsigned char *base)
139 {
140         unsigned int csum = 0;
141         unsigned char *p, *pend;
142         pir_table_t *pir = NULL;
143
144         /*
145          * From Microsoft's PCI IRQ Routing Table Specification 1.0:
146          *
147          * The PCI IRQ Routing Table can be detected by searching the
148          * system memory from F0000h to FFFFFh at every 16-byte boundary
149          * for the PCI IRQ routing signature ("$PIR").
150          */
151         pend = base + PIR_SIZE;
152         for (p = base; p < pend; p += 16) {
153                 if (strncmp(p, "$PIR", 4) == 0) {
154                         pir = (pir_table_t *)p;
155                         break;
156                 }
157         }
158
159         /*
160          * Now validate the table:
161          * Version: Must be 1.0.
162          * Table size: Must be larger than 32 and must be a multiple of 16.
163          * Checksum: The entire structure's checksum must be 0.
164          */
165         if (pir && (pir->major == 1) && (pir->minor == 0) &&
166             (pir->size > 32) && ((pir->size % 16) == 0)) {
167                 p = (unsigned char *)pir;
168                 pend = p + pir->size;
169
170                 while (p < pend)
171                         csum += *p++;
172
173                 if ((csum % 256) != 0)
174                         fprintf(stderr,
175                             "WARNING: PIR table checksum is invalid.\n");
176         }
177
178         return ((pir_table_t *)pir);
179 }
180
181 void
182 pci_print_irqmask(uint16_t irqs)
183 {
184         int i, first;
185
186         if (irqs == 0) {
187                 printf("none");
188                 return;
189         }
190         first = 1;
191         for (i = 0; i < 16; i++, irqs >>= 1)
192                 if (irqs & 1) {
193                         if (!first)
194                                 printf(" ");
195                         else
196                                 first = 0;
197                         printf("%d", i);
198                 }
199 }
200
201 void
202 dump_pir_table(pir_table_t *pir, char *map_addr)
203 {
204         int i, num_slots;
205         pir_entry_t *p, *pend;
206
207         num_slots = (pir->size - offsetof(pir_table_t, entry[0])) / 16;
208
209         printf( "PCI Interrupt Routing Table at 0x%08lX\r\n"
210             "-----------------------------------------\r\n"
211             "0x%02x: Signature:          %c%c%c%c\r\n"
212             "0x%02x: Version:            %u.%u\r\n"
213             "0x%02x: Size:               %u bytes (%u entries)\r\n"
214             "0x%02x: Device:             %u:%u:%u\r\n",
215             (uint32_t)(((char *)pir - map_addr) + PIR_BASE),
216             offsetof(pir_table_t, signature),
217             ((char *)&pir->signature)[0],
218             ((char *)&pir->signature)[1],
219             ((char *)&pir->signature)[2],
220             ((char *)&pir->signature)[3],
221             offsetof(pir_table_t, minor),
222             pir->major, pir->minor,
223             offsetof(pir_table_t, size),
224             pir->size,
225             num_slots,
226             offsetof(pir_table_t, bus),
227             pir->bus,
228             PIR_DEV(pir->devfunc),
229             PIR_FUNC(pir->devfunc));
230         printf(
231             "0x%02x: PCI Exclusive IRQs: ",
232              offsetof(pir_table_t, excl_irqs));
233         pci_print_irqmask(pir->excl_irqs);
234         printf("\r\n"
235             "0x%02x: Compatible with:    0x%08X %s\r\n"
236             "0x%02x: Miniport Data:      0x%08X\r\n"
237             "0x%02x: Checksum:           0x%02X\r\n"
238             "\r\n",
239             offsetof(pir_table_t, compatible),
240             pir->compatible,
241             lookup_southbridge(pir->compatible),
242             offsetof(pir_table_t, miniport_data),
243             pir->miniport_data,
244             offsetof(pir_table_t, checksum),
245             pir->checksum);
246
247         p = pend = &pir->entry[0];
248         pend += num_slots;
249         printf("Entry  Location  Bus Device Pin  Link  IRQs\n");
250         for (i = 0; p < pend; i++, p++) {
251                 print_irq_line(i, p, 'A', p->inta_link, p->inta_irqs);
252                 print_irq_line(i, p, 'B', p->intb_link, p->intb_irqs);
253                 print_irq_line(i, p, 'C', p->intc_link, p->intc_irqs);
254                 print_irq_line(i, p, 'D', p->intd_link, p->intd_irqs);
255         }
256 }
257
258 /*
259  * Print interrupt map for a given PCI interrupt line.
260  */
261 void
262 print_irq_line(int entry, pir_entry_t *p, char line, uint8_t link,
263     uint16_t irqs)
264 {
265
266         if (link == 0)
267                 return;
268
269         printf("%3d    ", entry);
270         if (p->slot == 0)
271                 printf("embedded ");
272         else
273                 printf("slot %-3d ", p->slot);
274
275         printf(" %3d  %3d    %c   0x%02x  ", p->bus, PIR_DEV(p->devfunc),
276             line, link);
277         pci_print_irqmask(irqs);
278         printf("\n");
279 }
280
281 /*
282  * Lookup textual descriptions for commonly-used south-bridges.
283  */
284 char *
285 lookup_southbridge(uint32_t id)
286 {
287
288         switch (id) {
289         case 0x157310b9:
290                 return ("ALi M1573 (Hypertransport)");
291         case 0x06861106:
292                 return ("VIA VT82C686/686A/686B (Apollo)");
293         case 0x122E8086:
294                 return ("Intel 82371FB (Triton I/PIIX)");
295         case 0x26418086:
296                 return ("Intel 82801FBM (ICH6M)");
297         case 0x70008086:
298                 return ("Intel 82371SB (Natoma/Triton II/PIIX3)");
299         default:
300                 return ("unknown chipset");
301         }
302 }