main.c revision 137978
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 137978 2004-11-21 21:40:08Z 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 "bootstrap.h"
43#include "efiboot.h"
44
45extern char bootprog_name[];
46extern char bootprog_rev[];
47extern char bootprog_date[];
48extern char bootprog_maker[];
49
50struct efi_devdesc	currdev;	/* our current device */
51struct arch_switch	archsw;		/* MI/MD interface boundary */
52
53extern u_int64_t	ia64_pal_entry;
54
55EFI_GUID acpi = ACPI_TABLE_GUID;
56EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
57EFI_GUID devid = DEVICE_PATH_PROTOCOL;
58EFI_GUID hcdp = HCDP_TABLE_GUID;
59EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
60EFI_GUID mps = MPS_TABLE_GUID;
61EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
62EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
63EFI_GUID smbios = SMBIOS_TABLE_GUID;
64
65static void
66find_pal_proc(void)
67{
68	int i;
69	struct sal_system_table *saltab = 0;
70	static int sizes[6] = {
71		48, 32, 16, 32, 16, 16
72	};
73	u_int8_t *p;
74
75	saltab = efi_get_table(&sal);
76	if (saltab == NULL) {
77		printf("Can't find SAL System Table\n");
78		return;
79	}
80
81	if (memcmp(saltab->sal_signature, "SST_", 4)) {
82		printf("Bad signature for SAL System Table\n");
83		return;
84	}
85
86	p = (u_int8_t *) (saltab + 1);
87	for (i = 0; i < saltab->sal_entry_count; i++) {
88		if (*p == 0) {
89			struct sal_entrypoint_descriptor *dp;
90			dp = (struct sal_entrypoint_descriptor *) p;
91			ia64_pal_entry = dp->sale_pal_proc;
92			return;
93		}
94		p += sizes[*p];
95	}
96
97	printf("Can't find PAL proc\n");
98	return;
99}
100
101EFI_STATUS
102main(int argc, CHAR16 *argv[])
103{
104	EFI_LOADED_IMAGE *img;
105	int i;
106
107	/*
108	 * XXX Chicken-and-egg problem; we want to have console output
109	 * early, but some console attributes may depend on reading from
110	 * eg. the boot device, which we can't do yet.  We can use
111	 * printf() etc. once this is done.
112	 */
113	cons_probe();
114
115	/*
116	 * Initialise the block cache
117	 */
118	bcache_init(32, 512);		/* 16k XXX tune this */
119
120	find_pal_proc();
121
122	/*
123	 * March through the device switch probing for things.
124	 */
125	for (i = 0; devsw[i] != NULL; i++)
126		if (devsw[i]->dv_init != NULL)
127			(devsw[i]->dv_init)();
128
129	efinet_init_driver();
130
131	/* Get our loaded image protocol interface structure. */
132	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
133
134	printf("Image base: 0x%016lx\n", (u_long)img->ImageBase);
135
136	printf("\n");
137	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
138	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
139
140	i = efifs_get_unit(img->DeviceHandle);
141	if (i >= 0) {
142		currdev.d_dev = devsw[0];		/* XXX disk */
143		currdev.d_kind.efidisk.unit = i;
144		/* XXX should be able to detect this, default to autoprobe */
145		currdev.d_kind.efidisk.slice = -1;
146		currdev.d_kind.efidisk.partition = 0;
147	} else {
148		currdev.d_dev = devsw[1];		/* XXX net */
149		currdev.d_kind.netif.unit = 0;		/* XXX */
150	}
151	currdev.d_type = currdev.d_dev->dv_type;
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	    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
182COMMAND_SET(quit, "quit", "exit the loader", command_quit);
183
184static int
185command_quit(int argc, char *argv[])
186{
187	exit(0);
188	return (CMD_OK);
189}
190
191COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
192
193static int
194command_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 = malloc(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
267COMMAND_SET(configuration, "configuration",
268	    "print configuration tables", command_configuration);
269
270static const char *
271guid_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
282static int
283command_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
313COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
314
315static int
316command_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
384int
385print_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		bzero(&buf, 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
469COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
470
471static int
472command_itr(int argc, char *argv[])
473{
474	return print_trs(0);
475}
476
477COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
478
479static int
480command_dtr(int argc, char *argv[])
481{
482	return print_trs(1);
483}
484
485COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
486
487static char *
488hcdp_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
497static int
498command_hcdp(int argc, char *argv[])
499{
500	struct dig64_hcdp_table *tbl;
501	struct dig64_hcdp_entry *ent;
502	struct dig64_gas *gas;
503	int i;
504
505	tbl = efi_get_table(&hcdp);
506	if (tbl == NULL) {
507		printf("No HCDP table present\n");
508		return (CMD_OK);
509	}
510	if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
511		printf("HCDP table has invalid signature\n");
512		return (CMD_OK);
513	}
514	if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) {
515		printf("HCDP table too short\n");
516		return (CMD_OK);
517	}
518	printf("HCDP table at 0x%016lx\n", (u_long)tbl);
519	printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
520	printf("Length     = %u\n", tbl->length);
521	printf("Revision   = %u\n", tbl->revision);
522	printf("Checksum   = %u\n", tbl->checksum);
523	printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
524	printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
525	printf("OEM rev    = %u\n", tbl->oem_rev);
526	printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
527	printf("Creator rev= %u\n", tbl->creator_rev);
528	printf("Entries    = %u\n", tbl->entries);
529	for (i = 0; i < tbl->entries; i++) {
530		ent = tbl->entry + i;
531		printf("Entry #%d:\n", i + 1);
532		printf("    Type      = %u\n", ent->type);
533		printf("    Databits  = %u\n", ent->databits);
534		printf("    Parity    = %u\n", ent->parity);
535		printf("    Stopbits  = %u\n", ent->stopbits);
536		printf("    PCI seg   = %u\n", ent->pci_segment);
537		printf("    PCI bus   = %u\n", ent->pci_bus);
538		printf("    PCI dev   = %u\n", ent->pci_device);
539		printf("    PCI func  = %u\n", ent->pci_function);
540		printf("    Interrupt = %u\n", ent->interrupt);
541		printf("    PCI flag  = %u\n", ent->pci_flag);
542		printf("    Baudrate  = %lu\n",
543		    ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low);
544		gas = &ent->address;
545		printf("    Addr space= %u\n", gas->addr_space);
546		printf("    Bit width = %u\n", gas->bit_width);
547		printf("    Bit offset= %u\n", gas->bit_offset);
548		printf("    Address   = 0x%016lx\n",
549		    ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low);
550		printf("    PCI type  = %u\n", ent->pci_devid);
551		printf("    PCI vndr  = %u\n", ent->pci_vendor);
552		printf("    IRQ       = %u\n", ent->irq);
553		printf("    PClock    = %u\n", ent->pclock);
554		printf("    PCI iface = %u\n", ent->pci_interface);
555	}
556	printf("<EOT>\n");
557	return (CMD_OK);
558}
559