main.c revision 93411
1290001Sglebius/*-
2290001Sglebius * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3290001Sglebius * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
4290001Sglebius * All rights reserved.
5290001Sglebius *
6290001Sglebius * Redistribution and use in source and binary forms, with or without
7290001Sglebius * modification, are permitted provided that the following conditions
8290001Sglebius * are met:
9290001Sglebius * 1. Redistributions of source code must retain the above copyright
10290001Sglebius *    notice, this list of conditions and the following disclaimer.
11290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
12290001Sglebius *    notice, this list of conditions and the following disclaimer in the
13290001Sglebius *    documentation and/or other materials provided with the distribution.
14290001Sglebius *
15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16290001Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17290001Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18290001Sglebius * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19290001Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20290001Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21290001Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22290001Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23290001Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24290001Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25290001Sglebius * SUCH DAMAGE.
26290001Sglebius */
27290001Sglebius
28290001Sglebius#ifndef lint
29290001Sglebiusstatic const char rcsid[] =
30290001Sglebius  "$FreeBSD: head/sys/boot/ia64/efi/main.c 93411 2002-03-30 07:32:08Z marcel $";
31290001Sglebius#endif /* not lint */
32290001Sglebius
33290001Sglebius#include <stand.h>
34290001Sglebius#include <string.h>
35290001Sglebius#include <setjmp.h>
36290001Sglebius#include <machine/sal.h>
37290001Sglebius#include <machine/pal.h>
38290001Sglebius#include <machine/pte.h>
39290001Sglebius
40290001Sglebius#include <efi.h>
41290001Sglebius#include <efilib.h>
42290001Sglebius
43290001Sglebius#include "bootstrap.h"
44290001Sglebius#include "efiboot.h"
45290001Sglebius
46290001Sglebiusextern char bootprog_name[];
47290001Sglebiusextern char bootprog_rev[];
48290001Sglebiusextern char bootprog_date[];
49290001Sglebiusextern char bootprog_maker[];
50290001Sglebius
51290001Sglebiusstruct efi_devdesc	currdev;	/* our current device */
52290001Sglebiusstruct arch_switch	archsw;		/* MI/MD interface boundary */
53290001Sglebius
54290001Sglebiusextern u_int64_t	ia64_pal_entry;
55290001Sglebius
56290001Sglebiusstatic void
57290001Sglebiusfind_pal_proc(void)
58290001Sglebius{
59290001Sglebius	int i;
60290001Sglebius	struct sal_system_table *saltab = 0;
61290001Sglebius	static int sizes[6] = {
62290001Sglebius		48, 32, 16, 32, 16, 16
63290001Sglebius	};
64290001Sglebius	u_int8_t *p;
65290001Sglebius
66290001Sglebius	for (i = 0; i < ST->NumberOfTableEntries; i++) {
67290001Sglebius		static EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
68290001Sglebius		if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
69290001Sglebius				 &sal, sizeof(EFI_GUID)))
70290001Sglebius			saltab = ST->ConfigurationTable[i].VendorTable;
71290001Sglebius	}
72290001Sglebius
73290001Sglebius	if (!saltab) {
74290001Sglebius		printf("Can't find SAL System Table\n");
75290001Sglebius		return;
76290001Sglebius	}
77290001Sglebius
78290001Sglebius	if (memcmp(saltab->sal_signature, "SST_", 4)) {
79290001Sglebius		printf("Bad signature for SAL System Table\n");
80290001Sglebius		return;
81290001Sglebius	}
82290001Sglebius
83290001Sglebius	p = (u_int8_t *) (saltab + 1);
84290001Sglebius	for (i = 0; i < saltab->sal_entry_count; i++) {
85290001Sglebius		if (*p == 0) {
86290001Sglebius			struct sal_entrypoint_descriptor *dp;
87290001Sglebius			dp = (struct sal_entrypoint_descriptor *) p;
88290001Sglebius			ia64_pal_entry = dp->sale_pal_proc;
89290001Sglebius			return;
90290001Sglebius		}
91290001Sglebius		p += sizes[*p];
92290001Sglebius	}
93290001Sglebius
94290001Sglebius	printf("Can't find PAL proc\n");
95290001Sglebius	return;
96290001Sglebius}
97290001Sglebius
98290001SglebiusEFI_STATUS
99290001Sglebiusefi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
100290001Sglebius{
101290001Sglebius	static EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
102290001Sglebius	static EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
103290001Sglebius	EFI_PHYSICAL_ADDRESS mem;
104290001Sglebius	EFI_LOADED_IMAGE *img;
105290001Sglebius	EFI_SIMPLE_NETWORK *net;
106290001Sglebius	EFI_STATUS status;
107290001Sglebius	struct ia64_pal_result res;
108290001Sglebius	char buf[32];
109290001Sglebius	int i;
110290001Sglebius
111290001Sglebius	efi_init(image_handle, system_table);
112290001Sglebius
113290001Sglebius	/*
114290001Sglebius	 * Initialise the heap as early as possible.  Once this is done,
115290001Sglebius	 * alloc() is usable. The stack is buried inside us, so this is
116290001Sglebius	 * safe.
117290001Sglebius	 */
118290001Sglebius	BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
119290001Sglebius			  512*1024/4096, &mem);
120290001Sglebius	setheap((void *)mem, (void *)(mem + 512*1024));
121290001Sglebius
122290001Sglebius	/*
123290001Sglebius	 * XXX Chicken-and-egg problem; we want to have console output
124290001Sglebius	 * early, but some console attributes may depend on reading from
125290001Sglebius	 * eg. the boot device, which we can't do yet.  We can use
126290001Sglebius	 * printf() etc. once this is done.
127290001Sglebius	 */
128290001Sglebius	cons_probe();
129290001Sglebius
130290001Sglebius	/*
131290001Sglebius	 * Initialise the block cache
132290001Sglebius	 */
133290001Sglebius	bcache_init(32, 512);		/* 16k XXX tune this */
134290001Sglebius
135290001Sglebius	find_pal_proc();
136290001Sglebius
137290001Sglebius	/*
138290001Sglebius	 * March through the device switch probing for things.
139290001Sglebius	 */
140290001Sglebius	for (i = 0; devsw[i] != NULL; i++)
141290001Sglebius		if (devsw[i]->dv_init != NULL)
142290001Sglebius			(devsw[i]->dv_init)();
143290001Sglebius
144290001Sglebius	efinet_init_driver();
145290001Sglebius
146290001Sglebius	printf("\n");
147290001Sglebius	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
148290001Sglebius	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
149290001Sglebius#if 0
150290001Sglebius	printf("Memory: %ld k\n", memsize() / 1024);
151290001Sglebius#endif
152290001Sglebius
153290001Sglebius
154290001Sglebius	/*
155290001Sglebius	 * XXX quick and dirty check to see if we're loaded from the
156290001Sglebius	 * network. If so, we set the default device to 'net'. In all
157290001Sglebius	 * other cases we set the default device to 'disk'. We presume
158290001Sglebius	 * fixed positions in devsw for both net and disk.
159290001Sglebius	 */
160290001Sglebius	BS->HandleProtocol(image_handle, &imgid, (VOID**)&img);
161290001Sglebius
162290001Sglebius	status = BS->HandleProtocol(img->DeviceHandle, &netid, (VOID**)&net);
163290001Sglebius	if (status == EFI_SUCCESS && net != NULL) {
164290001Sglebius		currdev.d_dev = devsw[1];	/* XXX net */
165290001Sglebius		currdev.d_kind.netif.unit = 0;
166290001Sglebius	} else {
167290001Sglebius		currdev.d_dev = devsw[0];	/* XXX disk */
168290001Sglebius		currdev.d_kind.efidisk.unit = 0;
169290001Sglebius		/* XXX should be able to detect this, default to autoprobe */
170290001Sglebius		currdev.d_kind.efidisk.slice = -1;
171290001Sglebius		/* default to 'a' */
172290001Sglebius		currdev.d_kind.efidisk.partition = 0;
173290001Sglebius	}
174290001Sglebius
175290001Sglebius	currdev.d_type = currdev.d_dev->dv_type;
176290001Sglebius
177290001Sglebius#if 0
178290001Sglebius	/* Create arc-specific variables */
179290001Sglebius	bootfile = GetEnvironmentVariable(ARCENV_BOOTFILE);
180290001Sglebius	if (bootfile)
181290001Sglebius		setenv("bootfile", bootfile, 1);
182290001Sglebius#endif
183290001Sglebius
184290001Sglebius	env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
185290001Sglebius	    efi_setcurrdev, env_nounset);
186290001Sglebius	env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
187290001Sglebius	    env_nounset);
188290001Sglebius
189290001Sglebius	setenv("LINES", "24", 1);	/* optional */
190290001Sglebius
191290001Sglebius	archsw.arch_autoload = efi_autoload;
192290001Sglebius	archsw.arch_getdev = efi_getdev;
193290001Sglebius	archsw.arch_copyin = efi_copyin;
194290001Sglebius	archsw.arch_copyout = efi_copyout;
195290001Sglebius	archsw.arch_readin = efi_readin;
196290001Sglebius
197290001Sglebius	interact();			/* doesn't return */
198290001Sglebius
199290001Sglebius	return (EFI_SUCCESS);		/* keep compiler happy */
200290001Sglebius}
201290001Sglebius
202290001SglebiusCOMMAND_SET(quit, "quit", "exit the loader", command_quit);
203290001Sglebius
204290001Sglebiusstatic int
205290001Sglebiuscommand_quit(int argc, char *argv[])
206290001Sglebius{
207290001Sglebius	exit(0);
208290001Sglebius	return (CMD_OK);
209290001Sglebius}
210290001Sglebius
211290001SglebiusCOMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
212290001Sglebius
213290001Sglebiusstatic int
214290001Sglebiuscommand_memmap(int argc, char *argv[])
215290001Sglebius{
216290001Sglebius	UINTN sz;
217290001Sglebius	EFI_MEMORY_DESCRIPTOR *map, *p;
218290001Sglebius	UINTN key, dsz;
219290001Sglebius	UINT32 dver;
220290001Sglebius	EFI_STATUS status;
221290001Sglebius	int i, ndesc;
222290001Sglebius	static char *types[] = {
223290001Sglebius	    "Reserved",
224290001Sglebius	    "LoaderCode",
225290001Sglebius	    "LoaderData",
226290001Sglebius	    "BootServicesCode",
227290001Sglebius	    "BootServicesData",
228290001Sglebius	    "RuntimeServicesCode",
229290001Sglebius	    "RuntimeServicesData",
230290001Sglebius	    "ConventionalMemory",
231290001Sglebius	    "UnusableMemory",
232290001Sglebius	    "ACPIReclaimMemory",
233290001Sglebius	    "ACPIMemoryNVS",
234290001Sglebius	    "MemoryMappedIO",
235290001Sglebius	    "MemoryMappedIOPortSpace",
236290001Sglebius	    "PalCode"
237290001Sglebius	};
238290001Sglebius
239290001Sglebius	sz = 0;
240290001Sglebius	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
241290001Sglebius	if (status != EFI_BUFFER_TOO_SMALL) {
242290001Sglebius		printf("Can't determine memory map size\n");
243290001Sglebius		return CMD_ERROR;
244290001Sglebius	}
245290001Sglebius	map = malloc(sz);
246290001Sglebius	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
247290001Sglebius	if (EFI_ERROR(status)) {
248290001Sglebius		printf("Can't read memory map\n");
249290001Sglebius		return CMD_ERROR;
250290001Sglebius	}
251290001Sglebius
252290001Sglebius	ndesc = sz / dsz;
253290001Sglebius	printf("%23s %12s %12s %8s %4s\n",
254290001Sglebius	       "Type", "Physical", "Virtual", "#Pages", "Attr");
255290001Sglebius
256290001Sglebius	for (i = 0, p = map; i < ndesc;
257290001Sglebius	     i++, p = NextMemoryDescriptor(p, dsz)) {
258290001Sglebius	    printf("%23s %012lx %012lx %08lx ",
259290001Sglebius		   types[p->Type],
260290001Sglebius		   p->PhysicalStart,
261290001Sglebius		   p->VirtualStart,
262290001Sglebius		   p->NumberOfPages);
263290001Sglebius	    if (p->Attribute & EFI_MEMORY_UC)
264290001Sglebius		printf("UC ");
265290001Sglebius	    if (p->Attribute & EFI_MEMORY_WC)
266290001Sglebius		printf("WC ");
267290001Sglebius	    if (p->Attribute & EFI_MEMORY_WT)
268290001Sglebius		printf("WT ");
269290001Sglebius	    if (p->Attribute & EFI_MEMORY_WB)
270290001Sglebius		printf("WB ");
271290001Sglebius	    if (p->Attribute & EFI_MEMORY_UCE)
272290001Sglebius		printf("UCE ");
273290001Sglebius	    if (p->Attribute & EFI_MEMORY_WP)
274290001Sglebius		printf("WP ");
275290001Sglebius	    if (p->Attribute & EFI_MEMORY_RP)
276290001Sglebius		printf("RP ");
277290001Sglebius	    if (p->Attribute & EFI_MEMORY_XP)
278290001Sglebius		printf("XP ");
279290001Sglebius	    if (p->Attribute & EFI_MEMORY_RUNTIME)
280290001Sglebius		printf("RUNTIME");
281290001Sglebius	    printf("\n");
282290001Sglebius	}
283290001Sglebius
284290001Sglebius	return CMD_OK;
285290001Sglebius}
286290001Sglebius
287290001SglebiusCOMMAND_SET(configuration, "configuration",
288290001Sglebius	    "print configuration tables", command_configuration);
289290001Sglebius
290290001Sglebiusstatic int
291290001Sglebiuscommand_configuration(int argc, char *argv[])
292290001Sglebius{
293290001Sglebius	int i;
294290001Sglebius
295290001Sglebius	printf("NumberOfTableEntries=%d\n", ST->NumberOfTableEntries);
296290001Sglebius	for (i = 0; i < ST->NumberOfTableEntries; i++) {
297290001Sglebius		static EFI_GUID mps = MPS_TABLE_GUID;
298290001Sglebius		static EFI_GUID acpi = ACPI_TABLE_GUID;
299290001Sglebius		static EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
300290001Sglebius		static EFI_GUID smbios = SMBIOS_TABLE_GUID;
301290001Sglebius		static EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
302
303		printf("  ");
304		if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
305			    &mps, sizeof(EFI_GUID)))
306			printf("MPS Table");
307		else if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
308				 &acpi, sizeof(EFI_GUID)))
309			printf("ACPI Table");
310		else if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
311				 &acpi20, sizeof(EFI_GUID)))
312			printf("ACPI 2.0 Table");
313		else if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
314				 &smbios, sizeof(EFI_GUID)))
315			printf("SMBIOS Table");
316		else if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
317				 &sal, sizeof(EFI_GUID)))
318			printf("SAL System Table");
319		else
320			printf("Unknown Table");
321		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
322	}
323
324	return CMD_OK;
325}
326
327COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
328
329static int
330command_sal(int argc, char *argv[])
331{
332	int i;
333	struct sal_system_table *saltab = 0;
334	static int sizes[6] = {
335		48, 32, 16, 32, 16, 16
336	};
337	u_int8_t *p;
338
339	for (i = 0; i < ST->NumberOfTableEntries; i++) {
340		static EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
341		if (!memcmp(&ST->ConfigurationTable[i].VendorGuid,
342				 &sal, sizeof(EFI_GUID)))
343			saltab = ST->ConfigurationTable[i].VendorTable;
344	}
345
346	if (!saltab) {
347		printf("Can't find SAL System Table\n");
348		return CMD_ERROR;
349	}
350
351	if (memcmp(saltab->sal_signature, "SST_", 4)) {
352		printf("Bad signature for SAL System Table\n");
353		return CMD_ERROR;
354	}
355
356	printf("SAL Revision %x.%02x\n",
357	       saltab->sal_rev[1],
358	       saltab->sal_rev[0]);
359	printf("SAL A Version %x.%02x\n",
360	       saltab->sal_a_version[1],
361	       saltab->sal_a_version[0]);
362	printf("SAL B Version %x.%02x\n",
363	       saltab->sal_b_version[1],
364	       saltab->sal_b_version[0]);
365
366	p = (u_int8_t *) (saltab + 1);
367	for (i = 0; i < saltab->sal_entry_count; i++) {
368		printf("  Desc %d", *p);
369		if (*p == 0) {
370			struct sal_entrypoint_descriptor *dp;
371			dp = (struct sal_entrypoint_descriptor *) p;
372			printf("\n");
373			printf("    PAL Proc at 0x%lx\n",
374			       dp->sale_pal_proc);
375			printf("    SAL Proc at 0x%lx\n",
376			       dp->sale_sal_proc);
377			printf("    SAL GP at 0x%lx\n",
378			       dp->sale_sal_gp);
379		} else if (*p == 1) {
380			struct sal_memory_descriptor *dp;
381			dp = (struct sal_memory_descriptor *) p;
382			printf(" Type %d.%d, ",
383			       dp->sale_memory_type[0],
384			       dp->sale_memory_type[1]);
385			printf("Address 0x%lx, ",
386			       dp->sale_physical_address);
387			printf("Length 0x%x\n",
388			       dp->sale_length);
389		} else {
390			printf("\n");
391		}
392		p += sizes[*p];
393	}
394
395	return CMD_OK;
396}
397
398int
399print_trs(int type)
400{
401	struct ia64_pal_result	res;
402	int			i, maxtr;
403	struct {
404		struct ia64_pte	pte;
405		struct ia64_itir itir;
406		struct ia64_ifa ifa;
407		struct ia64_rr	rr;
408	}			buf;
409	static const char*	psnames[] = {
410		"1B",	"2B",	"4B",	"8B",
411		"16B",	"32B",	"64B",	"128B",
412		"256B",	"512B",	"1K",	"2K",
413		"4K",	"8K",	"16K",	"32K",
414		"64K",	"128K",	"256K",	"512K",
415		"1M",	"2M",	"4M",	"8M",
416		"16M",	"32M",	"64M",	"128M",
417		"256M",	"512M",	"1G",	"2G"
418	};
419	static const char*	manames[] = {
420		"WB",	"bad",	"bad",	"bad",
421		"UC",	"UCE",	"WC",	"NaT",
422
423	};
424
425	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
426	if (res.pal_status != 0) {
427		printf("Can't get VM summary\n");
428		return CMD_ERROR;
429	}
430
431	if (type == 0)
432		maxtr = (res.pal_result[0] >> 40) & 0xff;
433	else
434		maxtr = (res.pal_result[0] >> 32) & 0xff;
435
436	pager_open();
437	pager_output("V RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
438	for (i = 0; i <= maxtr; i++) {
439		char lbuf[128];
440
441		bzero(&buf, sizeof(buf));
442		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
443					    (u_int64_t) &buf);
444		if (!(res.pal_result[0] & 1))
445			buf.pte.pte_ar = 0;
446		if (!(res.pal_result[0] & 2))
447			buf.pte.pte_pl = 0;
448		if (!(res.pal_result[0] & 4))
449			buf.pte.pte_d = 0;
450		if (!(res.pal_result[0] & 8))
451			buf.pte.pte_ma = 0;
452		sprintf(lbuf,
453			"%d %06x %013x %013x %4s %d  %d  %d  %d %d %-3s %d %06x\n",
454			buf.ifa.ifa_ig & 1,
455			buf.rr.rr_rid,
456			buf.ifa.ifa_vpn,
457			buf.pte.pte_ppn,
458			psnames[buf.itir.itir_ps],
459			buf.pte.pte_ed,
460			buf.pte.pte_ar,
461			buf.pte.pte_pl,
462			buf.pte.pte_d,
463			buf.pte.pte_a,
464			manames[buf.pte.pte_ma],
465			buf.pte.pte_p,
466			buf.itir.itir_key);
467		pager_output(lbuf);
468	}
469	pager_close();
470
471	return CMD_OK;
472}
473
474COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
475
476static int
477command_itr(int argc, char *argv[])
478{
479	return print_trs(0);
480}
481
482COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
483
484static int
485command_dtr(int argc, char *argv[])
486{
487	return print_trs(1);
488}
489
490