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$");
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 arch_switch archsw;	/* MI/MD interface boundary */
54
55extern u_int64_t	ia64_pal_entry;
56
57EFI_GUID acpi = ACPI_TABLE_GUID;
58EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
59EFI_GUID devid = DEVICE_PATH_PROTOCOL;
60EFI_GUID hcdp = HCDP_TABLE_GUID;
61EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
62EFI_GUID mps = MPS_TABLE_GUID;
63EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
64EFI_GUID sal = SAL_SYSTEM_TABLE_GUID;
65EFI_GUID smbios = SMBIOS_TABLE_GUID;
66
67static void
68find_pal_proc(void)
69{
70	int i;
71	struct sal_system_table *saltab = 0;
72	static int sizes[6] = {
73		48, 32, 16, 32, 16, 16
74	};
75	u_int8_t *p;
76
77	saltab = efi_get_table(&sal);
78	if (saltab == NULL) {
79		printf("Can't find SAL System Table\n");
80		return;
81	}
82
83	if (memcmp(saltab->sal_signature, "SST_", 4)) {
84		printf("Bad signature for SAL System Table\n");
85		return;
86	}
87
88	p = (u_int8_t *) (saltab + 1);
89	for (i = 0; i < saltab->sal_entry_count; i++) {
90		if (*p == 0) {
91			struct sal_entrypoint_descriptor *dp;
92			dp = (struct sal_entrypoint_descriptor *) p;
93			ia64_pal_entry = dp->sale_pal_proc;
94			return;
95		}
96		p += sizes[*p];
97	}
98
99	printf("Can't find PAL proc\n");
100	return;
101}
102
103static int
104usc2cmp(CHAR16 *s1, CHAR16 *s2)
105{
106
107	while (*s1 == *s2++) {
108		if (*s1++ == 0)
109			return (0);
110	}
111	return (*s1 - *(s2 - 1));
112}
113
114static char *
115get_dev_option(int argc, CHAR16 *argv[])
116{
117	static char dev[32];
118	CHAR16 *arg;
119	char *devp;
120	int i, j;
121
122	devp = NULL;
123	for (i = 0; i < argc; i++) {
124		if (usc2cmp(argv[i], L"-dev") == 0 && i < argc - 1) {
125			arg = argv[i + 1];
126			j = 0;
127			while (j < sizeof(dev) && *arg != 0)
128				dev[j++] = *arg++;
129			if (j == sizeof(dev))
130				j--;
131			dev[j] = '\0';
132			devp = dev;
133			break;
134		}
135	}
136
137	return (devp);
138}
139
140EFI_STATUS
141main(int argc, CHAR16 *argv[])
142{
143	struct devdesc currdev;
144	EFI_LOADED_IMAGE *img;
145	char *dev;
146	int i;
147
148	/*
149	 * XXX Chicken-and-egg problem; we want to have console output
150	 * early, but some console attributes may depend on reading from
151	 * eg. the boot device, which we can't do yet.  We can use
152	 * printf() etc. once this is done.
153	 */
154	cons_probe();
155
156	printf("\n%s, Revision %s\n", bootprog_name, bootprog_rev);
157
158	find_pal_proc();
159
160	/*
161	 * March through the device switch probing for things.
162	 */
163	for (i = 0; devsw[i] != NULL; i++)
164		if (devsw[i]->dv_init != NULL)
165			(devsw[i]->dv_init)();
166
167	/*
168	 * Disable the watchdog timer. By default the boot manager sets
169	 * the timer to 5 minutes before invoking a boot option. If we
170	 * want to return to the boot manager, we have to disable the
171	 * watchdog timer and since we're an interactive program, we don't
172	 * want to wait until the user types "quit". The timer may have
173	 * fired by then. We don't care if this fails. It does not prevent
174	 * normal functioning in any way...
175	 */
176	BS->SetWatchdogTimer(0, 0, 0, NULL);
177
178	/* Get our loaded image protocol interface structure. */
179	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
180
181	bzero(&currdev, sizeof(currdev));
182	efi_handle_lookup(img->DeviceHandle, &currdev.d_dev,
183	    &currdev.d_unit, NULL);
184	currdev.d_type = currdev.d_dev->dv_type;
185
186	env_setenv("loaddev", EV_VOLATILE, ia64_fmtdev(&currdev), env_noset,
187	    env_nounset);
188
189	dev = get_dev_option(argc, argv);
190	if (dev == NULL)
191		dev = ia64_fmtdev(&currdev);
192
193	env_setenv("currdev", EV_VOLATILE, dev, ia64_setcurrdev, env_nounset);
194
195	setenv("LINES", "24", 1);	/* optional */
196
197	archsw.arch_autoload = ia64_autoload;
198	archsw.arch_copyin = ia64_copyin;
199	archsw.arch_copyout = ia64_copyout;
200	archsw.arch_getdev = ia64_getdev;
201	archsw.arch_loadaddr = ia64_loadaddr;
202	archsw.arch_loadseg = ia64_loadseg;
203	archsw.arch_readin = ia64_readin;
204
205	interact();			/* doesn't return */
206
207	return (EFI_SUCCESS);		/* keep compiler happy */
208}
209
210COMMAND_SET(quit, "quit", "exit the loader", command_quit);
211
212static int
213command_quit(int argc, char *argv[])
214{
215	exit(0);
216	/* NOTREACHED */
217	return (CMD_OK);
218}
219
220COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
221
222static int
223command_reboot(int argc, char *argv[])
224{
225
226	RS->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
227	/* NOTREACHED */
228	return (CMD_OK);
229}
230
231COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
232
233static int
234command_memmap(int argc, char *argv[])
235{
236	UINTN sz;
237	EFI_MEMORY_DESCRIPTOR *map, *p;
238	UINTN key, dsz;
239	UINT32 dver;
240	EFI_STATUS status;
241	int i, ndesc;
242	static char *types[] = {
243	    "Reserved",
244	    "LoaderCode",
245	    "LoaderData",
246	    "BootServicesCode",
247	    "BootServicesData",
248	    "RuntimeServicesCode",
249	    "RuntimeServicesData",
250	    "ConventionalMemory",
251	    "UnusableMemory",
252	    "ACPIReclaimMemory",
253	    "ACPIMemoryNVS",
254	    "MemoryMappedIO",
255	    "MemoryMappedIOPortSpace",
256	    "PalCode"
257	};
258
259	sz = 0;
260	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
261	if (status != EFI_BUFFER_TOO_SMALL) {
262		printf("Can't determine memory map size\n");
263		return CMD_ERROR;
264	}
265	map = malloc(sz);
266	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
267	if (EFI_ERROR(status)) {
268		printf("Can't read memory map\n");
269		return CMD_ERROR;
270	}
271
272	ndesc = sz / dsz;
273	printf("%23s %12s %12s %8s %4s\n",
274	       "Type", "Physical", "Virtual", "#Pages", "Attr");
275
276	for (i = 0, p = map; i < ndesc;
277	     i++, p = NextMemoryDescriptor(p, dsz)) {
278	    printf("%23s %012lx %012lx %08lx ",
279		   types[p->Type],
280		   p->PhysicalStart,
281		   p->VirtualStart,
282		   p->NumberOfPages);
283	    if (p->Attribute & EFI_MEMORY_UC)
284		printf("UC ");
285	    if (p->Attribute & EFI_MEMORY_WC)
286		printf("WC ");
287	    if (p->Attribute & EFI_MEMORY_WT)
288		printf("WT ");
289	    if (p->Attribute & EFI_MEMORY_WB)
290		printf("WB ");
291	    if (p->Attribute & EFI_MEMORY_UCE)
292		printf("UCE ");
293	    if (p->Attribute & EFI_MEMORY_WP)
294		printf("WP ");
295	    if (p->Attribute & EFI_MEMORY_RP)
296		printf("RP ");
297	    if (p->Attribute & EFI_MEMORY_XP)
298		printf("XP ");
299	    if (p->Attribute & EFI_MEMORY_RUNTIME)
300		printf("RUNTIME");
301	    printf("\n");
302	}
303
304	return CMD_OK;
305}
306
307COMMAND_SET(configuration, "configuration",
308	    "print configuration tables", command_configuration);
309
310static const char *
311guid_to_string(EFI_GUID *guid)
312{
313	static char buf[40];
314
315	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
316	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
317	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
318	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
319	return (buf);
320}
321
322static int
323command_configuration(int argc, char *argv[])
324{
325	int i;
326
327	printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
328	for (i = 0; i < ST->NumberOfTableEntries; i++) {
329		EFI_GUID *guid;
330
331		printf("  ");
332		guid = &ST->ConfigurationTable[i].VendorGuid;
333		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
334			printf("MPS Table");
335		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
336			printf("ACPI Table");
337		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
338			printf("ACPI 2.0 Table");
339		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
340			printf("SMBIOS Table");
341		else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
342			printf("SAL System Table");
343		else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
344			printf("DIG64 HCDP Table");
345		else
346			printf("Unknown Table (%s)", guid_to_string(guid));
347		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
348	}
349
350	return CMD_OK;
351}
352
353COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
354
355static int
356command_sal(int argc, char *argv[])
357{
358	int i;
359	struct sal_system_table *saltab = 0;
360	static int sizes[6] = {
361		48, 32, 16, 32, 16, 16
362	};
363	u_int8_t *p;
364
365	saltab = efi_get_table(&sal);
366	if (saltab == NULL) {
367		printf("Can't find SAL System Table\n");
368		return CMD_ERROR;
369	}
370
371	if (memcmp(saltab->sal_signature, "SST_", 4)) {
372		printf("Bad signature for SAL System Table\n");
373		return CMD_ERROR;
374	}
375
376	printf("SAL Revision %x.%02x\n",
377	       saltab->sal_rev[1],
378	       saltab->sal_rev[0]);
379	printf("SAL A Version %x.%02x\n",
380	       saltab->sal_a_version[1],
381	       saltab->sal_a_version[0]);
382	printf("SAL B Version %x.%02x\n",
383	       saltab->sal_b_version[1],
384	       saltab->sal_b_version[0]);
385
386	p = (u_int8_t *) (saltab + 1);
387	for (i = 0; i < saltab->sal_entry_count; i++) {
388		printf("  Desc %d", *p);
389		if (*p == 0) {
390			struct sal_entrypoint_descriptor *dp;
391			dp = (struct sal_entrypoint_descriptor *) p;
392			printf("\n");
393			printf("    PAL Proc at 0x%lx\n",
394			       dp->sale_pal_proc);
395			printf("    SAL Proc at 0x%lx\n",
396			       dp->sale_sal_proc);
397			printf("    SAL GP at 0x%lx\n",
398			       dp->sale_sal_gp);
399		} else if (*p == 1) {
400			struct sal_memory_descriptor *dp;
401			dp = (struct sal_memory_descriptor *) p;
402			printf(" Type %d.%d, ",
403			       dp->sale_memory_type[0],
404			       dp->sale_memory_type[1]);
405			printf("Address 0x%lx, ",
406			       dp->sale_physical_address);
407			printf("Length 0x%x\n",
408			       dp->sale_length);
409		} else if (*p == 5) {
410			struct sal_ap_wakeup_descriptor *dp;
411			dp = (struct sal_ap_wakeup_descriptor *) p;
412			printf("\n");
413			printf("    Mechanism %d\n", dp->sale_mechanism);
414			printf("    Vector 0x%lx\n", dp->sale_vector);
415		} else
416			printf("\n");
417
418		p += sizes[*p];
419	}
420
421	return CMD_OK;
422}
423
424int
425print_trs(int type)
426{
427	struct ia64_pal_result res;
428	int i, maxtr;
429	struct {
430		pt_entry_t	pte;
431		uint64_t	itir;
432		uint64_t	ifa;
433		struct ia64_rr	rr;
434	} buf;
435	static const char *psnames[] = {
436		"1B",	"2B",	"4B",	"8B",
437		"16B",	"32B",	"64B",	"128B",
438		"256B",	"512B",	"1K",	"2K",
439		"4K",	"8K",	"16K",	"32K",
440		"64K",	"128K",	"256K",	"512K",
441		"1M",	"2M",	"4M",	"8M",
442		"16M",	"32M",	"64M",	"128M",
443		"256M",	"512M",	"1G",	"2G"
444	};
445	static const char *manames[] = {
446		"WB",	"bad",	"bad",	"bad",
447		"UC",	"UCE",	"WC",	"NaT",
448	};
449
450	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
451	if (res.pal_status != 0) {
452		printf("Can't get VM summary\n");
453		return CMD_ERROR;
454	}
455
456	if (type == 0)
457		maxtr = (res.pal_result[0] >> 40) & 0xff;
458	else
459		maxtr = (res.pal_result[0] >> 32) & 0xff;
460
461	printf("%d translation registers\n", maxtr);
462
463	pager_open();
464	pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
465	for (i = 0; i <= maxtr; i++) {
466		char lbuf[128];
467
468		bzero(&buf, sizeof(buf));
469		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
470					    (u_int64_t) &buf);
471		if (res.pal_status != 0)
472			break;
473
474		/* Only display valid translations */
475		if ((buf.ifa & 1) == 0)
476			continue;
477
478		if (!(res.pal_result[0] & 1))
479			buf.pte &= ~PTE_AR_MASK;
480		if (!(res.pal_result[0] & 2))
481			buf.pte &= ~PTE_PL_MASK;
482		if (!(res.pal_result[0] & 4))
483			buf.pte &= ~PTE_DIRTY;
484		if (!(res.pal_result[0] & 8))
485			buf.pte &= ~PTE_MA_MASK;
486		sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d "
487		    "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12,
488		    (buf.pte & PTE_PPN_MASK) >> 12,
489		    psnames[(buf.itir & ITIR_PS_MASK) >> 2],
490		    (buf.pte & PTE_ED) ? 1 : 0,
491		    (int)(buf.pte & PTE_AR_MASK) >> 9,
492		    (int)(buf.pte & PTE_PL_MASK) >> 7,
493		    (buf.pte & PTE_DIRTY) ? 1 : 0,
494		    (buf.pte & PTE_ACCESSED) ? 1 : 0,
495		    manames[(buf.pte & PTE_MA_MASK) >> 2],
496		    (buf.pte & PTE_PRESENT) ? 1 : 0,
497		    (int)((buf.itir & ITIR_KEY_MASK) >> 8));
498		pager_output(lbuf);
499	}
500	pager_close();
501
502	if (res.pal_status != 0) {
503		printf("Error while getting TR contents\n");
504		return CMD_ERROR;
505	}
506	return CMD_OK;
507}
508
509COMMAND_SET(itr, "itr", "print instruction TRs", command_itr);
510
511static int
512command_itr(int argc, char *argv[])
513{
514	return print_trs(0);
515}
516
517COMMAND_SET(dtr, "dtr", "print data TRs", command_dtr);
518
519static int
520command_dtr(int argc, char *argv[])
521{
522	return print_trs(1);
523}
524
525COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
526
527static char *
528hcdp_string(char *s, u_int len)
529{
530	static char buffer[256];
531
532	memcpy(buffer, s, len);
533	buffer[len] = 0;
534	return (buffer);
535}
536
537static int
538command_hcdp(int argc, char *argv[])
539{
540	struct dig64_hcdp_table *tbl;
541	struct dig64_hcdp_entry *ent;
542	struct dig64_gas *gas;
543	int i;
544
545	tbl = efi_get_table(&hcdp);
546	if (tbl == NULL) {
547		printf("No HCDP table present\n");
548		return (CMD_OK);
549	}
550	if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
551		printf("HCDP table has invalid signature\n");
552		return (CMD_OK);
553	}
554	if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) {
555		printf("HCDP table too short\n");
556		return (CMD_OK);
557	}
558	printf("HCDP table at 0x%016lx\n", (u_long)tbl);
559	printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
560	printf("Length     = %u\n", tbl->length);
561	printf("Revision   = %u\n", tbl->revision);
562	printf("Checksum   = %u\n", tbl->checksum);
563	printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
564	printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
565	printf("OEM rev    = %u\n", tbl->oem_rev);
566	printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
567	printf("Creator rev= %u\n", tbl->creator_rev);
568	printf("Entries    = %u\n", tbl->entries);
569	for (i = 0; i < tbl->entries; i++) {
570		ent = tbl->entry + i;
571		printf("Entry #%d:\n", i + 1);
572		printf("    Type      = %u\n", ent->type);
573		printf("    Databits  = %u\n", ent->databits);
574		printf("    Parity    = %u\n", ent->parity);
575		printf("    Stopbits  = %u\n", ent->stopbits);
576		printf("    PCI seg   = %u\n", ent->pci_segment);
577		printf("    PCI bus   = %u\n", ent->pci_bus);
578		printf("    PCI dev   = %u\n", ent->pci_device);
579		printf("    PCI func  = %u\n", ent->pci_function);
580		printf("    Interrupt = %u\n", ent->interrupt);
581		printf("    PCI flag  = %u\n", ent->pci_flag);
582		printf("    Baudrate  = %lu\n",
583		    ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low);
584		gas = &ent->address;
585		printf("    Addr space= %u\n", gas->addr_space);
586		printf("    Bit width = %u\n", gas->bit_width);
587		printf("    Bit offset= %u\n", gas->bit_offset);
588		printf("    Address   = 0x%016lx\n",
589		    ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low);
590		printf("    PCI type  = %u\n", ent->pci_devid);
591		printf("    PCI vndr  = %u\n", ent->pci_vendor);
592		printf("    IRQ       = %u\n", ent->irq);
593		printf("    PClock    = %u\n", ent->pclock);
594		printf("    PCI iface = %u\n", ent->pci_interface);
595	}
596	printf("<EOT>\n");
597	return (CMD_OK);
598}
599
600COMMAND_SET(about, "about", "about the loader", command_about);
601
602extern uint64_t _start_plabel[];
603
604static int
605command_about(int argc, char *argv[])
606{
607	EFI_LOADED_IMAGE *img;
608
609	printf("%s\n", bootprog_name);
610	printf("revision %s\n", bootprog_rev);
611	printf("built by %s\n", bootprog_maker);
612	printf("built on %s\n", bootprog_date);
613
614	printf("\n");
615
616	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
617	printf("image loaded at %p\n", img->ImageBase);
618	printf("entry at %#lx (%#lx)\n", _start_plabel[0], _start_plabel[1]);
619}
620