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