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