xref: /openbsd/usr.sbin/pcidump/pcidump.c (revision cecf84d4)
1 /*	$OpenBSD: pcidump.c,v 1.37 2015/01/16 06:40:19 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2006, 2007 David Gwynne <loki@animata.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/pciio.h>
22 
23 #include <dev/pci/pcireg.h>
24 #include <dev/pci/pcidevs.h>
25 #include <dev/pci/pcidevs_data.h>
26 
27 #include <err.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <paths.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <limits.h>
36 
37 #define PCIDEV	"/dev/pci"
38 
39 #ifndef nitems
40 #define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
41 #endif
42 
43 __dead void usage(void);
44 void scanpcidomain(void);
45 int probe(int, int, int);
46 void dump(int, int, int);
47 void hexdump(int, int, int, int);
48 const char *str2busdevfunc(const char *, int *, int *, int *);
49 int pci_nfuncs(int, int);
50 int pci_read(int, int, int, u_int32_t, u_int32_t *);
51 int pci_readmask(int, int, int, u_int32_t, u_int32_t *);
52 void dump_caplist(int, int, int, u_int8_t);
53 void dump_pcie_linkspeed(int, int, int, uint8_t);
54 void print_pcie_ls(uint8_t);
55 int dump_rom(int, int, int);
56 int dump_vga_bios(void);
57 
58 void	dump_type0(int bus, int dev, int func);
59 void	dump_type1(int bus, int dev, int func);
60 void	dump_type2(int bus, int dev, int func);
61 
62 __dead void
63 usage(void)
64 {
65 	extern char *__progname;
66 
67 	fprintf(stderr,
68 	    "usage: %s [-v] [-x | -xx | -xxx] [-d pcidev] [bus:dev:func]\n"
69 	    "       %s -r file [-d pcidev] bus:dev:func\n",
70 	    __progname, __progname);
71 	exit(1);
72 }
73 
74 int pcifd;
75 int romfd;
76 int verbose = 0;
77 int hex = 0;
78 int size = 64;
79 
80 const char *pci_capnames[] = {
81 	"Reserved",
82 	"Power Management",
83 	"AGP",
84 	"Vital Product Data (VPD)",
85 	"Slot Identification",
86 	"Message Signaled Interrupts (MSI)",
87 	"CompactPCI Hot Swap",
88 	"PCI-X",
89 	"AMD LDT/HT",
90 	"Vendor Specific",
91 	"Debug Port",
92 	"CompactPCI Central Resource Control",
93 	"PCI Hot-Plug",
94 	"PCI-PCI",
95 	"AGP8",
96 	"Secure",
97 	"PCI Express",
98 	"Extended Message Signaled Interrupts (MSI-X)",
99 	"SATA",
100 	"PCI Advanced Features"
101 };
102 
103 int
104 main(int argc, char *argv[])
105 {
106 	int nfuncs;
107 	int bus, dev, func;
108 	char pcidev[PATH_MAX] = PCIDEV;
109 	char *romfile = NULL;
110 	const char *errstr;
111 	int c, error = 0, dumpall = 1, domid = 0;
112 
113 	while ((c = getopt(argc, argv, "d:r:vx")) != -1) {
114 		switch (c) {
115 		case 'd':
116 			strlcpy(pcidev, optarg, sizeof(pcidev));
117 			dumpall = 0;
118 			break;
119 		case 'r':
120 			romfile = optarg;
121 			dumpall = 0;
122 			break;
123 		case 'v':
124 			verbose = 1;
125 			break;
126 		case 'x':
127 			hex++;
128 			break;
129 		default:
130 			usage();
131 		}
132 	}
133 	argc -= optind;
134 	argv += optind;
135 
136 	if (argc > 1 || (romfile && argc != 1))
137 		usage();
138 
139 	if (romfile) {
140 		romfd = open(romfile, O_WRONLY|O_CREAT|O_TRUNC, 0777);
141 		if (romfd == -1)
142 			err(1, "%s", romfile);
143 	}
144 
145 	if (hex > 1)
146 		size = 256;
147 	if (hex > 2)
148 		size = 4096;
149 
150 	if (argc == 1)
151 		dumpall = 0;
152 
153 	if (dumpall == 0) {
154 		pcifd = open(pcidev, O_RDONLY, 0777);
155 		if (pcifd == -1)
156 			err(1, "%s", pcidev);
157 	} else {
158 		for (;;) {
159 			snprintf(pcidev, 16, "/dev/pci%d", domid++);
160 			pcifd = open(pcidev, O_RDONLY, 0777);
161 			if (pcifd == -1) {
162 				if (errno == ENXIO || errno == ENOENT) {
163 					return 0;
164 				} else {
165 					err(1, "%s", pcidev);
166 				}
167 			}
168 			printf("Domain %s:\n", pcidev);
169 			scanpcidomain();
170 			close(pcifd);
171 		}
172 	}
173 
174 	if (argc == 1) {
175 		errstr = str2busdevfunc(argv[0], &bus, &dev, &func);
176 		if (errstr != NULL)
177 			errx(1, "\"%s\": %s", argv[0], errstr);
178 
179 		nfuncs = pci_nfuncs(bus, dev);
180 		if (nfuncs == -1 || func > nfuncs)
181 			error = ENXIO;
182 		else if (romfile)
183 			error = dump_rom(bus, dev, func);
184 		else
185 			error = probe(bus, dev, func);
186 
187 		if (error != 0)
188 			errc(1, error, "\"%s\"", argv[0]);
189 	} else {
190 		printf("Domain %s:\n", pcidev);
191 		scanpcidomain();
192 	}
193 
194 	return (0);
195 }
196 
197 void
198 scanpcidomain(void)
199 {
200 	int nfuncs;
201 	int bus, dev, func;
202 
203 	for (bus = 0; bus < 256; bus++) {
204 		for (dev = 0; dev < 32; dev++) {
205 			nfuncs = pci_nfuncs(bus, dev);
206 			for (func = 0; func < nfuncs; func++) {
207 				probe(bus, dev, func);
208 			}
209 		}
210 	}
211 }
212 
213 const char *
214 str2busdevfunc(const char *string, int *bus, int *dev, int *func)
215 {
216 	const char *errstr;
217 	char b[80], *d, *f;
218 
219 	strlcpy(b, string, sizeof(b));
220 
221 	d = strchr(b, ':');
222 	if (d == NULL)
223 		return("device not specified");
224 	*d++ = '\0';
225 
226 	f = strchr(d, ':');
227 	if (f == NULL)
228 		return("function not specified");
229 	*f++ = '\0';
230 
231 	*bus = strtonum(b, 0, 255, &errstr);
232 	if (errstr != NULL)
233 		return (errstr);
234 	*dev = strtonum(d, 0, 31, &errstr);
235 	if (errstr != NULL)
236 		return (errstr);
237 	*func = strtonum(f, 0, 7, &errstr);
238 	if (errstr != NULL)
239 		return (errstr);
240 
241 	return (NULL);
242 }
243 
244 int
245 probe(int bus, int dev, int func)
246 {
247 	u_int32_t id_reg;
248 	const struct pci_known_vendor *pkv;
249 	const struct pci_known_product *pkp;
250 	const char *vendor = NULL, *product = NULL;
251 
252 	if (pci_read(bus, dev, func, PCI_ID_REG, &id_reg) != 0)
253 		return (errno);
254 
255 	if (PCI_VENDOR(id_reg) == PCI_VENDOR_INVALID ||
256 	    PCI_VENDOR(id_reg) == 0)
257 		return (ENXIO);
258 
259 	for (pkv = pci_known_vendors; pkv->vendorname != NULL; pkv++) {
260 		if (pkv->vendor == PCI_VENDOR(id_reg)) {
261 			vendor = pkv->vendorname;
262 			break;
263 		}
264 	}
265 
266 	if (vendor != NULL) {
267 		for (pkp = pci_known_products; pkp->productname != NULL; pkp++)
268 		if (pkp->vendor == PCI_VENDOR(id_reg) &&
269 		    pkp->product == PCI_PRODUCT(id_reg)) {
270 			product = pkp->productname;
271 			break;
272 		}
273 	}
274 
275 	printf(" %d:%d:%d: %s %s\n", bus, dev, func,
276 	    (vendor == NULL) ? "unknown" : vendor,
277 	    (product == NULL) ? "unknown" : product);
278 
279 	if (verbose)
280 		dump(bus, dev, func);
281 	if (hex > 0)
282 		hexdump(bus, dev, func, size);
283 
284 	return (0);
285 }
286 
287 void
288 print_pcie_ls(uint8_t speed)
289 {
290 	if (speed & 4)
291 		printf("8.0");
292 	else if (speed & 2)
293 		printf("5.0");
294 	else if (speed & 1)
295 		printf("2.5");
296 	else
297 		printf("unknown (%d)", speed);
298 }
299 
300 void
301 dump_pcie_linkspeed(int bus, int dev, int func, uint8_t ptr)
302 {
303 	u_int32_t lcap, sreg, lcap2 = 0, xcap;
304 	u_int8_t cwidth, cspeed, swidth, sspeed;
305 
306 	if (pci_read(bus, dev, func, ptr + PCI_PCIE_XCAP, &xcap) != 0)
307 		return;
308 
309 	if (PCI_PCIE_XCAP_VER(xcap) >= 2) {
310 		if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP2, &lcap2) != 0)
311 			lcap2 = 0;
312 		else
313 			cspeed = (lcap2 & 0x0e) >> 1;
314 	}
315 
316 	if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP, &lcap) != 0)
317 		return;
318 	if (lcap2 == 0)
319 		cspeed = lcap & 0x0f;
320 
321 	if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCSR, &sreg) != 0)
322 		return;
323 	sreg = sreg >> 16;
324 
325 	cwidth = (lcap >> 4) & 0x3f;
326 	if (cwidth == 0)
327 		return;
328 
329 	swidth = (sreg >> 4) & 0x3f;
330 	sspeed = sreg & 0x0f;
331 
332 	printf("\t        Link Speed: ");
333 	print_pcie_ls(sspeed);
334 	printf(" / ");
335 	print_pcie_ls(cspeed);
336 
337 	printf(" GT/s Link Width: x%d / x%d\n", swidth, cwidth);
338 }
339 
340 void
341 dump_caplist(int bus, int dev, int func, u_int8_t ptr)
342 {
343 	u_int32_t reg;
344 	u_int8_t cap;
345 
346 	if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, &reg) != 0)
347 		return;
348 	if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
349 		return;
350 
351 	if (pci_read(bus, dev, func, ptr, &reg) != 0)
352 		return;
353 	ptr = PCI_CAPLIST_PTR(reg);
354 	while (ptr != 0) {
355 		if (pci_read(bus, dev, func, ptr, &reg) != 0)
356 			return;
357 		cap = PCI_CAPLIST_CAP(reg);
358 		printf("\t0x%04x: Capability 0x%02x: ", ptr, cap);
359 		if (cap >= nitems(pci_capnames))
360 			cap = 0;
361 		printf("%s\n", pci_capnames[cap]);
362 		if (cap == PCI_CAP_PCIEXPRESS)
363 			dump_pcie_linkspeed(bus, dev, func, ptr);
364 		ptr = PCI_CAPLIST_NEXT(reg);
365 	}
366 }
367 
368 void
369 dump_type0(int bus, int dev, int func)
370 {
371 	const char *memtype;
372 	u_int64_t mem;
373 	u_int64_t mask;
374 	u_int32_t reg, reg1;
375 	int bar;
376 
377 	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 0x4) {
378 		if (pci_read(bus, dev, func, bar, &reg) != 0 ||
379 		    pci_readmask(bus, dev, func, bar, &reg1) != 0)
380 			warn("unable to read PCI_MAPREG 0x%02x", bar);
381 
382 		printf("\t0x%04x: BAR ", bar);
383 
384 		if (reg == 0 && reg1 == 0) {
385 			printf("empty (%08x)\n", reg);
386 			continue;
387 		}
388 
389 		switch (PCI_MAPREG_TYPE(reg)) {
390 		case PCI_MAPREG_TYPE_MEM:
391 			printf("mem ");
392 			if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
393 				printf("prefetchable ");
394 
395 			memtype = "32bit 1m";
396 			switch (PCI_MAPREG_MEM_TYPE(reg)) {
397 			case PCI_MAPREG_MEM_TYPE_32BIT:
398 				memtype = "32bit";
399 			case PCI_MAPREG_MEM_TYPE_32BIT_1M:
400 				printf("%s ", memtype);
401 
402 				printf("addr: 0x%08x/0x%08x\n",
403 				    PCI_MAPREG_MEM_ADDR(reg),
404 				    PCI_MAPREG_MEM_SIZE(reg1));
405 
406 				break;
407 			case PCI_MAPREG_MEM_TYPE_64BIT:
408 				mem = reg;
409 				mask = reg1;
410 				bar += 0x04;
411 				if (pci_read(bus, dev, func, bar, &reg) != 0 ||
412 				    pci_readmask(bus, dev, func, bar, &reg1) != 0)
413 					warn("unable to read 0x%02x", bar);
414 
415 				mem |= (u_int64_t)reg << 32;
416 				mask |= (u_int64_t)reg1 << 32;
417 
418 				printf("64bit addr: 0x%016llx/0x%08llx\n",
419 				    PCI_MAPREG_MEM64_ADDR(mem),
420 				    PCI_MAPREG_MEM64_SIZE(mask));
421 
422 				break;
423 			}
424 			break;
425 
426 		case PCI_MAPREG_TYPE_IO:
427 			printf("io addr: 0x%08x/0x%04x\n",
428 			    PCI_MAPREG_IO_ADDR(reg),
429 			    PCI_MAPREG_IO_SIZE(reg1));
430 			break;
431 		}
432 	}
433 
434 	if (pci_read(bus, dev, func, PCI_CARDBUS_CIS_REG, &reg) != 0)
435 		warn("unable to read PCI_CARDBUS_CIS_REG");
436 	printf("\t0x%04x: Cardbus CIS: %08x\n", PCI_CARDBUS_CIS_REG, reg);
437 
438 	if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG, &reg) != 0)
439 		warn("unable to read PCI_SUBSYS_ID_REG");
440 	printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
441 	    PCI_SUBSYS_ID_REG, PCI_VENDOR(reg), PCI_PRODUCT(reg));
442 
443 	if (pci_read(bus, dev, func, PCI_ROM_REG, &reg) != 0)
444 		warn("unable to read PCI_ROM_REG");
445 	printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
446 	    PCI_ROM_REG, reg);
447 
448 	if (pci_read(bus, dev, func, 0x38, &reg) != 0)
449 		warn("unable to read 0x38 (reserved)");
450 	printf("\t0x%04x: %08x\n", 0x38, reg);
451 
452 	if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, &reg) != 0)
453 		warn("unable to read PCI_INTERRUPT_REG");
454 	printf("\t0x%04x: Interrupt Pin: %02x Line: %02x Min Gnt: %02x"
455 	    " Max Lat: %02x\n", PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
456 	    PCI_INTERRUPT_LINE(reg), PCI_MIN_GNT(reg), PCI_MAX_LAT(reg));
457 }
458 
459 void
460 dump_type1(int bus, int dev, int func)
461 {
462 	u_int32_t reg;
463 	int bar;
464 
465 	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_PPB_END; bar += 0x4) {
466 		if (pci_read(bus, dev, func, bar, &reg) != 0)
467 			warn("unable to read PCI_MAPREG 0x%02x", bar);
468 		printf("\t0x%04x: %08x\n", bar, reg);
469 	}
470 
471 	if (pci_read(bus, dev, func, PCI_PRIBUS_1, &reg) != 0)
472 		warn("unable to read PCI_PRIBUS_1");
473 	printf("\t0x%04x: Primary Bus: %d Secondary Bus: %d "
474 	    "Subordinate Bus: %d \n\t        Secondary Latency Timer: %02x\n",
475 	    PCI_PRIBUS_1, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
476 	    (reg >> 16) & 0xff, (reg >> 24) & 0xff);
477 
478 	if (pci_read(bus, dev, func, PCI_IOBASEL_1, &reg) != 0)
479 		warn("unable to read PCI_IOBASEL_1");
480 	printf("\t0x%04x: I/O Base: %02x I/O Limit: %02x "
481 	    "Secondary Status: %04x\n", PCI_IOBASEL_1, (reg >> 0 ) & 0xff,
482 	    (reg >> 8) & 0xff, (reg >> 16) & 0xffff);
483 
484 	if (pci_read(bus, dev, func, PCI_MEMBASE_1, &reg) != 0)
485 		warn("unable to read PCI_MEMBASE_1");
486 	printf("\t0x%04x: Memory Base: %04x Memory Limit: %04x\n",
487 	    PCI_MEMBASE_1, (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
488 
489 	if (pci_read(bus, dev, func, PCI_PMBASEL_1, &reg) != 0)
490 		warn("unable to read PCI_PMBASEL_1");
491 	printf("\t0x%04x: Prefetch Memory Base: %04x "
492 	    "Prefetch Memory Limit: %04x\n", PCI_PMBASEL_1,
493 	    (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
494 
495 #undef PCI_PMBASEH_1
496 #define PCI_PMBASEH_1	0x28
497 	if (pci_read(bus, dev, func, PCI_PMBASEH_1, &reg) != 0)
498 		warn("unable to read PCI_PMBASEH_1");
499 	printf("\t0x%04x: Prefetch Memory Base Upper 32 Bits: %08x\n",
500 	    PCI_PMBASEH_1, reg);
501 
502 #undef PCI_PMLIMITH_1
503 #define PCI_PMLIMITH_1	0x2c
504 	if (pci_read(bus, dev, func, PCI_PMLIMITH_1, &reg) != 0)
505 		warn("unable to read PCI_PMLIMITH_1");
506 	printf("\t0x%04x: Prefetch Memory Limit Upper 32 Bits: %08x\n",
507 	    PCI_PMLIMITH_1, reg);
508 
509 #undef PCI_IOBASEH_1
510 #define PCI_IOBASEH_1	0x30
511 	if (pci_read(bus, dev, func, PCI_IOBASEH_1, &reg) != 0)
512 		warn("unable to read PCI_IOBASEH_1");
513 	printf("\t0x%04x: I/O Base Upper 16 Bits: %04x "
514 	    "I/O Limit Upper 16 Bits: %04x\n", PCI_IOBASEH_1,
515 	    (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
516 
517 #define PCI_PPB_ROM_REG		0x38
518 	if (pci_read(bus, dev, func, PCI_PPB_ROM_REG, &reg) != 0)
519 		warn("unable to read PCI_PPB_ROM_REG");
520 	printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
521 	    PCI_PPB_ROM_REG, reg);
522 
523 	if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, &reg) != 0)
524 		warn("unable to read PCI_INTERRUPT_REG");
525 	printf("\t0x%04x: Interrupt Pin: %02x Line: %02x "
526 	    "Bridge Control: %04x\n",
527 	    PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
528 	    PCI_INTERRUPT_LINE(reg), reg >> 16);
529 }
530 
531 void
532 dump_type2(int bus, int dev, int func)
533 {
534 	u_int32_t reg;
535 
536 	if (pci_read(bus, dev, func, PCI_MAPREG_START, &reg) != 0)
537 		warn("unable to read PCI_MAPREG\n");
538 	printf("\t0x%04x: Cardbus Control Registers Base Address: %08x\n",
539 	    PCI_MAPREG_START, reg);
540 
541 	if (pci_read(bus, dev, func, PCI_PRIBUS_2, &reg) != 0)
542 		warn("unable to read PCI_PRIBUS_2");
543 	printf("\t0x%04x: Primary Bus: %d Cardbus Bus: %d "
544 	    "Subordinate Bus: %d \n\t        Cardbus Latency Timer: %02x\n",
545 	    PCI_PRIBUS_2, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
546 	    (reg >> 16) & 0xff, (reg >> 24) & 0xff);
547 
548 	if (pci_read(bus, dev, func, PCI_MEMBASE0_2, &reg) != 0)
549 		warn("unable to read PCI_MEMBASE0_2\n");
550 	printf("\t0x%04x: Memory Base 0: %08x\n", PCI_MEMBASE0_2, reg);
551 
552 	if (pci_read(bus, dev, func, PCI_MEMLIMIT0_2, &reg) != 0)
553 		warn("unable to read PCI_MEMLIMIT0_2\n");
554 	printf("\t0x%04x: Memory Limit 0: %08x\n", PCI_MEMLIMIT0_2, reg);
555 
556 	if (pci_read(bus, dev, func, PCI_MEMBASE1_2, &reg) != 0)
557 		warn("unable to read PCI_MEMBASE1_2\n");
558 	printf("\t0x%04x: Memory Base 1: %08x\n", PCI_MEMBASE1_2, reg);
559 
560 	if (pci_read(bus, dev, func, PCI_MEMLIMIT1_2, &reg) != 0)
561 		warn("unable to read PCI_MEMLIMIT1_2\n");
562 	printf("\t0x%04x: Memory Limit 1: %08x\n", PCI_MEMLIMIT1_2, reg);
563 
564 	if (pci_read(bus, dev, func, PCI_IOBASE0_2, &reg) != 0)
565 		warn("unable to read PCI_IOBASE0_2\n");
566 	printf("\t0x%04x: I/O Base 0: %08x\n", PCI_IOBASE0_2, reg);
567 
568 	if (pci_read(bus, dev, func, PCI_IOLIMIT0_2, &reg) != 0)
569 		warn("unable to read PCI_IOLIMIT0_2\n");
570 	printf("\t0x%04x: I/O Limit 0: %08x\n", PCI_IOLIMIT0_2, reg);
571 
572 	if (pci_read(bus, dev, func, PCI_IOBASE1_2, &reg) != 0)
573 		warn("unable to read PCI_IOBASE1_2\n");
574 	printf("\t0x%04x: I/O Base 1: %08x\n", PCI_IOBASE1_2, reg);
575 
576 	if (pci_read(bus, dev, func, PCI_IOLIMIT1_2, &reg) != 0)
577 		warn("unable to read PCI_IOLIMIT1_2\n");
578 	printf("\t0x%04x: I/O Limit 1: %08x\n", PCI_IOLIMIT1_2, reg);
579 
580 	if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, &reg) != 0)
581 		warn("unable to read PCI_INTERRUPT_REG");
582 	printf("\t0x%04x: Interrupt Pin: %02x Line: %02x "
583 	    "Bridge Control: %04x\n",
584 	    PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
585 	    PCI_INTERRUPT_LINE(reg), reg >> 16);
586 
587 	if (pci_read(bus, dev, func, PCI_SUBVEND_2, &reg) != 0)
588 		warn("unable to read PCI_SUBVEND_2");
589 	printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
590 	    PCI_SUBVEND_2, PCI_VENDOR(reg), PCI_PRODUCT(reg));
591 
592 	if (pci_read(bus, dev, func, PCI_PCCARDIF_2, &reg) != 0)
593 		warn("unable to read PCI_PCCARDIF_2\n");
594 	printf("\t0x%04x: 16-bit Legacy Mode Base Address: %08x\n",
595 	    PCI_PCCARDIF_2, reg);
596 }
597 
598 void
599 dump(int bus, int dev, int func)
600 {
601 	u_int32_t reg;
602 	u_int8_t capptr = PCI_CAPLISTPTR_REG;
603 
604 	if (pci_read(bus, dev, func, PCI_ID_REG, &reg) != 0)
605 		warn("unable to read PCI_ID_REG");
606 	printf("\t0x%04x: Vendor ID: %04x Product ID: %04x\n", PCI_ID_REG,
607 	    PCI_VENDOR(reg), PCI_PRODUCT(reg));
608 
609 	if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, &reg) != 0)
610 		warn("unable to read PCI_COMMAND_STATUS_REG");
611 	printf("\t0x%04x: Command: %04x Status: %04x\n",
612 	    PCI_COMMAND_STATUS_REG, reg & 0xffff, (reg  >> 16) & 0xffff);
613 
614 	if (pci_read(bus, dev, func, PCI_CLASS_REG, &reg) != 0)
615 		warn("unable to read PCI_CLASS_REG");
616 	printf("\t0x%04x: Class: %02x Subclass: %02x Interface: %02x "
617 	    "Revision: %02x\n", PCI_CLASS_REG, PCI_CLASS(reg),
618 	    PCI_SUBCLASS(reg), PCI_INTERFACE(reg), PCI_REVISION(reg));
619 
620 	if (pci_read(bus, dev, func, PCI_BHLC_REG, &reg) != 0)
621 		warn("unable to read PCI_BHLC_REG");
622 	printf("\t0x%04x: BIST: %02x Header Type: %02x Latency Timer: %02x "
623 	    "Cache Line Size: %02x\n", PCI_BHLC_REG, PCI_BIST(reg),
624 	    PCI_HDRTYPE(reg), PCI_LATTIMER(reg), PCI_CACHELINE(reg));
625 
626 	switch (PCI_HDRTYPE_TYPE(reg)) {
627 	case 2:
628 		dump_type2(bus, dev, func);
629 		capptr = PCI_CARDBUS_CAPLISTPTR_REG;
630 		break;
631 	case 1:
632 		dump_type1(bus, dev, func);
633 		break;
634 	case 0:
635 		dump_type0(bus, dev, func);
636 		break;
637 	default:
638 		break;
639 	}
640 	dump_caplist(bus, dev, func, capptr);
641 }
642 
643 void
644 hexdump(int bus, int dev, int func, int size)
645 {
646 	u_int32_t reg;
647 	int i;
648 
649 	for (i = 0; i < size; i += 4) {
650 		if (pci_read(bus, dev, func, i, &reg) != 0) {
651 			if (errno == EINVAL)
652 				return;
653 			warn("unable to read 0x%02x", i);
654 		}
655 
656 		if ((i % 16) == 0)
657 			printf("\t0x%04x:", i);
658 		printf(" %08x", reg);
659 
660 		if ((i % 16) == 12)
661 			printf("\n");
662 	}
663 }
664 
665 int
666 pci_nfuncs(int bus, int dev)
667 {
668 	u_int32_t hdr;
669 
670 	if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
671 		return (-1);
672 
673 	return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
674 }
675 
676 int
677 pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
678 {
679 	struct pci_io io;
680 	int rv;
681 
682 	bzero(&io, sizeof(io));
683 	io.pi_sel.pc_bus = bus;
684 	io.pi_sel.pc_dev = dev;
685 	io.pi_sel.pc_func = func;
686 	io.pi_reg = reg;
687 	io.pi_width = 4;
688 
689 	rv = ioctl(pcifd, PCIOCREAD, &io);
690 	if (rv != 0)
691 		return (rv);
692 
693 	*val = io.pi_data;
694 
695 	return (0);
696 }
697 
698 int
699 pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
700 {
701 	struct pci_io io;
702 	int rv;
703 
704 	bzero(&io, sizeof(io));
705 	io.pi_sel.pc_bus = bus;
706 	io.pi_sel.pc_dev = dev;
707 	io.pi_sel.pc_func = func;
708 	io.pi_reg = reg;
709 	io.pi_width = 4;
710 
711 	rv = ioctl(pcifd, PCIOCREADMASK, &io);
712 	if (rv != 0)
713 		return (rv);
714 
715 	*val = io.pi_data;
716 
717 	return (0);
718 }
719 
720 int
721 dump_rom(int bus, int dev, int func)
722 {
723 	struct pci_rom rom;
724 	u_int32_t cr, addr;
725 
726 	if (pci_read(bus, dev, func, PCI_ROM_REG, &addr) != 0 ||
727 	    pci_read(bus, dev, func, PCI_CLASS_REG, &cr) != 0)
728 		return (errno);
729 
730 	if (addr == 0 && PCI_CLASS(cr) == PCI_CLASS_DISPLAY &&
731 	    PCI_SUBCLASS(cr) == PCI_SUBCLASS_DISPLAY_VGA)
732 		return dump_vga_bios();
733 
734 	bzero(&rom, sizeof(rom));
735 	rom.pr_sel.pc_bus = bus;
736 	rom.pr_sel.pc_dev = dev;
737 	rom.pr_sel.pc_func = func;
738 	if (ioctl(pcifd, PCIOCGETROMLEN, &rom))
739 		return (errno);
740 
741 	rom.pr_rom = malloc(rom.pr_romlen);
742 	if (rom.pr_rom == NULL)
743 		return (ENOMEM);
744 
745 	if (ioctl(pcifd, PCIOCGETROM, &rom))
746 		return (errno);
747 
748 	if (write(romfd, rom.pr_rom, rom.pr_romlen) == -1)
749 		return (errno);
750 
751 	return (0);
752 }
753 
754 #define VGA_BIOS_ADDR	0xc0000
755 #define VGA_BIOS_LEN	0x10000
756 
757 int
758 dump_vga_bios(void)
759 {
760 #if defined(__amd64__) || defined(__i386__)
761 	void *bios;
762 	int fd;
763 
764 	fd = open(_PATH_MEM, O_RDONLY, 0777);
765 	if (fd == -1)
766 		err(1, "%s", _PATH_MEM);
767 
768 	bios = malloc(VGA_BIOS_LEN);
769 	if (bios == NULL)
770 		return (ENOMEM);
771 
772 	if (pread(fd, bios, VGA_BIOS_LEN, VGA_BIOS_ADDR) == -1)
773 		err(1, "%s", _PATH_MEM);
774 
775 	if (write(romfd, bios, VGA_BIOS_LEN) == -1) {
776 		free(bios);
777 		return (errno);
778 	}
779 
780 	free(bios);
781 
782 	return (0);
783 #else
784 	return (ENODEV);
785 #endif
786 }
787