xref: /netbsd/sys/arch/ia64/stand/ia64/efi/main.c (revision 6550d01e)
1 /*	$NetBSD: main.c,v 1.7 2011/01/22 19:19:19 joerg Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5  * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 
32 #include <lib/libsa/stand.h>
33 #include <lib/libsa/loadfile.h>
34 
35 
36 #include <machine/sal.h>
37 #include <machine/pal.h>
38 #include <machine/pte.h>
39 #include <machine/dig64.h>
40 
41 #include <efi.h>
42 #include <efilib.h>
43 
44 #include "bootstrap.h"
45 #include "efiboot.h"
46 
47 extern char bootprog_name[];
48 extern char bootprog_rev[];
49 
50 struct efi_devdesc	currdev;	/* our current device */
51 struct arch_switch	archsw;		/* MI/MD interface boundary */
52 
53 vaddr_t ia64_unwindtab;
54 vsize_t ia64_unwindtablen;
55 
56 extern u_int64_t	ia64_pal_entry;
57 
58 EFI_GUID acpi = ACPI_TABLE_GUID;
59 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
60 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
61 EFI_GUID hcdp = HCDP_TABLE_GUID;
62 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
63 EFI_GUID mps = MPS_TABLE_GUID;
64 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
65 EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
66 EFI_GUID smbios = SMBIOS_TABLE_GUID;
67 
68 static void
69 find_pal_proc(void)
70 {
71 	int i;
72 	struct sal_system_table *saltab = 0;
73 	static int sizes[6] = {
74 		48, 32, 16, 32, 16, 16
75 	};
76 	u_int8_t *p;
77 
78 	saltab = efi_get_table(&sal);
79 	if (saltab == NULL) {
80 		printf("Can't find SAL System Table\n");
81 		return;
82 	}
83 
84 	if (memcmp(saltab->sal_signature, "SST_", 4)) {
85 		printf("Bad signature for SAL System Table\n");
86 		return;
87 	}
88 
89 	p = (u_int8_t *) (saltab + 1);
90 	for (i = 0; i < saltab->sal_entry_count; i++) {
91 		if (*p == 0) {
92 			struct sal_entrypoint_descriptor *dp;
93 			dp = (struct sal_entrypoint_descriptor *) p;
94 			ia64_pal_entry = dp->sale_pal_proc;
95 			return;
96 		}
97 		p += sizes[*p];
98 	}
99 
100 	printf("Can't find PAL proc\n");
101 	return;
102 }
103 
104 EFI_STATUS
105 main(int argc, CHAR16 *argv[])
106 {
107 	EFI_LOADED_IMAGE *img;
108 	int i;
109 
110 	/*
111 	 * XXX Chicken-and-egg problem; we want to have console output
112 	 * early, but some console attributes may depend on reading from
113 	 * eg. the boot device, which we can't do yet.  We can use
114 	 * printf() etc. once this is done.
115 	 */
116 	cons_probe();
117 
118 	/*
119 	 * Initialise the block cache
120 	 */
121 	/* bcache_init(32, 512); */		/* 16k XXX tune this */
122 
123 	find_pal_proc();
124 
125 	efifs_dev_init();
126 
127         /*	efinet_init_driver(); XXX enable net boot. */
128 
129 	/* Get our loaded image protocol interface structure. */
130 	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
131 
132 	printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
133 
134 	printf("\n");
135 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
136 
137 	i = efifs_get_unit(img->DeviceHandle);
138 	if (i >= 0) {
139 		currdev.d_dev = &devsw[0];		/* XXX disk */
140 		currdev.d_kind.efidisk.unit = i;
141 		/* XXX should be able to detect this, default to autoprobe */
142 		currdev.d_kind.efidisk.slice = -1;
143 		currdev.d_kind.efidisk.partition = 0;
144 		currdev.d_type = DEVT_DISK;
145 	} else {
146 		currdev.d_dev = &devsw[1];		/* XXX net */
147 		currdev.d_kind.netif.unit = 0;		/* XXX */
148 		currdev.d_type = DEVT_NET;
149 
150 	}
151 
152 
153 	/*
154 	 * Disable the watchdog timer. By default the boot manager sets
155 	 * the timer to 5 minutes before invoking a boot option. If we
156 	 * want to return to the boot manager, we have to disable the
157 	 * watchdog timer and since we're an interactive program, we don't
158 	 * want to wait until the user types "quit". The timer may have
159 	 * fired by then. We don't care if this fails. It does not prevent
160 	 * normal functioning in any way...
161 	 */
162 	BS->SetWatchdogTimer(0, 0, 0, NULL);
163 
164 	env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
165 	    (ev_sethook_t *) efi_setcurrdev, env_nounset);
166 	env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
167 	    env_nounset);
168 
169 	setenv("LINES", "24", 1);	/* optional */
170 
171 	archsw.arch_autoload = efi_autoload;
172 	archsw.arch_getdev = efi_getdev;
173 	archsw.arch_copyin = efi_copyin;
174 	archsw.arch_copyout = efi_copyout;
175 	archsw.arch_readin = efi_readin;
176 
177 	interact();			/* doesn't return */
178 
179 	return (EFI_SUCCESS);		/* keep compiler happy */
180 }
181 
182 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
183 
184 static int
185 command_quit(int argc, char *argv[])
186 {
187 	exit(0);
188 	return (CMD_OK);
189 }
190 
191 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
192 
193 static int
194 command_memmap(int argc, char *argv[])
195 {
196 	UINTN sz;
197 	EFI_MEMORY_DESCRIPTOR *map, *p;
198 	UINTN key, dsz;
199 	UINT32 dver;
200 	EFI_STATUS status;
201 	int i, ndesc;
202 	static char *types[] = {
203 	    "Reserved",
204 	    "LoaderCode",
205 	    "LoaderData",
206 	    "BootServicesCode",
207 	    "BootServicesData",
208 	    "RuntimeServicesCode",
209 	    "RuntimeServicesData",
210 	    "ConventionalMemory",
211 	    "UnusableMemory",
212 	    "ACPIReclaimMemory",
213 	    "ACPIMemoryNVS",
214 	    "MemoryMappedIO",
215 	    "MemoryMappedIOPortSpace",
216 	    "PalCode"
217 	};
218 
219 	sz = 0;
220 	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
221 	if (status != EFI_BUFFER_TOO_SMALL) {
222 		printf("Can't determine memory map size\n");
223 		return CMD_ERROR;
224 	}
225 	map = alloc(sz);
226 	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
227 	if (EFI_ERROR(status)) {
228 		printf("Can't read memory map\n");
229 		return CMD_ERROR;
230 	}
231 
232 	ndesc = sz / dsz;
233 	printf("%23s %12s %12s %8s %4s\n",
234 	       "Type", "Physical", "Virtual", "#Pages", "Attr");
235 
236 	for (i = 0, p = map; i < ndesc;
237 	     i++, p = NextMemoryDescriptor(p, dsz)) {
238 	    printf("%23s %012lx %012lx %08lx ",
239 		   types[p->Type],
240 		   p->PhysicalStart,
241 		   p->VirtualStart,
242 		   p->NumberOfPages);
243 	    if (p->Attribute & EFI_MEMORY_UC)
244 		printf("UC ");
245 	    if (p->Attribute & EFI_MEMORY_WC)
246 		printf("WC ");
247 	    if (p->Attribute & EFI_MEMORY_WT)
248 		printf("WT ");
249 	    if (p->Attribute & EFI_MEMORY_WB)
250 		printf("WB ");
251 	    if (p->Attribute & EFI_MEMORY_UCE)
252 		printf("UCE ");
253 	    if (p->Attribute & EFI_MEMORY_WP)
254 		printf("WP ");
255 	    if (p->Attribute & EFI_MEMORY_RP)
256 		printf("RP ");
257 	    if (p->Attribute & EFI_MEMORY_XP)
258 		printf("XP ");
259 	    if (p->Attribute & EFI_MEMORY_RUNTIME)
260 		printf("RUNTIME");
261 	    printf("\n");
262 	}
263 
264 	return CMD_OK;
265 }
266 
267 COMMAND_SET(configuration, "configuration",
268 	    "print configuration tables", command_configuration);
269 
270 static const char *
271 guid_to_string(EFI_GUID *guid)
272 {
273 	static char buf[40];
274 
275 	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
276 	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
277 	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
278 	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
279 	return (buf);
280 }
281 
282 static int
283 command_configuration(int argc, char *argv[])
284 {
285 	int i;
286 
287 	printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
288 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
289 		EFI_GUID *guid;
290 
291 		printf("  ");
292 		guid = &ST->ConfigurationTable[i].VendorGuid;
293 		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
294 			printf("MPS Table");
295 		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
296 			printf("ACPI Table");
297 		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
298 			printf("ACPI 2.0 Table");
299 		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
300 			printf("SMBIOS Table");
301 		else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
302 			printf("SAL System Table");
303 		else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
304 			printf("DIG64 HCDP Table");
305 		else
306 			printf("Unknown Table (%s)", guid_to_string(guid));
307 		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
308 	}
309 
310 	return CMD_OK;
311 }
312 
313 COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
314 
315 static int
316 command_sal(int argc, char *argv[])
317 {
318 	int i;
319 	struct sal_system_table *saltab = 0;
320 	static int sizes[6] = {
321 		48, 32, 16, 32, 16, 16
322 	};
323 	u_int8_t *p;
324 
325 	saltab = efi_get_table(&sal);
326 	if (saltab == NULL) {
327 		printf("Can't find SAL System Table\n");
328 		return CMD_ERROR;
329 	}
330 
331 	if (memcmp(saltab->sal_signature, "SST_", 4)) {
332 		printf("Bad signature for SAL System Table\n");
333 		return CMD_ERROR;
334 	}
335 
336 	printf("SAL Revision %x.%02x\n",
337 	       saltab->sal_rev[1],
338 	       saltab->sal_rev[0]);
339 	printf("SAL A Version %x.%02x\n",
340 	       saltab->sal_a_version[1],
341 	       saltab->sal_a_version[0]);
342 	printf("SAL B Version %x.%02x\n",
343 	       saltab->sal_b_version[1],
344 	       saltab->sal_b_version[0]);
345 
346 	p = (u_int8_t *) (saltab + 1);
347 	for (i = 0; i < saltab->sal_entry_count; i++) {
348 		printf("  Desc %d", *p);
349 		if (*p == 0) {
350 			struct sal_entrypoint_descriptor *dp;
351 			dp = (struct sal_entrypoint_descriptor *) p;
352 			printf("\n");
353 			printf("    PAL Proc at 0x%lx\n",
354 			       dp->sale_pal_proc);
355 			printf("    SAL Proc at 0x%lx\n",
356 			       dp->sale_sal_proc);
357 			printf("    SAL GP at 0x%lx\n",
358 			       dp->sale_sal_gp);
359 		} else if (*p == 1) {
360 			struct sal_memory_descriptor *dp;
361 			dp = (struct sal_memory_descriptor *) p;
362 			printf(" Type %d.%d, ",
363 			       dp->sale_memory_type[0],
364 			       dp->sale_memory_type[1]);
365 			printf("Address 0x%lx, ",
366 			       dp->sale_physical_address);
367 			printf("Length 0x%x\n",
368 			       dp->sale_length);
369 		} else if (*p == 5) {
370 			struct sal_ap_wakeup_descriptor *dp;
371 			dp = (struct sal_ap_wakeup_descriptor *) p;
372 			printf("\n");
373 			printf("    Mechanism %d\n", dp->sale_mechanism);
374 			printf("    Vector 0x%lx\n", dp->sale_vector);
375 		} else
376 			printf("\n");
377 
378 		p += sizes[*p];
379 	}
380 
381 	return CMD_OK;
382 }
383 
384 int
385 print_trs(int type)
386 {
387 	struct ia64_pal_result res;
388 	int i, maxtr;
389 	struct {
390 		pt_entry_t	pte;
391 		uint64_t	itir;
392 		uint64_t	ifa;
393 		struct ia64_rr	rr;
394 	} buf;
395 	static const char *psnames[] = {
396 		"1B",	"2B",	"4B",	"8B",
397 		"16B",	"32B",	"64B",	"128B",
398 		"256B",	"512B",	"1K",	"2K",
399 		"4K",	"8K",	"16K",	"32K",
400 		"64K",	"128K",	"256K",	"512K",
401 		"1M",	"2M",	"4M",	"8M",
402 		"16M",	"32M",	"64M",	"128M",
403 		"256M",	"512M",	"1G",	"2G"
404 	};
405 	static const char *manames[] = {
406 		"WB",	"bad",	"bad",	"bad",
407 		"UC",	"UCE",	"WC",	"NaT",
408 	};
409 
410 	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
411 	if (res.pal_status != 0) {
412 		printf("Can't get VM summary\n");
413 		return CMD_ERROR;
414 	}
415 
416 	if (type == 0)
417 		maxtr = (res.pal_result[0] >> 40) & 0xff;
418 	else
419 		maxtr = (res.pal_result[0] >> 32) & 0xff;
420 
421 	printf("%d translation registers\n", maxtr);
422 
423 	pager_open();
424 	pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
425 	for (i = 0; i <= maxtr; i++) {
426 		char lbuf[128];
427 
428 		memset(&buf, 0, sizeof(buf));
429 		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
430 					    (u_int64_t) &buf);
431 		if (res.pal_status != 0)
432 			break;
433 
434 		/* Only display valid translations */
435 		if ((buf.ifa & 1) == 0)
436 			continue;
437 
438 		if (!(res.pal_result[0] & 1))
439 			buf.pte &= ~PTE_AR_MASK;
440 		if (!(res.pal_result[0] & 2))
441 			buf.pte &= ~PTE_PL_MASK;
442 		if (!(res.pal_result[0] & 4))
443 			buf.pte &= ~PTE_DIRTY;
444 		if (!(res.pal_result[0] & 8))
445 			buf.pte &= ~PTE_MA_MASK;
446 		sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d "
447 		    "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12,
448 		    (buf.pte & PTE_PPN_MASK) >> 12,
449 		    psnames[(buf.itir & ITIR_PS_MASK) >> 2],
450 		    (buf.pte & PTE_ED) ? 1 : 0,
451 		    (int)(buf.pte & PTE_AR_MASK) >> 9,
452 		    (int)(buf.pte & PTE_PL_MASK) >> 7,
453 		    (buf.pte & PTE_DIRTY) ? 1 : 0,
454 		    (buf.pte & PTE_ACCESSED) ? 1 : 0,
455 		    manames[(buf.pte & PTE_MA_MASK) >> 2],
456 		    (buf.pte & PTE_PRESENT) ? 1 : 0,
457 		    (int)((buf.itir & ITIR_KEY_MASK) >> 8));
458 		pager_output(lbuf);
459 	}
460 	pager_close();
461 
462 	if (res.pal_status != 0) {
463 		printf("Error while getting TR contents\n");
464 		return CMD_ERROR;
465 	}
466 	return CMD_OK;
467 }
468 
469 COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
470 
471 static int
472 command_itr(int argc, char *argv[])
473 {
474 	return print_trs(0);
475 }
476 
477 COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
478 
479 static int
480 command_dtr(int argc, char *argv[])
481 {
482 	return print_trs(1);
483 }
484 
485 COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
486 
487 static char *
488 hcdp_string(char *s, u_int len)
489 {
490 	static char buffer[256];
491 
492 	memcpy(buffer, s, len);
493 	buffer[len] = 0;
494 	return (buffer);
495 }
496 
497 static int
498 command_hcdp(int argc, char *argv[])
499 {
500 	struct dig64_hcdp_table *tbl;
501 	union dev_desc *desc;
502 	int i, m, n;
503 
504 	tbl = efi_get_table(&hcdp);
505 	if (tbl == NULL) {
506 		printf("No HCDP table present\n");
507 		return (CMD_OK);
508 	}
509 	if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
510 		printf("HCDP table has invalid signature\n");
511 		return (CMD_OK);
512 	}
513 	printf("HCDP table at 0x%lx\n", (u_long)tbl);
514 	printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
515 	printf("Length     = %u\n", tbl->length);
516 	printf("Revision   = %u\n", tbl->revision);
517 	printf("Checksum   = %u\n", tbl->checksum);
518 	printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
519 	printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
520 	printf("OEM rev    = %u\n", tbl->oem_rev);
521 	printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
522 	printf("Creator rev= %u\n", tbl->creator_rev);
523 	printf("Entries    = %u\n", tbl->entries);
524 	n = 0;
525 	m = tbl->length - sizeof(struct dig64_hcdp_table);
526 	i = 1;
527 	while (n < m) {
528 		printf("Entry #%d:\n", i);
529 		desc = (union dev_desc *)((char *)tbl->entry + n);
530 		printf("    Type      = %u\n", desc->type);
531 		if (desc->type == DIG64_ENTRYTYPE_TYPE0 ||
532 		    desc->type == DIG64_ENTRYTYPE_TYPE1) {
533 			struct dig64_hcdp_entry *ent = &desc->uart;
534 			struct dig64_gas *gas;
535 			printf("    Databits  = %u\n", ent->databits);
536 			printf("    Parity    = %u\n", ent->parity);
537 			printf("    Stopbits  = %u\n", ent->stopbits);
538 			printf("    PCI seg   = %u\n", ent->pci_segment);
539 			printf("    PCI bus   = %u\n", ent->pci_bus);
540 			printf("    PCI dev   = %u\n", ent->pci_device);
541 			printf("    PCI func  = %u\n", ent->pci_function);
542 			printf("    Interrupt = %u\n", ent->interrupt);
543 			printf("    PCI flag  = %u\n", ent->pci_flag);
544 			printf("    Baudrate  = %lu\n",
545 			    ((u_long)ent->baud_high << 32) +
546 			    (u_long)ent->baud_low);
547 			gas = &ent->address;
548 			printf("    Addr space= %u\n", gas->addr_space);
549 			printf("    Bit width = %u\n", gas->bit_width);
550 			printf("    Bit offset= %u\n", gas->bit_offset);
551 			printf("    Address   = 0x%lx\n",
552 			    ((u_long)gas->addr_high << 32) +
553 			    (u_long)gas->addr_low);
554 			printf("    PCI type  = %u\n", ent->pci_devid);
555 			printf("    PCI vndr  = %u\n", ent->pci_vendor);
556 			printf("    IRQ       = %u\n", ent->irq);
557 			printf("    PClock    = %u\n", ent->pclock);
558 			printf("    PCI iface = %u\n", ent->pci_interface);
559 
560 			n += sizeof(struct dig64_hcdp_entry);
561 		} else {
562 			struct dig64_pcdp_entry *pcdp = &desc->pcdp;
563 
564 			if (tbl->revision < 3) {
565 				printf("PCDP not support\n");
566 				return (CMD_OK);
567 			}
568 
569 			printf("    Length    = %u\n", pcdp->length);
570 			printf("    Index EFI = %u\n", pcdp->index);
571 			printf("    Interconn = %u", pcdp->specs.type);
572 
573 			switch (pcdp->specs.type) {
574 			case DIG64_PCDP_SPEC_ACPI:
575 			{
576 				struct dig64_acpi_spec *acpi =
577 				    &pcdp->specs.acpi;
578 
579 				printf("(ACPI)\n");
580 				printf("    Length    = %u\n", acpi->length);
581 				printf("    ACPI_UID  = %x\n", acpi->uid);
582 				printf("    ACPI_HID  = %x\n", acpi->hid);
583 				printf("    ACPI GSI  = %x\n", acpi->acpi_gsi);
584 				printf("    MMIO_TRA  = %lx\n", acpi->mmio_tra);
585 				printf("    IOPort_TRA= %lx\n",
586 				    acpi->ioport_tra);
587 				printf("    Flags     = %x\n", acpi->flags);
588 				break;
589 			}
590 			case DIG64_PCDP_SPEC_PCI:
591 			{
592 				struct dig64_pci_spec *pci = &pcdp->specs.pci;
593 
594 				printf("(PCI)\n");
595 				printf("    Length    = %u\n", pci->length);
596 				printf("    Seg GrpNum= %u\n", pci->sgn);
597 				printf("    Bus       = %u\n", pci->bus);
598 				printf("    Device    = %u\n", pci->device);
599 				printf("    Function  = %u\n", pci->function);
600 				printf("    Device ID = %u\n", pci->device_id);
601 				printf("    Vendor ID = %u\n", pci->vendor_id);
602 				printf("    ACPI GSI  = %x\n", pci->acpi_gsi);
603 				printf("    MMIO_TRA  = %lx\n", pci->mmio_tra);
604 				printf("    IOPort_TRA= %lx\n",
605 				    pci->ioport_tra);
606 				printf("    Flags     = %x\n", pci->flags);
607 				break;
608 			}
609 			}
610 
611 			n += pcdp->length;
612 		}
613 	}
614 	printf("<EOT>\n");
615 	return (CMD_OK);
616 }
617 
618 struct bootblk_command commands[] = {
619         COMMON_COMMANDS,
620         { "quit",       "exit the loader",      command_quit },
621         { "memmap",	"print memory map",	command_memmap },
622         { "configuration", "print configuration tables", command_configuration },
623         { "sal",	"print SAL System Table", command_sal },
624         { "itr",	"print instruction TRs", command_itr },
625         { "dtr",	"print data TRs",	command_dtr },
626         { "hcdp",	"Dump HCDP info",	command_hcdp },
627         { NULL,         NULL,                   NULL         },
628 };
629