main.c revision 107722
1116576Smurray/*-
2116576Smurray * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3116576Smurray * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
4116576Smurray * All rights reserved.
5116576Smurray *
6116576Smurray * Redistribution and use in source and binary forms, with or without
7116576Smurray * modification, are permitted provided that the following conditions
8116576Smurray * are met:
9116576Smurray * 1. Redistributions of source code must retain the above copyright
10116576Smurray *    notice, this list of conditions and the following disclaimer.
11116576Smurray * 2. Redistributions in binary form must reproduce the above copyright
12116576Smurray *    notice, this list of conditions and the following disclaimer in the
13116576Smurray *    documentation and/or other materials provided with the distribution.
14116576Smurray *
15116576Smurray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116576Smurray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116576Smurray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116576Smurray * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116576Smurray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116576Smurray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116576Smurray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116576Smurray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116576Smurray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116576Smurray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116576Smurray * SUCH DAMAGE.
26116576Smurray */
27116576Smurray
28116576Smurray#ifndef lint
29116576Smurraystatic const char rcsid[] =
30116576Smurray  "$FreeBSD: head/sys/boot/ia64/efi/main.c 107722 2002-12-10 04:55:25Z marcel $";
31116576Smurray#endif /* not lint */
32116576Smurray
33116576Smurray#include <stand.h>
34116576Smurray#include <string.h>
35116576Smurray#include <setjmp.h>
36116576Smurray#include <machine/sal.h>
37116576Smurray#include <machine/pal.h>
38116576Smurray#include <machine/pte.h>
39116576Smurray
40116576Smurray#include <efi.h>
41116576Smurray#include <efilib.h>
42116576Smurray
43116576Smurray#include "bootstrap.h"
44116576Smurray#include "efiboot.h"
45116576Smurray
46116576Smurrayextern char bootprog_name[];
47116576Smurrayextern char bootprog_rev[];
48116576Smurrayextern char bootprog_date[];
49116576Smurrayextern char bootprog_maker[];
50116576Smurray
51116576Smurraystruct efi_devdesc	currdev;	/* our current device */
52116576Smurraystruct arch_switch	archsw;		/* MI/MD interface boundary */
53116576Smurray
54116576Smurrayextern u_int64_t	ia64_pal_entry;
55116576Smurray
56116576SmurrayEFI_GUID acpi = ACPI_TABLE_GUID;
57116576SmurrayEFI_GUID acpi20 = ACPI_20_TABLE_GUID;
58116576SmurrayEFI_GUID hcdp = HCDP_TABLE_GUID;
59116576SmurrayEFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
60116576SmurrayEFI_GUID mps = MPS_TABLE_GUID;
61116576SmurrayEFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
62116576SmurrayEFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
63116576SmurrayEFI_GUID smbios = SMBIOS_TABLE_GUID;
64116576Smurray
65116576Smurraystatic void
66116576Smurrayfind_pal_proc(void)
67116576Smurray{
68116576Smurray	int i;
69116576Smurray	struct sal_system_table *saltab = 0;
70116576Smurray	static int sizes[6] = {
71116576Smurray		48, 32, 16, 32, 16, 16
72116576Smurray	};
73116576Smurray	u_int8_t *p;
74116576Smurray
75116576Smurray	for (i = 0; i < ST->NumberOfTableEntries; i++) {
76116576Smurray		if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
77116576Smurray				 &sal, sizeof(EFI_GUID)))
78116576Smurray			saltab = ST->ConfigurationTable[i].VendorTable;
79116576Smurray	}
80116576Smurray
81116576Smurray	if (!saltab) {
82116576Smurray		printf("Can't find SAL System Table\n");
83116576Smurray		return;
84116576Smurray	}
85116576Smurray
86116576Smurray	if (memcmp(saltab->sal_signature, "SST_", 4)) {
87116576Smurray		printf("Bad signature for SAL System Table\n");
88116576Smurray		return;
89116576Smurray	}
90116576Smurray
91116576Smurray	p = (u_int8_t *) (saltab + 1);
92116576Smurray	for (i = 0; i < saltab->sal_entry_count; i++) {
93116576Smurray		if (*p == 0) {
94116576Smurray			struct sal_entrypoint_descriptor *dp;
95116576Smurray			dp = (struct sal_entrypoint_descriptor *) p;
96116576Smurray			ia64_pal_entry = dp->sale_pal_proc;
97116576Smurray			return;
98116576Smurray		}
99116576Smurray		p += sizes[*p];
100116576Smurray	}
101116576Smurray
102116576Smurray	printf("Can't find PAL proc\n");
103116576Smurray	return;
104116576Smurray}
105116576Smurray
106116576SmurrayEFI_STATUS
107116576Smurrayefi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
108116576Smurray{
109116576Smurray	EFI_PHYSICAL_ADDRESS mem;
110116576Smurray	EFI_LOADED_IMAGE *img;
111116576Smurray	EFI_SIMPLE_NETWORK *net;
112116576Smurray	EFI_STATUS status;
113116576Smurray	struct ia64_pal_result res;
114116576Smurray	char buf[32];
115116576Smurray	int i;
116116576Smurray
117116576Smurray	efi_init(image_handle, system_table);
118116576Smurray
119116576Smurray	/*
120116576Smurray	 * Initialise the heap as early as possible.  Once this is done,
121116576Smurray	 * alloc() is usable. The stack is buried inside us, so this is
122116576Smurray	 * safe.
123116576Smurray	 */
124116576Smurray	BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
125116576Smurray			  512*1024/4096, &mem);
126116576Smurray	setheap((void *)mem, (void *)(mem + 512*1024));
127116576Smurray
128116576Smurray	/*
129116576Smurray	 * XXX Chicken-and-egg problem; we want to have console output
130116576Smurray	 * early, but some console attributes may depend on reading from
131116576Smurray	 * eg. the boot device, which we can't do yet.  We can use
132116576Smurray	 * printf() etc. once this is done.
133116576Smurray	 */
134116576Smurray	cons_probe();
135116576Smurray
136116576Smurray	/*
137116576Smurray	 * Initialise the block cache
138116576Smurray	 */
139116576Smurray	bcache_init(32, 512);		/* 16k XXX tune this */
140
141	find_pal_proc();
142
143	/*
144	 * March through the device switch probing for things.
145	 */
146	for (i = 0; devsw[i] != NULL; i++)
147		if (devsw[i]->dv_init != NULL)
148			(devsw[i]->dv_init)();
149
150	efinet_init_driver();
151
152	printf("\n");
153	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
154	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
155#if 0
156	printf("Memory: %ld k\n", memsize() / 1024);
157#endif
158
159
160	/*
161	 * XXX quick and dirty check to see if we're loaded from the
162	 * network. If so, we set the default device to 'net'. In all
163	 * other cases we set the default device to 'disk'. We presume
164	 * fixed positions in devsw for both net and disk.
165	 */
166	BS->HandleProtocol(image_handle, &imgid, (VOID**)&img);
167
168	status = BS->HandleProtocol(img->DeviceHandle, &netid, (VOID**)&net);
169	if (status == EFI_SUCCESS && net != NULL) {
170		currdev.d_dev = devsw[1];	/* XXX net */
171		currdev.d_kind.netif.unit = 0;
172	} else {
173		currdev.d_dev = devsw[0];	/* XXX disk */
174		currdev.d_kind.efidisk.unit = 0;
175		/* XXX should be able to detect this, default to autoprobe */
176		currdev.d_kind.efidisk.slice = -1;
177		/* default to 'a' */
178		currdev.d_kind.efidisk.partition = 0;
179	}
180
181	currdev.d_type = currdev.d_dev->dv_type;
182
183	/*
184	 * Disable the watchdog timer. By default the boot manager sets
185	 * the timer to 5 minutes before invoking a boot option. If we
186	 * want to return to the boot manager, we have to disable the
187	 * watchdog timer and since we're an interactive program, we don't
188	 * want to wait until the user types "quit". The timer may have
189	 * fired by then. We don't care if this fails. It does not prevent
190	 * normal functioning in any way...
191	 */
192	BS->SetWatchdogTimer(0, 0, 0, NULL);
193
194	env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
195	    efi_setcurrdev, env_nounset);
196	env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
197	    env_nounset);
198
199	setenv("LINES", "24", 1);	/* optional */
200
201	archsw.arch_autoload = efi_autoload;
202	archsw.arch_getdev = efi_getdev;
203	archsw.arch_copyin = efi_copyin;
204	archsw.arch_copyout = efi_copyout;
205	archsw.arch_readin = efi_readin;
206
207	interact();			/* doesn't return */
208
209	return (EFI_SUCCESS);		/* keep compiler happy */
210}
211
212COMMAND_SET(quit, "quit", "exit the loader", command_quit);
213
214static int
215command_quit(int argc, char *argv[])
216{
217	exit(0);
218	return (CMD_OK);
219}
220
221COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
222
223static int
224command_memmap(int argc, char *argv[])
225{
226	UINTN sz;
227	EFI_MEMORY_DESCRIPTOR *map, *p;
228	UINTN key, dsz;
229	UINT32 dver;
230	EFI_STATUS status;
231	int i, ndesc;
232	static char *types[] = {
233	    "Reserved",
234	    "LoaderCode",
235	    "LoaderData",
236	    "BootServicesCode",
237	    "BootServicesData",
238	    "RuntimeServicesCode",
239	    "RuntimeServicesData",
240	    "ConventionalMemory",
241	    "UnusableMemory",
242	    "ACPIReclaimMemory",
243	    "ACPIMemoryNVS",
244	    "MemoryMappedIO",
245	    "MemoryMappedIOPortSpace",
246	    "PalCode"
247	};
248
249	sz = 0;
250	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
251	if (status != EFI_BUFFER_TOO_SMALL) {
252		printf("Can't determine memory map size\n");
253		return CMD_ERROR;
254	}
255	map = malloc(sz);
256	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
257	if (EFI_ERROR(status)) {
258		printf("Can't read memory map\n");
259		return CMD_ERROR;
260	}
261
262	ndesc = sz / dsz;
263	printf("%23s %12s %12s %8s %4s\n",
264	       "Type", "Physical", "Virtual", "#Pages", "Attr");
265
266	for (i = 0, p = map; i < ndesc;
267	     i++, p = NextMemoryDescriptor(p, dsz)) {
268	    printf("%23s %012lx %012lx %08lx ",
269		   types[p->Type],
270		   p->PhysicalStart,
271		   p->VirtualStart,
272		   p->NumberOfPages);
273	    if (p->Attribute & EFI_MEMORY_UC)
274		printf("UC ");
275	    if (p->Attribute & EFI_MEMORY_WC)
276		printf("WC ");
277	    if (p->Attribute & EFI_MEMORY_WT)
278		printf("WT ");
279	    if (p->Attribute & EFI_MEMORY_WB)
280		printf("WB ");
281	    if (p->Attribute & EFI_MEMORY_UCE)
282		printf("UCE ");
283	    if (p->Attribute & EFI_MEMORY_WP)
284		printf("WP ");
285	    if (p->Attribute & EFI_MEMORY_RP)
286		printf("RP ");
287	    if (p->Attribute & EFI_MEMORY_XP)
288		printf("XP ");
289	    if (p->Attribute & EFI_MEMORY_RUNTIME)
290		printf("RUNTIME");
291	    printf("\n");
292	}
293
294	return CMD_OK;
295}
296
297COMMAND_SET(configuration, "configuration",
298	    "print configuration tables", command_configuration);
299
300static const char *
301guid_to_string(EFI_GUID *guid)
302{
303	static char buf[40];
304
305	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
306	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
307	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
308	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
309	return (buf);
310}
311
312static int
313command_configuration(int argc, char *argv[])
314{
315	int i;
316
317	printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
318	for (i = 0; i < ST->NumberOfTableEntries; i++) {
319		EFI_GUID *guid;
320
321		printf("  ");
322		guid = &ST->ConfigurationTable[i].VendorGuid;
323		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
324			printf("MPS Table");
325		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
326			printf("ACPI Table");
327		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
328			printf("ACPI 2.0 Table");
329		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
330			printf("SMBIOS Table");
331		else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
332			printf("SAL System Table");
333		else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
334			printf("DIG64 HCDP Table");
335		else
336			printf("Unknown Table (%s)", guid_to_string(guid));
337		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
338	}
339
340	return CMD_OK;
341}
342
343COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
344
345static int
346command_sal(int argc, char *argv[])
347{
348	int i;
349	struct sal_system_table *saltab = 0;
350	static int sizes[6] = {
351		48, 32, 16, 32, 16, 16
352	};
353	u_int8_t *p;
354
355	for (i = 0; i < ST->NumberOfTableEntries; i++) {
356		if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
357				 &sal, sizeof(EFI_GUID)))
358			saltab = ST->ConfigurationTable[i].VendorTable;
359	}
360
361	if (!saltab) {
362		printf("Can't find SAL System Table\n");
363		return CMD_ERROR;
364	}
365
366	if (memcmp(saltab->sal_signature, "SST_", 4)) {
367		printf("Bad signature for SAL System Table\n");
368		return CMD_ERROR;
369	}
370
371	printf("SAL Revision %x.%02x\n",
372	       saltab->sal_rev[1],
373	       saltab->sal_rev[0]);
374	printf("SAL A Version %x.%02x\n",
375	       saltab->sal_a_version[1],
376	       saltab->sal_a_version[0]);
377	printf("SAL B Version %x.%02x\n",
378	       saltab->sal_b_version[1],
379	       saltab->sal_b_version[0]);
380
381	p = (u_int8_t *) (saltab + 1);
382	for (i = 0; i < saltab->sal_entry_count; i++) {
383		printf("  Desc %d", *p);
384		if (*p == 0) {
385			struct sal_entrypoint_descriptor *dp;
386			dp = (struct sal_entrypoint_descriptor *) p;
387			printf("\n");
388			printf("    PAL Proc at 0x%lx\n",
389			       dp->sale_pal_proc);
390			printf("    SAL Proc at 0x%lx\n",
391			       dp->sale_sal_proc);
392			printf("    SAL GP at 0x%lx\n",
393			       dp->sale_sal_gp);
394		} else if (*p == 1) {
395			struct sal_memory_descriptor *dp;
396			dp = (struct sal_memory_descriptor *) p;
397			printf(" Type %d.%d, ",
398			       dp->sale_memory_type[0],
399			       dp->sale_memory_type[1]);
400			printf("Address 0x%lx, ",
401			       dp->sale_physical_address);
402			printf("Length 0x%x\n",
403			       dp->sale_length);
404		} else if (*p == 5) {
405			struct sal_ap_wakeup_descriptor *dp;
406			dp = (struct sal_ap_wakeup_descriptor *) p;
407			printf("\n");
408			printf("    Mechanism %d\n", dp->sale_mechanism);
409			printf("    Vector 0x%lx\n", dp->sale_vector);
410		} else
411			printf("\n");
412
413		p += sizes[*p];
414	}
415
416	return CMD_OK;
417}
418
419int
420print_trs(int type)
421{
422	struct ia64_pal_result	res;
423	int			i, maxtr;
424	struct {
425		struct ia64_pte	pte;
426		struct ia64_itir itir;
427		struct ia64_ifa ifa;
428		struct ia64_rr	rr;
429	}			buf;
430	static const char*	psnames[] = {
431		"1B",	"2B",	"4B",	"8B",
432		"16B",	"32B",	"64B",	"128B",
433		"256B",	"512B",	"1K",	"2K",
434		"4K",	"8K",	"16K",	"32K",
435		"64K",	"128K",	"256K",	"512K",
436		"1M",	"2M",	"4M",	"8M",
437		"16M",	"32M",	"64M",	"128M",
438		"256M",	"512M",	"1G",	"2G"
439	};
440	static const char*	manames[] = {
441		"WB",	"bad",	"bad",	"bad",
442		"UC",	"UCE",	"WC",	"NaT",
443
444	};
445
446	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
447	if (res.pal_status != 0) {
448		printf("Can't get VM summary\n");
449		return CMD_ERROR;
450	}
451
452	if (type == 0)
453		maxtr = (res.pal_result[0] >> 40) & 0xff;
454	else
455		maxtr = (res.pal_result[0] >> 32) & 0xff;
456
457	printf("%d translation registers\n", maxtr);
458
459	pager_open();
460	pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
461	for (i = 0; i <= maxtr; i++) {
462		char lbuf[128];
463
464		bzero(&buf, sizeof(buf));
465		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
466					    (u_int64_t) &buf);
467		if (res.pal_status != 0)
468			break;
469
470		/* Only display valid translations */
471		if ((buf.ifa.ifa_ig & 1) == 0)
472			continue;
473
474		if (!(res.pal_result[0] & 1))
475			buf.pte.pte_ar = 0;
476		if (!(res.pal_result[0] & 2))
477			buf.pte.pte_pl = 0;
478		if (!(res.pal_result[0] & 4))
479			buf.pte.pte_d = 0;
480		if (!(res.pal_result[0] & 8))
481			buf.pte.pte_ma = 0;
482		sprintf(lbuf,
483	"%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d %-3s %d %06x\n",
484			i,
485			buf.rr.rr_rid,
486			buf.ifa.ifa_vpn,
487			buf.pte.pte_ppn,
488			psnames[buf.itir.itir_ps],
489			buf.pte.pte_ed,
490			buf.pte.pte_ar,
491			buf.pte.pte_pl,
492			buf.pte.pte_d,
493			buf.pte.pte_a,
494			manames[buf.pte.pte_ma],
495			buf.pte.pte_p,
496			buf.itir.itir_key);
497		pager_output(lbuf);
498	}
499	pager_close();
500
501	if (res.pal_status != 0) {
502		printf("Error while getting TR contents\n");
503		return CMD_ERROR;
504	}
505	return CMD_OK;
506}
507
508COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
509
510static int
511command_itr(int argc, char *argv[])
512{
513	return print_trs(0);
514}
515
516COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
517
518static int
519command_dtr(int argc, char *argv[])
520{
521	return print_trs(1);
522}
523
524