xref: /dflybsd-src/stand/boot/efi/loader/main.c (revision 34f16cb63a66b8f9628ff8a7eed4e9c5ccec9b45)
1479ab7f0SSascha Wildner /*-
2479ab7f0SSascha Wildner  * Copyright (c) 2008-2010 Rui Paulo
3479ab7f0SSascha Wildner  * Copyright (c) 2006 Marcel Moolenaar
4479ab7f0SSascha Wildner  * All rights reserved.
5479ab7f0SSascha Wildner  *
6479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
7479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
8479ab7f0SSascha Wildner  * are met:
9479ab7f0SSascha Wildner  *
10479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
11479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
12479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
13479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
14479ab7f0SSascha Wildner  *    documentation and/or other materials provided with the distribution.
15479ab7f0SSascha Wildner  *
16479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17479ab7f0SSascha Wildner  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18479ab7f0SSascha Wildner  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19479ab7f0SSascha Wildner  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20479ab7f0SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21479ab7f0SSascha Wildner  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22479ab7f0SSascha Wildner  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23479ab7f0SSascha Wildner  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24479ab7f0SSascha Wildner  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25479ab7f0SSascha Wildner  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26479ab7f0SSascha Wildner  *
27479ab7f0SSascha Wildner  * $FreeBSD: head/sys/boot/efi/loader/main.c 295408 2016-02-08 19:34:17Z imp $
28479ab7f0SSascha Wildner  */
29479ab7f0SSascha Wildner 
30479ab7f0SSascha Wildner #include <sys/param.h>
31479ab7f0SSascha Wildner #include <sys/reboot.h>
32479ab7f0SSascha Wildner #include <sys/boot.h>
33479ab7f0SSascha Wildner #include <stand.h>
34479ab7f0SSascha Wildner #include <string.h>
35479ab7f0SSascha Wildner #include <setjmp.h>
36479ab7f0SSascha Wildner 
37479ab7f0SSascha Wildner #include <efi.h>
38479ab7f0SSascha Wildner #include <efilib.h>
39479ab7f0SSascha Wildner 
40479ab7f0SSascha Wildner #include <uuid.h>
41479ab7f0SSascha Wildner 
42479ab7f0SSascha Wildner #include <bootstrap.h>
43479ab7f0SSascha Wildner #include <smbios.h>
44479ab7f0SSascha Wildner 
45479ab7f0SSascha Wildner #include "loader_efi.h"
46479ab7f0SSascha Wildner 
47479ab7f0SSascha Wildner extern char bootprog_name[];
48479ab7f0SSascha Wildner extern char bootprog_rev[];
49479ab7f0SSascha Wildner extern char bootprog_date[];
50479ab7f0SSascha Wildner extern char bootprog_maker[];
51479ab7f0SSascha Wildner 
52479ab7f0SSascha Wildner struct arch_switch archsw;	/* MI/MD interface boundary */
53479ab7f0SSascha Wildner 
54479ab7f0SSascha Wildner EFI_GUID acpi = ACPI_TABLE_GUID;
55479ab7f0SSascha Wildner EFI_GUID acpi20 = EFI_ACPI_TABLE_GUID;
56479ab7f0SSascha Wildner EFI_GUID devid = DEVICE_PATH_PROTOCOL;
57479ab7f0SSascha Wildner EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
58479ab7f0SSascha Wildner EFI_GUID mps = EFI_MPS_TABLE_GUID;
59479ab7f0SSascha Wildner EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
60479ab7f0SSascha Wildner EFI_GUID smbios = SMBIOS_TABLE_GUID;
61*34f16cb6SAaron LI EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
62479ab7f0SSascha Wildner EFI_GUID dxe = DXE_SERVICES_TABLE_GUID;
63479ab7f0SSascha Wildner EFI_GUID hoblist = HOB_LIST_GUID;
64479ab7f0SSascha Wildner EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
65479ab7f0SSascha Wildner EFI_GUID debugimg = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
66479ab7f0SSascha Wildner EFI_GUID fdtdtb = FDT_TABLE_GUID;
67479ab7f0SSascha Wildner EFI_GUID inputid = SIMPLE_INPUT_PROTOCOL;
68*34f16cb6SAaron LI EFI_GUID esrt = EFI_SYSTEM_RESOURCE_TABLE_GUID;
69*34f16cb6SAaron LI EFI_GUID lzmadecomp = LZMA_CUSTOM_DECOMPRESS_GUID;
70*34f16cb6SAaron LI EFI_GUID amiromlayout = AMI_ROM_LAYOUT_GUID;
71479ab7f0SSascha Wildner 
72479ab7f0SSascha Wildner /*
73479ab7f0SSascha Wildner  * Need this because EFI uses UTF-16 unicode string constants, but we
74e782c7f6SSascha Wildner  * use UTF-8. We can't use printf due to the possibility of \0 and we
75479ab7f0SSascha Wildner  * don't support support wide characters either.
76479ab7f0SSascha Wildner  */
77479ab7f0SSascha Wildner static void
print_str16(const CHAR16 * str)78479ab7f0SSascha Wildner print_str16(const CHAR16 *str)
79479ab7f0SSascha Wildner {
80479ab7f0SSascha Wildner 	int i;
81479ab7f0SSascha Wildner 
82479ab7f0SSascha Wildner 	for (i = 0; str[i]; i++)
83479ab7f0SSascha Wildner 		printf("%c", (char)str[i]);
84479ab7f0SSascha Wildner }
85479ab7f0SSascha Wildner 
86479ab7f0SSascha Wildner /*
87479ab7f0SSascha Wildner  * cpy8to16 copies a traditional C string into a CHAR16 string and
88479ab7f0SSascha Wildner  * 0 terminates it. len is the size of *dst in bytes.
89479ab7f0SSascha Wildner  */
90479ab7f0SSascha Wildner static void
cpy8to16(const char * src,CHAR16 * dst,size_t len)91479ab7f0SSascha Wildner cpy8to16(const char *src, CHAR16 *dst, size_t len)
92479ab7f0SSascha Wildner {
93479ab7f0SSascha Wildner 	len <<= 1;		/* Assume CHAR16 is 2 bytes */
94479ab7f0SSascha Wildner 	while (len > 0 && *src) {
95479ab7f0SSascha Wildner 		*dst++ = *src++;
96479ab7f0SSascha Wildner 		len--;
97479ab7f0SSascha Wildner 	}
98479ab7f0SSascha Wildner 	*dst++ = (CHAR16)0;
99479ab7f0SSascha Wildner }
100479ab7f0SSascha Wildner 
101479ab7f0SSascha Wildner static void
cp16to8(const CHAR16 * src,char * dst,size_t len)102479ab7f0SSascha Wildner cp16to8(const CHAR16 *src, char *dst, size_t len)
103479ab7f0SSascha Wildner {
104479ab7f0SSascha Wildner 	size_t i;
105479ab7f0SSascha Wildner 
106479ab7f0SSascha Wildner 	for (i = 0; i < len && src[i]; i++)
107479ab7f0SSascha Wildner 		dst[i] = (char)src[i];
108479ab7f0SSascha Wildner }
109479ab7f0SSascha Wildner 
110479ab7f0SSascha Wildner static int
has_keyboard(void)111479ab7f0SSascha Wildner has_keyboard(void)
112479ab7f0SSascha Wildner {
113479ab7f0SSascha Wildner 	EFI_STATUS status;
114479ab7f0SSascha Wildner 	EFI_DEVICE_PATH *path;
115479ab7f0SSascha Wildner 	EFI_HANDLE *hin, *hin_end, *walker;
116479ab7f0SSascha Wildner 	UINTN sz;
117479ab7f0SSascha Wildner 	int retval = 0;
118479ab7f0SSascha Wildner 
119479ab7f0SSascha Wildner 	/*
120479ab7f0SSascha Wildner 	 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
121479ab7f0SSascha Wildner 	 * do the typical dance to get the right sized buffer.
122479ab7f0SSascha Wildner 	 */
123479ab7f0SSascha Wildner 	sz = 0;
124479ab7f0SSascha Wildner 	hin = NULL;
125479ab7f0SSascha Wildner 	status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
126479ab7f0SSascha Wildner 	if (status == EFI_BUFFER_TOO_SMALL) {
127479ab7f0SSascha Wildner 		hin = (EFI_HANDLE *)malloc(sz);
128479ab7f0SSascha Wildner 		status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
129479ab7f0SSascha Wildner 		    hin);
130479ab7f0SSascha Wildner 		if (EFI_ERROR(status))
131479ab7f0SSascha Wildner 			free(hin);
132479ab7f0SSascha Wildner 	}
133479ab7f0SSascha Wildner 	if (EFI_ERROR(status))
134479ab7f0SSascha Wildner 		return retval;
135479ab7f0SSascha Wildner 
136479ab7f0SSascha Wildner 	/*
137479ab7f0SSascha Wildner 	 * Look at each of the handles. If it supports the device path protocol,
138479ab7f0SSascha Wildner 	 * use it to get the device path for this handle. Then see if that
139479ab7f0SSascha Wildner 	 * device path matches either the USB device path for keyboards or the
140479ab7f0SSascha Wildner 	 * legacy device path for keyboards.
141479ab7f0SSascha Wildner 	 */
142479ab7f0SSascha Wildner 	hin_end = &hin[sz / sizeof(*hin)];
143479ab7f0SSascha Wildner 	for (walker = hin; walker < hin_end; walker++) {
144479ab7f0SSascha Wildner 		status = OpenProtocolByHandle(*walker, &devid, (VOID **)&path);
145479ab7f0SSascha Wildner 		if (EFI_ERROR(status))
146479ab7f0SSascha Wildner 			continue;
147479ab7f0SSascha Wildner 
148479ab7f0SSascha Wildner 		while (!IsDevicePathEnd(path)) {
149479ab7f0SSascha Wildner 			/*
150479ab7f0SSascha Wildner 			 * Check for the ACPI keyboard node. All PNP3xx nodes
151479ab7f0SSascha Wildner 			 * are keyboards of different flavors. Note: It is
152479ab7f0SSascha Wildner 			 * unclear of there's always a keyboard node when
153479ab7f0SSascha Wildner 			 * there's a keyboard controller, or if there's only one
154479ab7f0SSascha Wildner 			 * when a keyboard is detected at boot.
155479ab7f0SSascha Wildner 			 */
156479ab7f0SSascha Wildner 			if (DevicePathType(path) == ACPI_DEVICE_PATH &&
157479ab7f0SSascha Wildner 			    (DevicePathSubType(path) == ACPI_DP ||
158479ab7f0SSascha Wildner 				DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
159479ab7f0SSascha Wildner 				ACPI_HID_DEVICE_PATH  *acpi;
160479ab7f0SSascha Wildner 
161479ab7f0SSascha Wildner 				acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
162479ab7f0SSascha Wildner 				if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
163479ab7f0SSascha Wildner 				    (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
164479ab7f0SSascha Wildner 					retval = 1;
165479ab7f0SSascha Wildner 					goto out;
166479ab7f0SSascha Wildner 				}
167479ab7f0SSascha Wildner 			/*
168479ab7f0SSascha Wildner 			 * Check for USB keyboard node, if present. Unlike a
169479ab7f0SSascha Wildner 			 * PS/2 keyboard, these definitely only appear when
170479ab7f0SSascha Wildner 			 * connected to the system.
171479ab7f0SSascha Wildner 			 */
172479ab7f0SSascha Wildner 			} else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
173479ab7f0SSascha Wildner 			    DevicePathSubType(path) == MSG_USB_CLASS_DP) {
174479ab7f0SSascha Wildner 				USB_CLASS_DEVICE_PATH *usb;
175479ab7f0SSascha Wildner 
176479ab7f0SSascha Wildner 				usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
177479ab7f0SSascha Wildner 				if (usb->DeviceClass == 3 && /* HID */
178479ab7f0SSascha Wildner 				    usb->DeviceSubClass == 1 && /* Boot devices */
179479ab7f0SSascha Wildner 				    usb->DeviceProtocol == 1) { /* Boot keyboards */
180479ab7f0SSascha Wildner 					retval = 1;
181479ab7f0SSascha Wildner 					goto out;
182479ab7f0SSascha Wildner 				}
183479ab7f0SSascha Wildner 			}
184479ab7f0SSascha Wildner 			path = NextDevicePathNode(path);
185479ab7f0SSascha Wildner 		}
186479ab7f0SSascha Wildner 	}
187479ab7f0SSascha Wildner out:
188479ab7f0SSascha Wildner 	free(hin);
189479ab7f0SSascha Wildner 	return retval;
190479ab7f0SSascha Wildner }
191479ab7f0SSascha Wildner 
192479ab7f0SSascha Wildner EFI_STATUS
main(int argc,CHAR16 * argv[])193479ab7f0SSascha Wildner main(int argc, CHAR16 *argv[])
194479ab7f0SSascha Wildner {
195479ab7f0SSascha Wildner 	char var[128];
196479ab7f0SSascha Wildner 	EFI_LOADED_IMAGE *img;
197479ab7f0SSascha Wildner 	EFI_GUID *guid;
198479ab7f0SSascha Wildner 	int i, j, vargood, unit, howto;
199479ab7f0SSascha Wildner 	struct devsw *dev;
200479ab7f0SSascha Wildner 	uint64_t pool_guid;
201479ab7f0SSascha Wildner 	UINTN k;
202479ab7f0SSascha Wildner 	int has_kbd;
203479ab7f0SSascha Wildner 
204479ab7f0SSascha Wildner 	archsw.arch_autoload = efi_autoload;
205479ab7f0SSascha Wildner 	archsw.arch_getdev = efi_getdev;
206479ab7f0SSascha Wildner 	archsw.arch_copyin = efi_copyin;
207479ab7f0SSascha Wildner 	archsw.arch_copyout = efi_copyout;
208479ab7f0SSascha Wildner 	archsw.arch_readin = efi_readin;
209479ab7f0SSascha Wildner 
210479ab7f0SSascha Wildner 	has_kbd = has_keyboard();
211479ab7f0SSascha Wildner 
212479ab7f0SSascha Wildner 	/*
213479ab7f0SSascha Wildner 	 * XXX Chicken-and-egg problem; we want to have console output
214479ab7f0SSascha Wildner 	 * early, but some console attributes may depend on reading from
215479ab7f0SSascha Wildner 	 * eg. the boot device, which we can't do yet.  We can use
216479ab7f0SSascha Wildner 	 * printf() etc. once this is done.
217479ab7f0SSascha Wildner 	 */
218479ab7f0SSascha Wildner 	cons_probe();
219479ab7f0SSascha Wildner 
220479ab7f0SSascha Wildner 	/*
221479ab7f0SSascha Wildner 	 * Parse the args to set the console settings, etc
222479ab7f0SSascha Wildner 	 * boot1.efi passes these in, if it can read /boot.config or /boot/config
223479ab7f0SSascha Wildner 	 * or iPXE may be setup to pass these in.
224479ab7f0SSascha Wildner 	 *
225479ab7f0SSascha Wildner 	 * Loop through the args, and for each one that contains an '=' that is
226479ab7f0SSascha Wildner 	 * not the first character, add it to the environment.  This allows
227479ab7f0SSascha Wildner 	 * loader and kernel env vars to be passed on the command line.  Convert
228479ab7f0SSascha Wildner 	 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
229479ab7f0SSascha Wildner 	 */
230479ab7f0SSascha Wildner 	howto = 0;
231479ab7f0SSascha Wildner 	for (i = 1; i < argc; i++) {
232479ab7f0SSascha Wildner 		if (argv[i][0] == '-') {
233479ab7f0SSascha Wildner 			for (j = 1; argv[i][j] != 0; j++) {
234479ab7f0SSascha Wildner 				int ch;
235479ab7f0SSascha Wildner 
236479ab7f0SSascha Wildner 				ch = argv[i][j];
237479ab7f0SSascha Wildner 				switch (ch) {
238479ab7f0SSascha Wildner 				case 'a':
239479ab7f0SSascha Wildner 					howto |= RB_ASKNAME;
240479ab7f0SSascha Wildner 					break;
241479ab7f0SSascha Wildner 				case 'd':
242479ab7f0SSascha Wildner 					howto |= RB_KDB;
243479ab7f0SSascha Wildner 					break;
244479ab7f0SSascha Wildner 				case 'h':
245479ab7f0SSascha Wildner 					howto |= RB_SERIAL;
246479ab7f0SSascha Wildner 					break;
247479ab7f0SSascha Wildner 				case 'm':
248479ab7f0SSascha Wildner 					howto |= RB_MUTE;
249479ab7f0SSascha Wildner 					break;
250479ab7f0SSascha Wildner 				case 'p':
251479ab7f0SSascha Wildner 					howto |= RB_PAUSE;
252479ab7f0SSascha Wildner 					break;
253479ab7f0SSascha Wildner 				case 'P':
254479ab7f0SSascha Wildner 					if (!has_kbd) {
255479ab7f0SSascha Wildner 						howto &= ~(RB_MUTE|RB_VIDEO);
256479ab7f0SSascha Wildner 						howto |= RB_SERIAL;
257479ab7f0SSascha Wildner 					}
258479ab7f0SSascha Wildner 					break;
259479ab7f0SSascha Wildner 				case 'r':
260479ab7f0SSascha Wildner 					howto |= RB_DFLTROOT;
261479ab7f0SSascha Wildner 					break;
262479ab7f0SSascha Wildner 				case 's':
263479ab7f0SSascha Wildner 					howto |= RB_SINGLE;
264479ab7f0SSascha Wildner 					break;
265479ab7f0SSascha Wildner 				case 'S':
266479ab7f0SSascha Wildner 					if (argv[i][j + 1] == 0) {
267479ab7f0SSascha Wildner 						if (i + 1 == argc) {
268479ab7f0SSascha Wildner 							setenv("comconsole_speed", "115200", 1);
269479ab7f0SSascha Wildner 						} else {
270479ab7f0SSascha Wildner 							cp16to8(&argv[i + 1][0], var,
271479ab7f0SSascha Wildner 							    sizeof(var));
272479ab7f0SSascha Wildner 							setenv("comconsole_speedspeed", var, 1);
273479ab7f0SSascha Wildner 						}
274479ab7f0SSascha Wildner 						i++;
275479ab7f0SSascha Wildner 						break;
276479ab7f0SSascha Wildner 					} else {
277479ab7f0SSascha Wildner 						cp16to8(&argv[i][j + 1], var,
278479ab7f0SSascha Wildner 						    sizeof(var));
279479ab7f0SSascha Wildner 						setenv("comconsole_speed", var, 1);
280479ab7f0SSascha Wildner 						break;
281479ab7f0SSascha Wildner 					}
282479ab7f0SSascha Wildner 				case 'v':
283479ab7f0SSascha Wildner 					howto |= RB_VERBOSE;
284479ab7f0SSascha Wildner 					break;
285479ab7f0SSascha Wildner 				}
286479ab7f0SSascha Wildner 			}
287479ab7f0SSascha Wildner 		} else {
288479ab7f0SSascha Wildner 			vargood = 0;
289479ab7f0SSascha Wildner 			for (j = 0; argv[i][j] != 0; j++) {
290479ab7f0SSascha Wildner 				if (j == sizeof(var)) {
291479ab7f0SSascha Wildner 					vargood = 0;
292479ab7f0SSascha Wildner 					break;
293479ab7f0SSascha Wildner 				}
294479ab7f0SSascha Wildner 				if (j > 0 && argv[i][j] == '=')
295479ab7f0SSascha Wildner 					vargood = 1;
296479ab7f0SSascha Wildner 				var[j] = (char)argv[i][j];
297479ab7f0SSascha Wildner 			}
298479ab7f0SSascha Wildner 			if (vargood) {
299479ab7f0SSascha Wildner 				var[j] = 0;
300479ab7f0SSascha Wildner 				putenv(var);
301479ab7f0SSascha Wildner 			}
302479ab7f0SSascha Wildner 		}
303479ab7f0SSascha Wildner 	}
304479ab7f0SSascha Wildner 	for (i = 0; howto_names[i].ev != NULL; i++)
305479ab7f0SSascha Wildner 		if (howto & howto_names[i].mask)
306479ab7f0SSascha Wildner 			setenv(howto_names[i].ev, "YES", 1);
307479ab7f0SSascha Wildner 	if (howto & RB_SERIAL) {
308479ab7f0SSascha Wildner 		setenv("console", "comconsole" , 1);
309479ab7f0SSascha Wildner 	}
310479ab7f0SSascha Wildner 
311479ab7f0SSascha Wildner 	if (efi_copy_init()) {
312479ab7f0SSascha Wildner 		printf("failed to allocate staging area\n");
313479ab7f0SSascha Wildner 		return (EFI_BUFFER_TOO_SMALL);
314479ab7f0SSascha Wildner 	}
315479ab7f0SSascha Wildner 
316479ab7f0SSascha Wildner 	/*
317479ab7f0SSascha Wildner 	 * March through the device switch probing for things.
318479ab7f0SSascha Wildner 	 */
319479ab7f0SSascha Wildner 	for (i = 0; devsw[i] != NULL; i++)
320479ab7f0SSascha Wildner 		if (devsw[i]->dv_init != NULL)
321479ab7f0SSascha Wildner 			(devsw[i]->dv_init)();
322479ab7f0SSascha Wildner 
323479ab7f0SSascha Wildner 	/* Get our loaded image protocol interface structure. */
324479ab7f0SSascha Wildner 	OpenProtocolByHandle(IH, &imgid, (VOID**)&img);
325479ab7f0SSascha Wildner 
326479ab7f0SSascha Wildner 	printf("Command line arguments:");
327479ab7f0SSascha Wildner 	for (i = 0; i < argc; i++) {
328479ab7f0SSascha Wildner 		printf(" ");
329479ab7f0SSascha Wildner 		print_str16(argv[i]);
330479ab7f0SSascha Wildner 	}
331479ab7f0SSascha Wildner 	printf("\n");
332479ab7f0SSascha Wildner 
333479ab7f0SSascha Wildner 	printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
334479ab7f0SSascha Wildner 	printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
335479ab7f0SSascha Wildner 	    ST->Hdr.Revision & 0xffff);
336479ab7f0SSascha Wildner 	printf("EFI Firmware: ");
337479ab7f0SSascha Wildner 	/* printf doesn't understand EFI Unicode */
338479ab7f0SSascha Wildner 	ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor);
339479ab7f0SSascha Wildner 	printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16,
340479ab7f0SSascha Wildner 	    ST->FirmwareRevision & 0xffff);
341479ab7f0SSascha Wildner 
342479ab7f0SSascha Wildner 	printf("\n");
343479ab7f0SSascha Wildner 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
344479ab7f0SSascha Wildner 	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
345479ab7f0SSascha Wildner 
346479ab7f0SSascha Wildner 	/*
347479ab7f0SSascha Wildner 	 * Disable the watchdog timer. By default the boot manager sets
348479ab7f0SSascha Wildner 	 * the timer to 5 minutes before invoking a boot option. If we
349479ab7f0SSascha Wildner 	 * want to return to the boot manager, we have to disable the
350479ab7f0SSascha Wildner 	 * watchdog timer and since we're an interactive program, we don't
351479ab7f0SSascha Wildner 	 * want to wait until the user types "quit". The timer may have
352479ab7f0SSascha Wildner 	 * fired by then. We don't care if this fails. It does not prevent
353479ab7f0SSascha Wildner 	 * normal functioning in any way...
354479ab7f0SSascha Wildner 	 */
355479ab7f0SSascha Wildner 	BS->SetWatchdogTimer(0, 0, 0, NULL);
356479ab7f0SSascha Wildner 
357479ab7f0SSascha Wildner 	if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0)
358479ab7f0SSascha Wildner 		return (EFI_NOT_FOUND);
359479ab7f0SSascha Wildner 
360479ab7f0SSascha Wildner 	switch (dev->dv_type) {
361479ab7f0SSascha Wildner 	default: {
362479ab7f0SSascha Wildner 		struct efi_devdesc currdev;
363479ab7f0SSascha Wildner 
364479ab7f0SSascha Wildner 		currdev.d_dev = dev;
365479ab7f0SSascha Wildner 		currdev.d_kind.efidisk.unit = unit;
366479ab7f0SSascha Wildner 		currdev.d_kind.efidisk.data = NULL;
367479ab7f0SSascha Wildner 		currdev.d_type = currdev.d_dev->dv_type;
368479ab7f0SSascha Wildner 		env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
369479ab7f0SSascha Wildner 			   efi_setcurrdev, env_nounset);
370479ab7f0SSascha Wildner 		env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
371479ab7f0SSascha Wildner 			   env_nounset);
372479ab7f0SSascha Wildner 		break;
373479ab7f0SSascha Wildner 	}
374479ab7f0SSascha Wildner 	}
375479ab7f0SSascha Wildner 
376479ab7f0SSascha Wildner 	/* enable EHCI */
377479ab7f0SSascha Wildner 	setenv("ehci_load", "YES", 1);
378479ab7f0SSascha Wildner 
379479ab7f0SSascha Wildner 	/* enable XHCI */
380479ab7f0SSascha Wildner 	setenv("xhci_load", "YES", 1);
381479ab7f0SSascha Wildner 
382479ab7f0SSascha Wildner 	/* Check if ACPI is available */
383479ab7f0SSascha Wildner 	if (efi_get_table(&acpi20) != NULL ||
384479ab7f0SSascha Wildner 	    efi_get_table(&acpi) != NULL) {
385479ab7f0SSascha Wildner 		setenv("acpi_load", "YES", 1);
386479ab7f0SSascha Wildner 	}
387479ab7f0SSascha Wildner 
388479ab7f0SSascha Wildner 	setenv("LINES", "24", 1);	/* optional */
389479ab7f0SSascha Wildner 
390479ab7f0SSascha Wildner 	for (k = 0; k < ST->NumberOfTableEntries; k++) {
391479ab7f0SSascha Wildner 		guid = &ST->ConfigurationTable[k].VendorGuid;
392479ab7f0SSascha Wildner 		if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
393479ab7f0SSascha Wildner 			smbios_detect(ST->ConfigurationTable[k].VendorTable);
394479ab7f0SSascha Wildner 			break;
395479ab7f0SSascha Wildner 		}
396479ab7f0SSascha Wildner 	}
397479ab7f0SSascha Wildner 
398479ab7f0SSascha Wildner 	interact();			/* doesn't return */
399479ab7f0SSascha Wildner 
400479ab7f0SSascha Wildner 	return (EFI_SUCCESS);		/* keep compiler happy */
401479ab7f0SSascha Wildner }
402479ab7f0SSascha Wildner 
403479ab7f0SSascha Wildner /* XXX move to lib stand ? */
404479ab7f0SSascha Wildner static int
wcscmp(CHAR16 * a,CHAR16 * b)405479ab7f0SSascha Wildner wcscmp(CHAR16 *a, CHAR16 *b)
406479ab7f0SSascha Wildner {
407479ab7f0SSascha Wildner 
408479ab7f0SSascha Wildner 	while (*a && *b && *a == *b) {
409479ab7f0SSascha Wildner 		a++;
410479ab7f0SSascha Wildner 		b++;
411479ab7f0SSascha Wildner 	}
412479ab7f0SSascha Wildner 	return *a - *b;
413479ab7f0SSascha Wildner }
414479ab7f0SSascha Wildner 
415479ab7f0SSascha Wildner 
416479ab7f0SSascha Wildner COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
417479ab7f0SSascha Wildner 
418479ab7f0SSascha Wildner static int
command_reboot(int argc,char * argv[])419479ab7f0SSascha Wildner command_reboot(int argc, char *argv[])
420479ab7f0SSascha Wildner {
421479ab7f0SSascha Wildner 	int i;
422479ab7f0SSascha Wildner 
423479ab7f0SSascha Wildner 	for (i = 0; devsw[i] != NULL; ++i)
424479ab7f0SSascha Wildner 		if (devsw[i]->dv_cleanup != NULL)
425479ab7f0SSascha Wildner 			(devsw[i]->dv_cleanup)();
426479ab7f0SSascha Wildner 
427479ab7f0SSascha Wildner 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23,
428479ab7f0SSascha Wildner 	    (CHAR16 *)"Reboot from the loader");
429479ab7f0SSascha Wildner 
430479ab7f0SSascha Wildner 	/* NOTREACHED */
431479ab7f0SSascha Wildner 	return (CMD_ERROR);
432479ab7f0SSascha Wildner }
433479ab7f0SSascha Wildner 
434479ab7f0SSascha Wildner COMMAND_SET(quit, "quit", "exit the loader", command_quit);
435479ab7f0SSascha Wildner 
436479ab7f0SSascha Wildner static int
command_quit(int argc,char * argv[])437479ab7f0SSascha Wildner command_quit(int argc, char *argv[])
438479ab7f0SSascha Wildner {
439479ab7f0SSascha Wildner 	exit(0);
440479ab7f0SSascha Wildner 	return (CMD_OK);
441479ab7f0SSascha Wildner }
442479ab7f0SSascha Wildner 
443479ab7f0SSascha Wildner COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
444479ab7f0SSascha Wildner 
445479ab7f0SSascha Wildner static int
command_memmap(int argc,char * argv[])446479ab7f0SSascha Wildner command_memmap(int argc, char *argv[])
447479ab7f0SSascha Wildner {
448479ab7f0SSascha Wildner 	UINTN sz;
449479ab7f0SSascha Wildner 	EFI_MEMORY_DESCRIPTOR *map, *p;
450479ab7f0SSascha Wildner 	UINTN key, dsz;
451479ab7f0SSascha Wildner 	UINT32 dver;
452479ab7f0SSascha Wildner 	EFI_STATUS status;
453479ab7f0SSascha Wildner 	int i, ndesc;
454479ab7f0SSascha Wildner 	char line[80];
455479ab7f0SSascha Wildner 	static char *types[] = {
456479ab7f0SSascha Wildner 	    "Reserved",
457479ab7f0SSascha Wildner 	    "LoaderCode",
458479ab7f0SSascha Wildner 	    "LoaderData",
459479ab7f0SSascha Wildner 	    "BootServicesCode",
460479ab7f0SSascha Wildner 	    "BootServicesData",
461479ab7f0SSascha Wildner 	    "RuntimeServicesCode",
462479ab7f0SSascha Wildner 	    "RuntimeServicesData",
463479ab7f0SSascha Wildner 	    "ConventionalMemory",
464479ab7f0SSascha Wildner 	    "UnusableMemory",
465479ab7f0SSascha Wildner 	    "ACPIReclaimMemory",
466479ab7f0SSascha Wildner 	    "ACPIMemoryNVS",
467479ab7f0SSascha Wildner 	    "MemoryMappedIO",
468479ab7f0SSascha Wildner 	    "MemoryMappedIOPortSpace",
469479ab7f0SSascha Wildner 	    "PalCode"
470479ab7f0SSascha Wildner 	};
471479ab7f0SSascha Wildner 
472479ab7f0SSascha Wildner 	sz = 0;
473479ab7f0SSascha Wildner 	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
474479ab7f0SSascha Wildner 	if (status != EFI_BUFFER_TOO_SMALL) {
475479ab7f0SSascha Wildner 		printf("Can't determine memory map size\n");
476479ab7f0SSascha Wildner 		return (CMD_ERROR);
477479ab7f0SSascha Wildner 	}
478479ab7f0SSascha Wildner 	map = malloc(sz);
479479ab7f0SSascha Wildner 	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
480479ab7f0SSascha Wildner 	if (EFI_ERROR(status)) {
481479ab7f0SSascha Wildner 		printf("Can't read memory map\n");
482479ab7f0SSascha Wildner 		return (CMD_ERROR);
483479ab7f0SSascha Wildner 	}
484479ab7f0SSascha Wildner 
485479ab7f0SSascha Wildner 	ndesc = sz / dsz;
486479ab7f0SSascha Wildner 	snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n",
487479ab7f0SSascha Wildner 	    "Type", "Physical", "Virtual", "#Pages", "Attr");
488479ab7f0SSascha Wildner 	pager_open();
489479ab7f0SSascha Wildner 	if (pager_output(line)) {
490479ab7f0SSascha Wildner 		pager_close();
491479ab7f0SSascha Wildner 		return (CMD_OK);
492479ab7f0SSascha Wildner 	}
493479ab7f0SSascha Wildner 
494479ab7f0SSascha Wildner 	for (i = 0, p = map; i < ndesc;
495479ab7f0SSascha Wildner 	     i++, p = NextMemoryDescriptor(p, dsz)) {
496479ab7f0SSascha Wildner 		printf("%23s %012jx %012jx %08jx ", types[p->Type],
497479ab7f0SSascha Wildner 		    (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart,
498479ab7f0SSascha Wildner 		    (uintmax_t)p->NumberOfPages);
499479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_UC)
500479ab7f0SSascha Wildner 			printf("UC ");
501479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_WC)
502479ab7f0SSascha Wildner 			printf("WC ");
503479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_WT)
504479ab7f0SSascha Wildner 			printf("WT ");
505479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_WB)
506479ab7f0SSascha Wildner 			printf("WB ");
507479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_UCE)
508479ab7f0SSascha Wildner 			printf("UCE ");
509479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_WP)
510479ab7f0SSascha Wildner 			printf("WP ");
511479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_RP)
512479ab7f0SSascha Wildner 			printf("RP ");
513479ab7f0SSascha Wildner 		if (p->Attribute & EFI_MEMORY_XP)
514479ab7f0SSascha Wildner 			printf("XP ");
515479ab7f0SSascha Wildner 		if (pager_output("\n"))
516479ab7f0SSascha Wildner 			break;
517479ab7f0SSascha Wildner 	}
518479ab7f0SSascha Wildner 
519479ab7f0SSascha Wildner 	pager_close();
520479ab7f0SSascha Wildner 	return (CMD_OK);
521479ab7f0SSascha Wildner }
522479ab7f0SSascha Wildner 
523479ab7f0SSascha Wildner COMMAND_SET(configuration, "configuration", "print configuration tables",
524479ab7f0SSascha Wildner     command_configuration);
525479ab7f0SSascha Wildner 
526479ab7f0SSascha Wildner static const char *
guid_to_string(EFI_GUID * guid)527479ab7f0SSascha Wildner guid_to_string(EFI_GUID *guid)
528479ab7f0SSascha Wildner {
529479ab7f0SSascha Wildner 	static char buf[40];
530479ab7f0SSascha Wildner 
531479ab7f0SSascha Wildner 	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
532479ab7f0SSascha Wildner 	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
533479ab7f0SSascha Wildner 	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
534479ab7f0SSascha Wildner 	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
535479ab7f0SSascha Wildner 	return (buf);
536479ab7f0SSascha Wildner }
537479ab7f0SSascha Wildner 
538479ab7f0SSascha Wildner static int
command_configuration(int argc,char * argv[])539479ab7f0SSascha Wildner command_configuration(int argc, char *argv[])
540479ab7f0SSascha Wildner {
541479ab7f0SSascha Wildner 	char line[80];
542479ab7f0SSascha Wildner 	UINTN i;
543479ab7f0SSascha Wildner 
544479ab7f0SSascha Wildner 	snprintf(line, sizeof(line), "NumberOfTableEntries=%lu\n",
545479ab7f0SSascha Wildner 		(unsigned long)ST->NumberOfTableEntries);
546479ab7f0SSascha Wildner 	pager_open();
547479ab7f0SSascha Wildner 	if (pager_output(line)) {
548479ab7f0SSascha Wildner 		pager_close();
549479ab7f0SSascha Wildner 		return (CMD_OK);
550479ab7f0SSascha Wildner 	}
551479ab7f0SSascha Wildner 
552479ab7f0SSascha Wildner 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
553479ab7f0SSascha Wildner 		EFI_GUID *guid;
554479ab7f0SSascha Wildner 
555479ab7f0SSascha Wildner 		printf("  ");
556479ab7f0SSascha Wildner 		guid = &ST->ConfigurationTable[i].VendorGuid;
557479ab7f0SSascha Wildner 		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
558479ab7f0SSascha Wildner 			printf("MPS Table");
559479ab7f0SSascha Wildner 		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
560479ab7f0SSascha Wildner 			printf("ACPI Table");
561479ab7f0SSascha Wildner 		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
562479ab7f0SSascha Wildner 			printf("ACPI 2.0 Table");
563479ab7f0SSascha Wildner 		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
564479ab7f0SSascha Wildner 			printf("SMBIOS Table");
565*34f16cb6SAaron LI 		else if (!memcmp(guid, &smbios3, sizeof(EFI_GUID)))
566*34f16cb6SAaron LI 			printf("SMBIOS3 Table");
567479ab7f0SSascha Wildner 		else if (!memcmp(guid, &dxe, sizeof(EFI_GUID)))
568479ab7f0SSascha Wildner 			printf("DXE Table");
569479ab7f0SSascha Wildner 		else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID)))
570479ab7f0SSascha Wildner 			printf("HOB List Table");
571479ab7f0SSascha Wildner 		else if (!memcmp(guid, &memtype, sizeof(EFI_GUID)))
572479ab7f0SSascha Wildner 			printf("Memory Type Information Table");
573479ab7f0SSascha Wildner 		else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID)))
574479ab7f0SSascha Wildner 			printf("Debug Image Info Table");
575479ab7f0SSascha Wildner 		else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID)))
576479ab7f0SSascha Wildner 			printf("FDT Table");
577*34f16cb6SAaron LI 		else if (!memcmp(guid, &esrt, sizeof(EFI_GUID)))
578*34f16cb6SAaron LI 			printf("System Resource Table");
579*34f16cb6SAaron LI 		else if (!memcmp(guid, &lzmadecomp, sizeof(EFI_GUID)))
580*34f16cb6SAaron LI 			printf("LZMA-compressed Filesystem");
581*34f16cb6SAaron LI 		else if (!memcmp(guid, &amiromlayout, sizeof(EFI_GUID)))
582*34f16cb6SAaron LI 			printf("AMI ROM Layout");
583479ab7f0SSascha Wildner 		else
584479ab7f0SSascha Wildner 			printf("Unknown Table (%s)", guid_to_string(guid));
585479ab7f0SSascha Wildner 		snprintf(line, sizeof(line), " at %p\n",
586479ab7f0SSascha Wildner 		    ST->ConfigurationTable[i].VendorTable);
587479ab7f0SSascha Wildner 		if (pager_output(line))
588479ab7f0SSascha Wildner 			break;
589479ab7f0SSascha Wildner 	}
590479ab7f0SSascha Wildner 
591479ab7f0SSascha Wildner 	pager_close();
592479ab7f0SSascha Wildner 	return (CMD_OK);
593479ab7f0SSascha Wildner }
594479ab7f0SSascha Wildner 
595479ab7f0SSascha Wildner 
596479ab7f0SSascha Wildner COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
597479ab7f0SSascha Wildner 
598479ab7f0SSascha Wildner static int
command_mode(int argc,char * argv[])599479ab7f0SSascha Wildner command_mode(int argc, char *argv[])
600479ab7f0SSascha Wildner {
601479ab7f0SSascha Wildner 	UINTN cols, rows;
602479ab7f0SSascha Wildner 	unsigned int mode;
603479ab7f0SSascha Wildner 	int i;
604479ab7f0SSascha Wildner 	char *cp;
605479ab7f0SSascha Wildner 	char rowenv[8];
606479ab7f0SSascha Wildner 	EFI_STATUS status;
607479ab7f0SSascha Wildner 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
608479ab7f0SSascha Wildner 	extern void HO(void);
609479ab7f0SSascha Wildner 
610479ab7f0SSascha Wildner 	conout = ST->ConOut;
611479ab7f0SSascha Wildner 
612479ab7f0SSascha Wildner 	if (argc > 1) {
613479ab7f0SSascha Wildner 		mode = strtol(argv[1], &cp, 0);
614479ab7f0SSascha Wildner 		if (cp[0] != '\0') {
615479ab7f0SSascha Wildner 			printf("Invalid mode\n");
616479ab7f0SSascha Wildner 			return (CMD_ERROR);
617479ab7f0SSascha Wildner 		}
618479ab7f0SSascha Wildner 		status = conout->QueryMode(conout, mode, &cols, &rows);
619479ab7f0SSascha Wildner 		if (EFI_ERROR(status)) {
620479ab7f0SSascha Wildner 			printf("invalid mode %d\n", mode);
621479ab7f0SSascha Wildner 			return (CMD_ERROR);
622479ab7f0SSascha Wildner 		}
623479ab7f0SSascha Wildner 		status = conout->SetMode(conout, mode);
624479ab7f0SSascha Wildner 		if (EFI_ERROR(status)) {
625479ab7f0SSascha Wildner 			printf("couldn't set mode %d\n", mode);
626479ab7f0SSascha Wildner 			return (CMD_ERROR);
627479ab7f0SSascha Wildner 		}
628479ab7f0SSascha Wildner 		sprintf(rowenv, "%u", (unsigned)rows);
629479ab7f0SSascha Wildner 		setenv("LINES", rowenv, 1);
630479ab7f0SSascha Wildner 		HO();		/* set cursor */
631479ab7f0SSascha Wildner 		return (CMD_OK);
632479ab7f0SSascha Wildner 	}
633479ab7f0SSascha Wildner 
634479ab7f0SSascha Wildner 	printf("Current mode: %d\n", conout->Mode->Mode);
635479ab7f0SSascha Wildner 	for (i = 0; i <= conout->Mode->MaxMode; i++) {
636479ab7f0SSascha Wildner 		status = conout->QueryMode(conout, i, &cols, &rows);
637479ab7f0SSascha Wildner 		if (EFI_ERROR(status))
638479ab7f0SSascha Wildner 			continue;
639479ab7f0SSascha Wildner 		printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
640479ab7f0SSascha Wildner 		    (unsigned)rows);
641479ab7f0SSascha Wildner 	}
642479ab7f0SSascha Wildner 
643479ab7f0SSascha Wildner 	if (i != 0)
644479ab7f0SSascha Wildner 		printf("Select a mode with the command \"mode <number>\"\n");
645479ab7f0SSascha Wildner 
646479ab7f0SSascha Wildner 	return (CMD_OK);
647479ab7f0SSascha Wildner }
648479ab7f0SSascha Wildner 
649479ab7f0SSascha Wildner COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
650479ab7f0SSascha Wildner 
651479ab7f0SSascha Wildner static int
efi_print_var(CHAR16 * varnamearg,EFI_GUID * matchguid,int lflag)652479ab7f0SSascha Wildner efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
653479ab7f0SSascha Wildner {
654479ab7f0SSascha Wildner 	UINTN		datasz, i;
655479ab7f0SSascha Wildner 	EFI_STATUS	status;
656479ab7f0SSascha Wildner 	UINT32		attr;
657479ab7f0SSascha Wildner 	CHAR16		*data;
658479ab7f0SSascha Wildner 	char		*str;
659479ab7f0SSascha Wildner 	uint32_t	uuid_status;
660479ab7f0SSascha Wildner 	int		is_ascii;
661479ab7f0SSascha Wildner 
662479ab7f0SSascha Wildner 	datasz = 0;
663479ab7f0SSascha Wildner 	status = RS->GetVariable(varnamearg, matchguid, &attr,
664479ab7f0SSascha Wildner 	    &datasz, NULL);
665479ab7f0SSascha Wildner 	if (status != EFI_BUFFER_TOO_SMALL) {
666479ab7f0SSascha Wildner 		printf("Can't get the variable: error %#llx\n", status);
667479ab7f0SSascha Wildner 		return (CMD_ERROR);
668479ab7f0SSascha Wildner 	}
669479ab7f0SSascha Wildner 	data = malloc(datasz);
670479ab7f0SSascha Wildner 	status = RS->GetVariable(varnamearg, matchguid, &attr,
671479ab7f0SSascha Wildner 	    &datasz, data);
672479ab7f0SSascha Wildner 	if (status != EFI_SUCCESS) {
673479ab7f0SSascha Wildner 		printf("Can't get the variable: error %#llx\n", status);
674479ab7f0SSascha Wildner 		return (CMD_ERROR);
675479ab7f0SSascha Wildner 	}
676479ab7f0SSascha Wildner 	uuid_to_string((uuid_t *)matchguid, &str, &uuid_status);
677479ab7f0SSascha Wildner 	if (lflag) {
678479ab7f0SSascha Wildner 		printf("%s 0x%x %S", str, attr, varnamearg);
679479ab7f0SSascha Wildner 	} else {
680479ab7f0SSascha Wildner 		printf("%s 0x%x %S=", str, attr, varnamearg);
681479ab7f0SSascha Wildner 		is_ascii = 1;
682479ab7f0SSascha Wildner 		free(str);
683479ab7f0SSascha Wildner 		str = (char *)data;
684479ab7f0SSascha Wildner 		for (i = 0; i < datasz - 1; i++) {
685479ab7f0SSascha Wildner 			/* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */
686479ab7f0SSascha Wildner 			if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) {
687479ab7f0SSascha Wildner 				is_ascii = 0;
688479ab7f0SSascha Wildner 				break;
689479ab7f0SSascha Wildner 			}
690479ab7f0SSascha Wildner 		}
691479ab7f0SSascha Wildner 		if (str[datasz - 1] != '\0')
692479ab7f0SSascha Wildner 			is_ascii = 0;
693479ab7f0SSascha Wildner 		if (is_ascii)
694479ab7f0SSascha Wildner 			printf("%s", str);
695479ab7f0SSascha Wildner 		else {
696479ab7f0SSascha Wildner 			for (i = 0; i < datasz / 2; i++) {
697479ab7f0SSascha Wildner 				if (isalnum(data[i]) || isspace(data[i]))
698479ab7f0SSascha Wildner 					printf("%c", data[i]);
699479ab7f0SSascha Wildner 				else
700479ab7f0SSascha Wildner 					printf("\\x%02x", data[i]);
701479ab7f0SSascha Wildner 			}
702479ab7f0SSascha Wildner 		}
703479ab7f0SSascha Wildner 	}
704479ab7f0SSascha Wildner 	free(data);
705479ab7f0SSascha Wildner 	pager_output("\n");
706479ab7f0SSascha Wildner 	return (CMD_OK);
707479ab7f0SSascha Wildner }
708479ab7f0SSascha Wildner 
709479ab7f0SSascha Wildner static int
command_efi_show(int argc,char * argv[])710479ab7f0SSascha Wildner command_efi_show(int argc, char *argv[])
711479ab7f0SSascha Wildner {
712479ab7f0SSascha Wildner 	/*
713479ab7f0SSascha Wildner 	 * efi-show [-a]
714479ab7f0SSascha Wildner 	 *	print all the env
715479ab7f0SSascha Wildner 	 * efi-show -u UUID
716479ab7f0SSascha Wildner 	 *	print all the env vars tagged with UUID
717479ab7f0SSascha Wildner 	 * efi-show -v var
718479ab7f0SSascha Wildner 	 *	search all the env vars and print the ones matching var
719479ab7f0SSascha Wildner 	 * eif-show -u UUID -v var
720479ab7f0SSascha Wildner 	 * eif-show UUID var
721479ab7f0SSascha Wildner 	 *	print all the env vars that match UUID and var
722479ab7f0SSascha Wildner 	 */
723479ab7f0SSascha Wildner 	/* NB: We assume EFI_GUID is the same as uuid_t */
724479ab7f0SSascha Wildner 	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
725479ab7f0SSascha Wildner 	int		ch, rv;
726479ab7f0SSascha Wildner 	unsigned	i;
727479ab7f0SSascha Wildner 	EFI_STATUS	status;
728479ab7f0SSascha Wildner 	EFI_GUID	varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
729479ab7f0SSascha Wildner 	EFI_GUID	matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
730479ab7f0SSascha Wildner 	uint32_t	uuid_status;
731479ab7f0SSascha Wildner 	CHAR16		*varname;
732479ab7f0SSascha Wildner 	CHAR16		*newnm;
733479ab7f0SSascha Wildner 	CHAR16		varnamearg[128];
734479ab7f0SSascha Wildner 	UINTN		varalloc;
735479ab7f0SSascha Wildner 	UINTN		varsz;
736479ab7f0SSascha Wildner 
737479ab7f0SSascha Wildner 	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
738479ab7f0SSascha Wildner 		switch (ch) {
739479ab7f0SSascha Wildner 		case 'a':
740479ab7f0SSascha Wildner 			aflag = 1;
741479ab7f0SSascha Wildner 			break;
742479ab7f0SSascha Wildner 		case 'g':
743479ab7f0SSascha Wildner 			gflag = 1;
744479ab7f0SSascha Wildner 			uuid_from_string(optarg, (uuid_t *)&matchguid,
745479ab7f0SSascha Wildner 			    &uuid_status);
746479ab7f0SSascha Wildner 			if (uuid_status != uuid_s_ok) {
747479ab7f0SSascha Wildner 				printf("uid %s could not be parsed\n", optarg);
748479ab7f0SSascha Wildner 				return (CMD_ERROR);
749479ab7f0SSascha Wildner 			}
750479ab7f0SSascha Wildner 			break;
751479ab7f0SSascha Wildner 		case 'l':
752479ab7f0SSascha Wildner 			lflag = 1;
753479ab7f0SSascha Wildner 			break;
754479ab7f0SSascha Wildner 		case 'v':
755479ab7f0SSascha Wildner 			vflag = 1;
756479ab7f0SSascha Wildner 			if (strlen(optarg) >= nitems(varnamearg)) {
757479ab7f0SSascha Wildner 				printf("Variable %s is longer than %zu characters\n",
758479ab7f0SSascha Wildner 				    optarg, nitems(varnamearg));
759479ab7f0SSascha Wildner 				return (CMD_ERROR);
760479ab7f0SSascha Wildner 			}
761479ab7f0SSascha Wildner 			for (i = 0; i < strlen(optarg); i++)
762479ab7f0SSascha Wildner 				varnamearg[i] = optarg[i];
763479ab7f0SSascha Wildner 			varnamearg[i] = 0;
764479ab7f0SSascha Wildner 			break;
765479ab7f0SSascha Wildner 		default:
766479ab7f0SSascha Wildner 			printf("Invalid argument %c\n", ch);
767479ab7f0SSascha Wildner 			return (CMD_ERROR);
768479ab7f0SSascha Wildner 		}
769479ab7f0SSascha Wildner 	}
770479ab7f0SSascha Wildner 
771479ab7f0SSascha Wildner 	if (aflag && (gflag || vflag)) {
772479ab7f0SSascha Wildner 		printf("-a isn't compatible with -v or -u\n");
773479ab7f0SSascha Wildner 		return (CMD_ERROR);
774479ab7f0SSascha Wildner 	}
775479ab7f0SSascha Wildner 
776479ab7f0SSascha Wildner 	if (aflag && optind < argc) {
777479ab7f0SSascha Wildner 		printf("-a doesn't take any args");
778479ab7f0SSascha Wildner 		return (CMD_ERROR);
779479ab7f0SSascha Wildner 	}
780479ab7f0SSascha Wildner 
781479ab7f0SSascha Wildner 	if (optind == argc)
782479ab7f0SSascha Wildner 		aflag = 1;
783479ab7f0SSascha Wildner 
784479ab7f0SSascha Wildner 	argc -= optind;
785479ab7f0SSascha Wildner 	argv += optind;
786479ab7f0SSascha Wildner 
787479ab7f0SSascha Wildner 	pager_open();
788479ab7f0SSascha Wildner 	if (vflag && gflag) {
789479ab7f0SSascha Wildner 		rv = efi_print_var(varnamearg, &matchguid, lflag);
790479ab7f0SSascha Wildner 		pager_close();
791479ab7f0SSascha Wildner 		return (rv);
792479ab7f0SSascha Wildner 	}
793479ab7f0SSascha Wildner 
794479ab7f0SSascha Wildner 	if (argc == 2) {
795479ab7f0SSascha Wildner 		optarg = argv[0];
796479ab7f0SSascha Wildner 		if (strlen(optarg) >= nitems(varnamearg)) {
797479ab7f0SSascha Wildner 			printf("Variable %s is longer than %zu characters\n",
798479ab7f0SSascha Wildner 			    optarg, nitems(varnamearg));
799479ab7f0SSascha Wildner 			pager_close();
800479ab7f0SSascha Wildner 			return (CMD_ERROR);
801479ab7f0SSascha Wildner 		}
802479ab7f0SSascha Wildner 		for (i = 0; i < strlen(optarg); i++)
803479ab7f0SSascha Wildner 			varnamearg[i] = optarg[i];
804479ab7f0SSascha Wildner 		varnamearg[i] = 0;
805479ab7f0SSascha Wildner 		optarg = argv[1];
806479ab7f0SSascha Wildner 		uuid_from_string(optarg, (uuid_t *)&matchguid,
807479ab7f0SSascha Wildner 		    &uuid_status);
808479ab7f0SSascha Wildner 		if (uuid_status != uuid_s_ok) {
809479ab7f0SSascha Wildner 			printf("uid %s could not be parsed\n", optarg);
810479ab7f0SSascha Wildner 			pager_close();
811479ab7f0SSascha Wildner 			return (CMD_ERROR);
812479ab7f0SSascha Wildner 		}
813479ab7f0SSascha Wildner 		rv = efi_print_var(varnamearg, &matchguid, lflag);
814479ab7f0SSascha Wildner 		pager_close();
815479ab7f0SSascha Wildner 		return (rv);
816479ab7f0SSascha Wildner 	}
817479ab7f0SSascha Wildner 
818479ab7f0SSascha Wildner 	if (argc > 0) {
819479ab7f0SSascha Wildner 		printf("Too many args %d\n", argc);
820479ab7f0SSascha Wildner 		pager_close();
821479ab7f0SSascha Wildner 		return (CMD_ERROR);
822479ab7f0SSascha Wildner 	}
823479ab7f0SSascha Wildner 
824479ab7f0SSascha Wildner 	/*
825479ab7f0SSascha Wildner 	 * Initiate the search -- note the standard takes pain
826479ab7f0SSascha Wildner 	 * to specify the initial call must be a poiner to a NULL
827479ab7f0SSascha Wildner 	 * character.
828479ab7f0SSascha Wildner 	 */
829479ab7f0SSascha Wildner 	varalloc = 1024;
830479ab7f0SSascha Wildner 	varname = malloc(varalloc);
831479ab7f0SSascha Wildner 	if (varname == NULL) {
832479ab7f0SSascha Wildner 		printf("Can't allocate memory to get variables\n");
833479ab7f0SSascha Wildner 		pager_close();
834479ab7f0SSascha Wildner 		return (CMD_ERROR);
835479ab7f0SSascha Wildner 	}
836479ab7f0SSascha Wildner 	varname[0] = 0;
837479ab7f0SSascha Wildner 	while (1) {
838479ab7f0SSascha Wildner 		varsz = varalloc;
839479ab7f0SSascha Wildner 		status = RS->GetNextVariableName(&varsz, varname, &varguid);
840479ab7f0SSascha Wildner 		if (status == EFI_BUFFER_TOO_SMALL) {
841479ab7f0SSascha Wildner 			varalloc = varsz;
842479ab7f0SSascha Wildner 			newnm = malloc(varalloc);
843479ab7f0SSascha Wildner 			if (newnm == NULL) {
844479ab7f0SSascha Wildner 				printf("Can't allocate memory to get variables\n");
845479ab7f0SSascha Wildner 				free(varname);
846479ab7f0SSascha Wildner 				pager_close();
847479ab7f0SSascha Wildner 				return (CMD_ERROR);
848479ab7f0SSascha Wildner 			}
849479ab7f0SSascha Wildner 			memcpy(newnm, varname, varsz);
850479ab7f0SSascha Wildner 			free(varname);
851479ab7f0SSascha Wildner 			varname = newnm;
852479ab7f0SSascha Wildner 			continue; /* Try again with bigger buffer */
853479ab7f0SSascha Wildner 		}
854479ab7f0SSascha Wildner 		if (status != EFI_SUCCESS)
855479ab7f0SSascha Wildner 			break;
856479ab7f0SSascha Wildner 		if (aflag) {
857479ab7f0SSascha Wildner 			if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
858479ab7f0SSascha Wildner 				break;
859479ab7f0SSascha Wildner 			continue;
860479ab7f0SSascha Wildner 		}
861479ab7f0SSascha Wildner 		if (vflag) {
862479ab7f0SSascha Wildner 			if (wcscmp(varnamearg, varname) == 0) {
863479ab7f0SSascha Wildner 				if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
864479ab7f0SSascha Wildner 					break;
865479ab7f0SSascha Wildner 				continue;
866479ab7f0SSascha Wildner 			}
867479ab7f0SSascha Wildner 		}
868479ab7f0SSascha Wildner 		if (gflag) {
869479ab7f0SSascha Wildner 			if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) {
870479ab7f0SSascha Wildner 				if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
871479ab7f0SSascha Wildner 					break;
872479ab7f0SSascha Wildner 				continue;
873479ab7f0SSascha Wildner 			}
874479ab7f0SSascha Wildner 		}
875479ab7f0SSascha Wildner 	}
876479ab7f0SSascha Wildner 	free(varname);
877479ab7f0SSascha Wildner 	pager_close();
878479ab7f0SSascha Wildner 
879479ab7f0SSascha Wildner 	return (CMD_OK);
880479ab7f0SSascha Wildner }
881479ab7f0SSascha Wildner 
882479ab7f0SSascha Wildner COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
883479ab7f0SSascha Wildner 
884479ab7f0SSascha Wildner static int
command_efi_set(int argc,char * argv[])885479ab7f0SSascha Wildner command_efi_set(int argc, char *argv[])
886479ab7f0SSascha Wildner {
887479ab7f0SSascha Wildner 	char *uuid, *var, *val;
888479ab7f0SSascha Wildner 	CHAR16 wvar[128];
889479ab7f0SSascha Wildner 	EFI_GUID guid;
890479ab7f0SSascha Wildner 	uint32_t status;
891479ab7f0SSascha Wildner 	EFI_STATUS err;
892479ab7f0SSascha Wildner 
893479ab7f0SSascha Wildner 	if (argc != 4) {
894479ab7f0SSascha Wildner 		printf("efi-set uuid var new-value\n");
895479ab7f0SSascha Wildner 		return (CMD_ERROR);
896479ab7f0SSascha Wildner 	}
897479ab7f0SSascha Wildner 	uuid = argv[1];
898479ab7f0SSascha Wildner 	var = argv[2];
899479ab7f0SSascha Wildner 	val = argv[3];
900479ab7f0SSascha Wildner 	uuid_from_string(uuid, (uuid_t *)&guid, &status);
901479ab7f0SSascha Wildner 	if (status != uuid_s_ok) {
902479ab7f0SSascha Wildner 		printf("Invalid uuid %s %d\n", uuid, status);
903479ab7f0SSascha Wildner 		return (CMD_ERROR);
904479ab7f0SSascha Wildner 	}
905479ab7f0SSascha Wildner 	cpy8to16(var, wvar, sizeof(wvar));
906479ab7f0SSascha Wildner 	err = RS->SetVariable(wvar, &guid,
907479ab7f0SSascha Wildner 	    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
908479ab7f0SSascha Wildner 	    strlen(val) + 1, val);
909479ab7f0SSascha Wildner 	if (EFI_ERROR(err)) {
910479ab7f0SSascha Wildner 		printf("Failed to set variable: error %llu\n", err);
911479ab7f0SSascha Wildner 		return (CMD_ERROR);
912479ab7f0SSascha Wildner 	}
913479ab7f0SSascha Wildner 	return (CMD_OK);
914479ab7f0SSascha Wildner }
915479ab7f0SSascha Wildner 
916479ab7f0SSascha Wildner COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
917479ab7f0SSascha Wildner 
918479ab7f0SSascha Wildner static int
command_efi_unset(int argc,char * argv[])919479ab7f0SSascha Wildner command_efi_unset(int argc, char *argv[])
920479ab7f0SSascha Wildner {
921479ab7f0SSascha Wildner 	char *uuid, *var;
922479ab7f0SSascha Wildner 	CHAR16 wvar[128];
923479ab7f0SSascha Wildner 	EFI_GUID guid;
924479ab7f0SSascha Wildner 	uint32_t status;
925479ab7f0SSascha Wildner 	EFI_STATUS err;
926479ab7f0SSascha Wildner 
927479ab7f0SSascha Wildner 	if (argc != 3) {
928479ab7f0SSascha Wildner 		printf("efi-unset uuid var\n");
929479ab7f0SSascha Wildner 		return (CMD_ERROR);
930479ab7f0SSascha Wildner 	}
931479ab7f0SSascha Wildner 	uuid = argv[1];
932479ab7f0SSascha Wildner 	var = argv[2];
933479ab7f0SSascha Wildner 	uuid_from_string(uuid, (uuid_t *)&guid, &status);
934479ab7f0SSascha Wildner 	if (status != uuid_s_ok) {
935479ab7f0SSascha Wildner 		printf("Invalid uuid %s\n", uuid);
936479ab7f0SSascha Wildner 		return (CMD_ERROR);
937479ab7f0SSascha Wildner 	}
938479ab7f0SSascha Wildner 	cpy8to16(var, wvar, sizeof(wvar));
939479ab7f0SSascha Wildner 	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
940479ab7f0SSascha Wildner 	if (EFI_ERROR(err)) {
941479ab7f0SSascha Wildner 		printf("Failed to unset variable: error %llu\n", err);
942479ab7f0SSascha Wildner 		return (CMD_ERROR);
943479ab7f0SSascha Wildner 	}
944479ab7f0SSascha Wildner 	return (CMD_OK);
945479ab7f0SSascha Wildner }
946