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, &currdev.d_unit);
183	currdev.d_type = currdev.d_dev->dv_type;
184
185	env_setenv("loaddev", EV_VOLATILE, ia64_fmtdev(&currdev), env_noset,
186	    env_nounset);
187
188	dev = get_dev_option(argc, argv);
189	if (dev == NULL)
190		dev = ia64_fmtdev(&currdev);
191
192	env_setenv("currdev", EV_VOLATILE, dev, ia64_setcurrdev, env_nounset);
193
194	setenv("LINES", "24", 1);	/* optional */
195
196	archsw.arch_autoload = ia64_autoload;
197	archsw.arch_copyin = ia64_copyin;
198	archsw.arch_copyout = ia64_copyout;
199	archsw.arch_getdev = ia64_getdev;
200	archsw.arch_loadaddr = ia64_loadaddr;
201	archsw.arch_loadseg = ia64_loadseg;
202	archsw.arch_readin = ia64_readin;
203
204	interact();			/* doesn't return */
205
206	return (EFI_SUCCESS);		/* keep compiler happy */
207}
208
209COMMAND_SET(quit, "quit", "exit the loader", command_quit);
210
211static int
212command_quit(int argc, char *argv[])
213{
214	exit(0);
215	/* NOTREACHED */
216	return (CMD_OK);
217}
218
219COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
220
221static int
222command_reboot(int argc, char *argv[])
223{
224
225	RS->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
226	/* NOTREACHED */
227	return (CMD_OK);
228}
229
230COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
231
232static int
233command_memmap(int argc, char *argv[])
234{
235	UINTN sz;
236	EFI_MEMORY_DESCRIPTOR *map, *p;
237	UINTN key, dsz;
238	UINT32 dver;
239	EFI_STATUS status;
240	int i, ndesc;
241	static char *types[] = {
242	    "Reserved",
243	    "LoaderCode",
244	    "LoaderData",
245	    "BootServicesCode",
246	    "BootServicesData",
247	    "RuntimeServicesCode",
248	    "RuntimeServicesData",
249	    "ConventionalMemory",
250	    "UnusableMemory",
251	    "ACPIReclaimMemory",
252	    "ACPIMemoryNVS",
253	    "MemoryMappedIO",
254	    "MemoryMappedIOPortSpace",
255	    "PalCode"
256	};
257
258	sz = 0;
259	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
260	if (status != EFI_BUFFER_TOO_SMALL) {
261		printf("Can't determine memory map size\n");
262		return CMD_ERROR;
263	}
264	map = malloc(sz);
265	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
266	if (EFI_ERROR(status)) {
267		printf("Can't read memory map\n");
268		return CMD_ERROR;
269	}
270
271	ndesc = sz / dsz;
272	printf("%23s %12s %12s %8s %4s\n",
273	       "Type", "Physical", "Virtual", "#Pages", "Attr");
274
275	for (i = 0, p = map; i < ndesc;
276	     i++, p = NextMemoryDescriptor(p, dsz)) {
277	    printf("%23s %012lx %012lx %08lx ",
278		   types[p->Type],
279		   p->PhysicalStart,
280		   p->VirtualStart,
281		   p->NumberOfPages);
282	    if (p->Attribute & EFI_MEMORY_UC)
283		printf("UC ");
284	    if (p->Attribute & EFI_MEMORY_WC)
285		printf("WC ");
286	    if (p->Attribute & EFI_MEMORY_WT)
287		printf("WT ");
288	    if (p->Attribute & EFI_MEMORY_WB)
289		printf("WB ");
290	    if (p->Attribute & EFI_MEMORY_UCE)
291		printf("UCE ");
292	    if (p->Attribute & EFI_MEMORY_WP)
293		printf("WP ");
294	    if (p->Attribute & EFI_MEMORY_RP)
295		printf("RP ");
296	    if (p->Attribute & EFI_MEMORY_XP)
297		printf("XP ");
298	    if (p->Attribute & EFI_MEMORY_RUNTIME)
299		printf("RUNTIME");
300	    printf("\n");
301	}
302
303	return CMD_OK;
304}
305
306COMMAND_SET(configuration, "configuration",
307	    "print configuration tables", command_configuration);
308
309static const char *
310guid_to_string(EFI_GUID *guid)
311{
312	static char buf[40];
313
314	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
315	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
316	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
317	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
318	return (buf);
319}
320
321static int
322command_configuration(int argc, char *argv[])
323{
324	int i;
325
326	printf("NumberOfTableEntries=%ld\n", ST->NumberOfTableEntries);
327	for (i = 0; i < ST->NumberOfTableEntries; i++) {
328		EFI_GUID *guid;
329
330		printf("  ");
331		guid = &ST->ConfigurationTable[i].VendorGuid;
332		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
333			printf("MPS Table");
334		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
335			printf("ACPI Table");
336		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
337			printf("ACPI 2.0 Table");
338		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
339			printf("SMBIOS Table");
340		else if (!memcmp(guid, &sal, sizeof(EFI_GUID)))
341			printf("SAL System Table");
342		else if (!memcmp(guid, &hcdp, sizeof(EFI_GUID)))
343			printf("DIG64 HCDP Table");
344		else
345			printf("Unknown Table (%s)", guid_to_string(guid));
346		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
347	}
348
349	return CMD_OK;
350}
351
352COMMAND_SET(sal, "sal", "print SAL System Table", command_sal);
353
354static int
355command_sal(int argc, char *argv[])
356{
357	int i;
358	struct sal_system_table *saltab = 0;
359	static int sizes[6] = {
360		48, 32, 16, 32, 16, 16
361	};
362	u_int8_t *p;
363
364	saltab = efi_get_table(&sal);
365	if (saltab == NULL) {
366		printf("Can't find SAL System Table\n");
367		return CMD_ERROR;
368	}
369
370	if (memcmp(saltab->sal_signature, "SST_", 4)) {
371		printf("Bad signature for SAL System Table\n");
372		return CMD_ERROR;
373	}
374
375	printf("SAL Revision %x.%02x\n",
376	       saltab->sal_rev[1],
377	       saltab->sal_rev[0]);
378	printf("SAL A Version %x.%02x\n",
379	       saltab->sal_a_version[1],
380	       saltab->sal_a_version[0]);
381	printf("SAL B Version %x.%02x\n",
382	       saltab->sal_b_version[1],
383	       saltab->sal_b_version[0]);
384
385	p = (u_int8_t *) (saltab + 1);
386	for (i = 0; i < saltab->sal_entry_count; i++) {
387		printf("  Desc %d", *p);
388		if (*p == 0) {
389			struct sal_entrypoint_descriptor *dp;
390			dp = (struct sal_entrypoint_descriptor *) p;
391			printf("\n");
392			printf("    PAL Proc at 0x%lx\n",
393			       dp->sale_pal_proc);
394			printf("    SAL Proc at 0x%lx\n",
395			       dp->sale_sal_proc);
396			printf("    SAL GP at 0x%lx\n",
397			       dp->sale_sal_gp);
398		} else if (*p == 1) {
399			struct sal_memory_descriptor *dp;
400			dp = (struct sal_memory_descriptor *) p;
401			printf(" Type %d.%d, ",
402			       dp->sale_memory_type[0],
403			       dp->sale_memory_type[1]);
404			printf("Address 0x%lx, ",
405			       dp->sale_physical_address);
406			printf("Length 0x%x\n",
407			       dp->sale_length);
408		} else if (*p == 5) {
409			struct sal_ap_wakeup_descriptor *dp;
410			dp = (struct sal_ap_wakeup_descriptor *) p;
411			printf("\n");
412			printf("    Mechanism %d\n", dp->sale_mechanism);
413			printf("    Vector 0x%lx\n", dp->sale_vector);
414		} else
415			printf("\n");
416
417		p += sizes[*p];
418	}
419
420	return CMD_OK;
421}
422
423int
424print_trs(int type)
425{
426	struct ia64_pal_result res;
427	int i, maxtr;
428	struct {
429		pt_entry_t	pte;
430		uint64_t	itir;
431		uint64_t	ifa;
432		struct ia64_rr	rr;
433	} buf;
434	static const char *psnames[] = {
435		"1B",	"2B",	"4B",	"8B",
436		"16B",	"32B",	"64B",	"128B",
437		"256B",	"512B",	"1K",	"2K",
438		"4K",	"8K",	"16K",	"32K",
439		"64K",	"128K",	"256K",	"512K",
440		"1M",	"2M",	"4M",	"8M",
441		"16M",	"32M",	"64M",	"128M",
442		"256M",	"512M",	"1G",	"2G"
443	};
444	static const char *manames[] = {
445		"WB",	"bad",	"bad",	"bad",
446		"UC",	"UCE",	"WC",	"NaT",
447	};
448
449	res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
450	if (res.pal_status != 0) {
451		printf("Can't get VM summary\n");
452		return CMD_ERROR;
453	}
454
455	if (type == 0)
456		maxtr = (res.pal_result[0] >> 40) & 0xff;
457	else
458		maxtr = (res.pal_result[0] >> 32) & 0xff;
459
460	printf("%d translation registers\n", maxtr);
461
462	pager_open();
463	pager_output("TR# RID    Virtual Page  Physical Page PgSz ED AR PL D A MA  P KEY\n");
464	for (i = 0; i <= maxtr; i++) {
465		char lbuf[128];
466
467		bzero(&buf, sizeof(buf));
468		res = ia64_call_pal_stacked(PAL_VM_TR_READ, i, type,
469					    (u_int64_t) &buf);
470		if (res.pal_status != 0)
471			break;
472
473		/* Only display valid translations */
474		if ((buf.ifa & 1) == 0)
475			continue;
476
477		if (!(res.pal_result[0] & 1))
478			buf.pte &= ~PTE_AR_MASK;
479		if (!(res.pal_result[0] & 2))
480			buf.pte &= ~PTE_PL_MASK;
481		if (!(res.pal_result[0] & 4))
482			buf.pte &= ~PTE_DIRTY;
483		if (!(res.pal_result[0] & 8))
484			buf.pte &= ~PTE_MA_MASK;
485		sprintf(lbuf, "%03d %06x %013lx %013lx %4s %d  %d  %d  %d %d "
486		    "%-3s %d %06x\n", i, buf.rr.rr_rid, buf.ifa >> 12,
487		    (buf.pte & PTE_PPN_MASK) >> 12,
488		    psnames[(buf.itir & ITIR_PS_MASK) >> 2],
489		    (buf.pte & PTE_ED) ? 1 : 0,
490		    (int)(buf.pte & PTE_AR_MASK) >> 9,
491		    (int)(buf.pte & PTE_PL_MASK) >> 7,
492		    (buf.pte & PTE_DIRTY) ? 1 : 0,
493		    (buf.pte & PTE_ACCESSED) ? 1 : 0,
494		    manames[(buf.pte & PTE_MA_MASK) >> 2],
495		    (buf.pte & PTE_PRESENT) ? 1 : 0,
496		    (int)((buf.itir & ITIR_KEY_MASK) >> 8));
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
524COMMAND_SET(hcdp, "hcdp", "Dump HCDP info", command_hcdp);
525
526static char *
527hcdp_string(char *s, u_int len)
528{
529	static char buffer[256];
530
531	memcpy(buffer, s, len);
532	buffer[len] = 0;
533	return (buffer);
534}
535
536static int
537command_hcdp(int argc, char *argv[])
538{
539	struct dig64_hcdp_table *tbl;
540	struct dig64_hcdp_entry *ent;
541	struct dig64_gas *gas;
542	int i;
543
544	tbl = efi_get_table(&hcdp);
545	if (tbl == NULL) {
546		printf("No HCDP table present\n");
547		return (CMD_OK);
548	}
549	if (memcmp(tbl->signature, HCDP_SIGNATURE, sizeof(tbl->signature))) {
550		printf("HCDP table has invalid signature\n");
551		return (CMD_OK);
552	}
553	if (tbl->length < sizeof(*tbl) - sizeof(*tbl->entry)) {
554		printf("HCDP table too short\n");
555		return (CMD_OK);
556	}
557	printf("HCDP table at 0x%016lx\n", (u_long)tbl);
558	printf("Signature  = %s\n", hcdp_string(tbl->signature, 4));
559	printf("Length     = %u\n", tbl->length);
560	printf("Revision   = %u\n", tbl->revision);
561	printf("Checksum   = %u\n", tbl->checksum);
562	printf("OEM Id     = %s\n", hcdp_string(tbl->oem_id, 6));
563	printf("Table Id   = %s\n", hcdp_string(tbl->oem_tbl_id, 8));
564	printf("OEM rev    = %u\n", tbl->oem_rev);
565	printf("Creator Id = %s\n", hcdp_string(tbl->creator_id, 4));
566	printf("Creator rev= %u\n", tbl->creator_rev);
567	printf("Entries    = %u\n", tbl->entries);
568	for (i = 0; i < tbl->entries; i++) {
569		ent = tbl->entry + i;
570		printf("Entry #%d:\n", i + 1);
571		printf("    Type      = %u\n", ent->type);
572		printf("    Databits  = %u\n", ent->databits);
573		printf("    Parity    = %u\n", ent->parity);
574		printf("    Stopbits  = %u\n", ent->stopbits);
575		printf("    PCI seg   = %u\n", ent->pci_segment);
576		printf("    PCI bus   = %u\n", ent->pci_bus);
577		printf("    PCI dev   = %u\n", ent->pci_device);
578		printf("    PCI func  = %u\n", ent->pci_function);
579		printf("    Interrupt = %u\n", ent->interrupt);
580		printf("    PCI flag  = %u\n", ent->pci_flag);
581		printf("    Baudrate  = %lu\n",
582		    ((u_long)ent->baud_high << 32) + (u_long)ent->baud_low);
583		gas = &ent->address;
584		printf("    Addr space= %u\n", gas->addr_space);
585		printf("    Bit width = %u\n", gas->bit_width);
586		printf("    Bit offset= %u\n", gas->bit_offset);
587		printf("    Address   = 0x%016lx\n",
588		    ((u_long)gas->addr_high << 32) + (u_long)gas->addr_low);
589		printf("    PCI type  = %u\n", ent->pci_devid);
590		printf("    PCI vndr  = %u\n", ent->pci_vendor);
591		printf("    IRQ       = %u\n", ent->irq);
592		printf("    PClock    = %u\n", ent->pclock);
593		printf("    PCI iface = %u\n", ent->pci_interface);
594	}
595	printf("<EOT>\n");
596	return (CMD_OK);
597}
598
599COMMAND_SET(about, "about", "about the loader", command_about);
600
601extern uint64_t _start_plabel[];
602
603static int
604command_about(int argc, char *argv[])
605{
606	EFI_LOADED_IMAGE *img;
607
608	printf("%s\n", bootprog_name);
609	printf("revision %s\n", bootprog_rev);
610	printf("built by %s\n", bootprog_maker);
611	printf("built on %s\n", bootprog_date);
612
613	printf("\n");
614
615	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
616	printf("image loaded at %p\n", img->ImageBase);
617	printf("entry at %#lx (%#lx)\n", _start_plabel[0], _start_plabel[1]);
618}
619