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