main.c revision 201966
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/boot/ia64/efi/main.c 201966 2010-01-10 00:14:04Z marcel $");
30
31#include <stand.h>
32#include <string.h>
33#include <setjmp.h>
34#include <machine/sal.h>
35#include <machine/pal.h>
36#include <machine/pte.h>
37#include <machine/dig64.h>
38
39#include <efi.h>
40#include <efilib.h>
41
42#include <libia64.h>
43
44/* DIG64 Headless Console & Debug Port Table. */
45#define	HCDP_TABLE_GUID		\
46    {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}}
47
48extern char bootprog_name[];
49extern char bootprog_rev[];
50extern char bootprog_date[];
51extern char bootprog_maker[];
52
53struct devdesc currdev;		/* our current device */
54struct arch_switch archsw;	/* MI/MD interface boundary */
55
56extern u_int64_t	ia64_pal_entry;
57
58EFI_GUID acpi = ACPI_TABLE_GUID;
59EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
60EFI_GUID devid = DEVICE_PATH_PROTOCOL;
61EFI_GUID hcdp = HCDP_TABLE_GUID;
62EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
63EFI_GUID mps = MPS_TABLE_GUID;
64EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
65EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
66EFI_GUID smbios = SMBIOS_TABLE_GUID;
67
68static void
69find_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
104EFI_STATUS
105main(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	find_pal_proc();
119
120	/*
121	 * March through the device switch probing for things.
122	 */
123	for (i = 0; devsw[i] != NULL; i++)
124		if (devsw[i]->dv_init != NULL)
125			(devsw[i]->dv_init)();
126
127	/* Get our loaded image protocol interface structure. */
128	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
129
130	printf("\n");
131	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
132	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
133
134	efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
135	currdev.d_type = currdev.d_dev->dv_type;
136
137	/*
138	 * Disable the watchdog timer. By default the boot manager sets
139	 * the timer to 5 minutes before invoking a boot option. If we
140	 * want to return to the boot manager, we have to disable the
141	 * watchdog timer and since we're an interactive program, we don't
142	 * want to wait until the user types "quit". The timer may have
143	 * fired by then. We don't care if this fails. It does not prevent
144	 * normal functioning in any way...
145	 */
146	BS->SetWatchdogTimer(0, 0, 0, NULL);
147
148	env_setenv("currdev", EV_VOLATILE, ia64_fmtdev(&currdev),
149	    ia64_setcurrdev, env_nounset);
150	env_setenv("loaddev", EV_VOLATILE, ia64_fmtdev(&currdev), env_noset,
151	    env_nounset);
152
153	setenv("LINES", "24", 1);	/* optional */
154
155	archsw.arch_autoload = ia64_autoload;
156	archsw.arch_getdev = ia64_getdev;
157	archsw.arch_copyin = ia64_copyin;
158	archsw.arch_copyout = ia64_copyout;
159	archsw.arch_readin = ia64_readin;
160
161	interact();			/* doesn't return */
162
163	return (EFI_SUCCESS);		/* keep compiler happy */
164}
165
166COMMAND_SET(quit, "quit", "exit the loader", command_quit);
167
168static int
169command_quit(int argc, char *argv[])
170{
171	exit(0);
172	return (CMD_OK);
173}
174
175COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
176
177static int
178command_memmap(int argc, char *argv[])
179{
180	UINTN sz;
181	EFI_MEMORY_DESCRIPTOR *map, *p;
182	UINTN key, dsz;
183	UINT32 dver;
184	EFI_STATUS status;
185	int i, ndesc;
186	static char *types[] = {
187	    "Reserved",
188	    "LoaderCode",
189	    "LoaderData",
190	    "BootServicesCode",
191	    "BootServicesData",
192	    "RuntimeServicesCode",
193	    "RuntimeServicesData",
194	    "ConventionalMemory",
195	    "UnusableMemory",
196	    "ACPIReclaimMemory",
197	    "ACPIMemoryNVS",
198	    "MemoryMappedIO",
199	    "MemoryMappedIOPortSpace",
200	    "PalCode"
201	};
202
203	sz = 0;
204	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
205	if (status != EFI_BUFFER_TOO_SMALL) {
206		printf("Can't determine memory map size\n");
207		return CMD_ERROR;
208	}
209	map = malloc(sz);
210	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
211	if (EFI_ERROR(status)) {
212		printf("Can't read memory map\n");
213		return CMD_ERROR;
214	}
215
216	ndesc = sz / dsz;
217	printf("%23s %12s %12s %8s %4s\n",
218	       "Type", "Physical", "Virtual", "#Pages", "Attr");
219
220	for (i = 0, p = map; i < ndesc;
221	     i++, p = NextMemoryDescriptor(p, dsz)) {
222	    printf("%23s %012lx %012lx %08lx ",
223		   types[p->Type],
224		   p->PhysicalStart,
225		   p->VirtualStart,
226		   p->NumberOfPages);
227	    if (p->Attribute & EFI_MEMORY_UC)
228		printf("UC ");
229	    if (p->Attribute & EFI_MEMORY_WC)
230		printf("WC ");
231	    if (p->Attribute & EFI_MEMORY_WT)
232		printf("WT ");
233	    if (p->Attribute & EFI_MEMORY_WB)
234		printf("WB ");
235	    if (p->Attribute & EFI_MEMORY_UCE)
236		printf("UCE ");
237	    if (p->Attribute & EFI_MEMORY_WP)
238		printf("WP ");
239	    if (p->Attribute & EFI_MEMORY_RP)
240		printf("RP ");
241	    if (p->Attribute & EFI_MEMORY_XP)
242		printf("XP ");
243	    if (p->Attribute & EFI_MEMORY_RUNTIME)
244		printf("RUNTIME");
245	    printf("\n");
246	}
247
248	return CMD_OK;
249}
250
251COMMAND_SET(configuration, "configuration",
252	    "print configuration tables", command_configuration);
253
254static const char *
255guid_to_string(EFI_GUID *guid)
256{
257	static char buf[40];
258
259	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
260	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
261	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
262	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
263	return (buf);
264}
265
266static int
267command_configuration(int argc, char *argv[])
268{
269	int i;
270
271	printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
272	for (i = 0; i < ST->NumberOfTableEntries; i++) {
273		EFI_GUID *guid;
274
275		printf("  ");
276		guid = &ST->ConfigurationTable[i].VendorGuid;
277		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
278			printf("MPS Table");
279		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
280			printf("ACPI Table");
281		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
282			printf("ACPI 2.0 Table");
283		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
284			printf("SMBIOS Table");
285		else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
286			printf("SAL System Table");
287		else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
288			printf("DIG64 HCDP Table");
289		else
290			printf("Unknown Table (%s)", guid_to_string(guid));
291		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
292	}
293
294	return CMD_OK;
295}
296
297COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
298
299static int
300command_sal(int argc, char *argv[])
301{
302	int i;
303	struct sal_system_table *saltab = 0;
304	static int sizes[6] = {
305		48, 32, 16, 32, 16, 16
306	};
307	u_int8_t *p;
308
309	saltab = efi_get_table(&sal);
310	if (saltab == NULL) {
311		printf("Can't find SAL System Table\n");
312		return CMD_ERROR;
313	}
314
315	if (memcmp(saltab->sal_signature, "SST_", 4)) {
316		printf("Bad signature for SAL System Table\n");
317		return CMD_ERROR;
318	}
319
320	printf("SAL Revision %x.%02x\n",
321	       saltab->sal_rev[1],
322	       saltab->sal_rev[0]);
323	printf("SAL A Version %x.%02x\n",
324	       saltab->sal_a_version[1],
325	       saltab->sal_a_version[0]);
326	printf("SAL B Version %x.%02x\n",
327	       saltab->sal_b_version[1],
328	       saltab->sal_b_version[0]);
329
330	p = (u_int8_t *) (saltab + 1);
331	for (i = 0; i < saltab->sal_entry_count; i++) {
332		printf("  Desc %d", *p);
333		if (*p == 0) {
334			struct sal_entrypoint_descriptor *dp;
335			dp = (struct sal_entrypoint_descriptor *) p;
336			printf("\n");
337			printf("    PAL Proc at 0x%lx\n",
338			       dp->sale_pal_proc);
339			printf("    SAL Proc at 0x%lx\n",
340			       dp->sale_sal_proc);
341			printf("    SAL GP at 0x%lx\n",
342			       dp->sale_sal_gp);
343		} else if (*p == 1) {
344			struct sal_memory_descriptor *dp;
345			dp = (struct sal_memory_descriptor *) p;
346			printf(" Type %d.%d, ",
347			       dp->sale_memory_type[0],
348			       dp->sale_memory_type[1]);
349			printf("Address 0x%lx, ",
350			       dp->sale_physical_address);
351			printf("Length 0x%x\n",
352			       dp->sale_length);
353		} else if (*p == 5) {
354			struct sal_ap_wakeup_descriptor *dp;
355			dp = (struct sal_ap_wakeup_descriptor *) p;
356			printf("\n");
357			printf("    Mechanism %d\n", dp->sale_mechanism);
358			printf("    Vector 0x%lx\n", dp->sale_vector);
359		} else
360			printf("\n");
361
362		p += sizes[*p];
363	}
364
365	return CMD_OK;
366}
367
368int
369print_trs(int type)
370{
371	struct ia64_pal_result res;
372	int i, maxtr;
373	struct {
374		pt_entry_t	pte;
375		uint64_t	itir;
376		uint64_t	ifa;
377		struct ia64_rr	rr;
378	} buf;
379	static const char *psnames[] = {
380		"1B",	"2B",	"4B",	"8B",
381		"16B",	"32B",	"64B",	"128B",
382		"256B",	"512B",	"1K",	"2K",
383		"4K",	"8K",	"16K",	"32K",
384		"64K",	"128K",	"256K",	"512K",
385		"1M",	"2M",	"4M",	"8M",
386		"16M",	"32M",	"64M",	"128M",
387		"256M",	"512M",	"1G",	"2G"
388	};
389	static const char *manames[] = {
390		"WB",	"bad",	"bad",	"bad",
391		"UC",	"UCE",	"WC",	"NaT",
392	};
393
394	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
395	if (res.pal_status != 0) {
396		printf("Can't get VM summary\n");
397		return CMD_ERROR;
398	}
399
400	if (type == 0)
401		maxtr = (res.pal_result[0] >> 40) & 0xff;
402	else
403		maxtr = (res.pal_result[0] >> 32) & 0xff;
404
405	printf("%d translation registers\n", maxtr);
406
407	pager_open();
408	pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
409	for (i = 0; i <= maxtr; i++) {
410		char lbuf[128];
411
412		bzero(&buf, sizeof(buf));
413		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
414					    (u_int64_t) &buf);
415		if (res.pal_status != 0)
416			break;
417
418		/* Only display valid translations */
419		if ((buf.ifa & 1) == 0)
420			continue;
421
422		if (!(res.pal_result[0] & 1))
423			buf.pte &= ~PTE_AR_MASK;
424		if (!(res.pal_result[0] & 2))
425			buf.pte &= ~PTE_PL_MASK;
426		if (!(res.pal_result[0] & 4))
427			buf.pte &= ~PTE_DIRTY;
428		if (!(res.pal_result[0] & 8))
429			buf.pte &= ~PTE_MA_MASK;
430		sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d "
431		    "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12,
432		    (buf.pte & PTE_PPN_MASK) >> 12,
433		    psnames[(buf.itir & ITIR_PS_MASK) >> 2],
434		    (buf.pte & PTE_ED) ? 1 : 0,
435		    (int)(buf.pte & PTE_AR_MASK) >> 9,
436		    (int)(buf.pte & PTE_PL_MASK) >> 7,
437		    (buf.pte & PTE_DIRTY) ? 1 : 0,
438		    (buf.pte & PTE_ACCESSED) ? 1 : 0,
439		    manames[(buf.pte & PTE_MA_MASK) >> 2],
440		    (buf.pte & PTE_PRESENT) ? 1 : 0,
441		    (int)((buf.itir & ITIR_KEY_MASK) >> 8));
442		pager_output(lbuf);
443	}
444	pager_close();
445
446	if (res.pal_status != 0) {
447		printf("Error while getting TR contents\n");
448		return CMD_ERROR;
449	}
450	return CMD_OK;
451}
452
453COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
454
455static int
456command_itr(int argc, char *argv[])
457{
458	return print_trs(0);
459}
460
461COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
462
463static int
464command_dtr(int argc, char *argv[])
465{
466	return print_trs(1);
467}
468
469COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
470
471static char *
472hcdp_string(char *s, u_int len)
473{
474	static char buffer[256];
475
476	memcpy(buffer, s, len);
477	buffer[len] = 0;
478	return (buffer);
479}
480
481static int
482command_hcdp(int argc, char *argv[])
483{
484	struct dig64_hcdp_table *tbl;
485	struct dig64_hcdp_entry *ent;
486	struct dig64_gas *gas;
487	int i;
488
489	tbl = efi_get_table(&hcdp);
490	if (tbl == NULL) {
491		printf("No HCDP table present\n");
492		return (CMD_OK);
493	}
494	if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
495		printf("HCDP table has invalid signature\n");
496		return (CMD_OK);
497	}
498	if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) {
499		printf("HCDP table too short\n");
500		return (CMD_OK);
501	}
502	printf("HCDP table at 0x%016lx\n", (u_long)tbl);
503	printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
504	printf("Length     = %u\n", tbl->length);
505	printf("Revision   = %u\n", tbl->revision);
506	printf("Checksum   = %u\n", tbl->checksum);
507	printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
508	printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
509	printf("OEM rev    = %u\n", tbl->oem_rev);
510	printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
511	printf("Creator rev= %u\n", tbl->creator_rev);
512	printf("Entries    = %u\n", tbl->entries);
513	for (i = 0; i < tbl->entries; i++) {
514		ent = tbl->entry + i;
515		printf("Entry #%d:\n", i + 1);
516		printf("    Type      = %u\n", ent->type);
517		printf("    Databits  = %u\n", ent->databits);
518		printf("    Parity    = %u\n", ent->parity);
519		printf("    Stopbits  = %u\n", ent->stopbits);
520		printf("    PCI seg   = %u\n", ent->pci_segment);
521		printf("    PCI bus   = %u\n", ent->pci_bus);
522		printf("    PCI dev   = %u\n", ent->pci_device);
523		printf("    PCI func  = %u\n", ent->pci_function);
524		printf("    Interrupt = %u\n", ent->interrupt);
525		printf("    PCI flag  = %u\n", ent->pci_flag);
526		printf("    Baudrate  = %lu\n",
527		    ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low);
528		gas = &ent->address;
529		printf("    Addr space= %u\n", gas->addr_space);
530		printf("    Bit width = %u\n", gas->bit_width);
531		printf("    Bit offset= %u\n", gas->bit_offset);
532		printf("    Address   = 0x%016lx\n",
533		    ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low);
534		printf("    PCI type  = %u\n", ent->pci_devid);
535		printf("    PCI vndr  = %u\n", ent->pci_vendor);
536		printf("    IRQ       = %u\n", ent->irq);
537		printf("    PClock    = %u\n", ent->pclock);
538		printf("    PCI iface = %u\n", ent->pci_interface);
539	}
540	printf("<EOT>\n");
541	return (CMD_OK);
542}
543