2 * Copyright (c) 2015 Netflix, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
34 #include <efigpt.h> /* Partition GUIDS */
35 #include <Guid/MemoryTypeInformation.h>
36 #include <Guid/MtcVendor.h>
37 #include <Guid/ZeroGuid.h>
38 #include <Protocol/EdidActive.h>
39 #include <Protocol/EdidDiscovered.h>
42 #include <sys/param.h>
43 #include "bootstrap.h"
46 * About ENABLE_UPDATES
48 * The UEFI variables are identified only by GUID and name, there is no
49 * way to (auto)detect the type for the value, so we need to process the
50 * variables case by case, as we do learn about them.
52 * While showing the variable name and the value is safe, we must not store
53 * random values nor allow removing (random) variables.
55 * Since we do have stub code to set/unset the variables, I do want to keep
56 * it to make the future development a bit easier, but the updates are disabled
58 * a) the validation and data translation to values is properly implemented
59 * b) We have established which variables we do allow to be updated.
60 * Therefore the set/unset code is included only for developers aid.
63 static struct efi_uuid_mapping {
64 const char *efi_guid_name;
66 } efi_uuid_mapping[] = {
67 { .efi_guid_name = "global", .efi_guid = EFI_GLOBAL_VARIABLE },
68 { .efi_guid_name = "freebsd", .efi_guid = FREEBSD_BOOT_VAR_GUID },
69 /* EFI Systab entry names. */
70 { .efi_guid_name = "MPS Table", .efi_guid = MPS_TABLE_GUID },
71 { .efi_guid_name = "ACPI Table", .efi_guid = ACPI_TABLE_GUID },
72 { .efi_guid_name = "ACPI 2.0 Table", .efi_guid = ACPI_20_TABLE_GUID },
73 { .efi_guid_name = "SMBIOS Table", .efi_guid = SMBIOS_TABLE_GUID },
74 { .efi_guid_name = "SMBIOS3 Table", .efi_guid = SMBIOS3_TABLE_GUID },
75 { .efi_guid_name = "DXE Table", .efi_guid = DXE_SERVICES_TABLE_GUID },
76 { .efi_guid_name = "HOB List Table", .efi_guid = HOB_LIST_TABLE_GUID },
77 { .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
78 .efi_guid = EFI_MEMORY_TYPE_INFORMATION_GUID },
79 { .efi_guid_name = "Debug Image Info Table",
80 .efi_guid = DEBUG_IMAGE_INFO_TABLE_GUID },
81 { .efi_guid_name = "FDT Table", .efi_guid = FDT_TABLE_GUID },
83 * Protocol names for debug purposes.
84 * Can be removed along with lsefi command.
86 { .efi_guid_name = "device path", .efi_guid = DEVICE_PATH_PROTOCOL },
87 { .efi_guid_name = "block io", .efi_guid = BLOCK_IO_PROTOCOL },
88 { .efi_guid_name = "disk io", .efi_guid = DISK_IO_PROTOCOL },
89 { .efi_guid_name = "disk info", .efi_guid =
90 EFI_DISK_INFO_PROTOCOL_GUID },
91 { .efi_guid_name = "simple fs",
92 .efi_guid = SIMPLE_FILE_SYSTEM_PROTOCOL },
93 { .efi_guid_name = "load file", .efi_guid = LOAD_FILE_PROTOCOL },
94 { .efi_guid_name = "device io", .efi_guid = DEVICE_IO_PROTOCOL },
95 { .efi_guid_name = "unicode collation",
96 .efi_guid = UNICODE_COLLATION_PROTOCOL },
97 { .efi_guid_name = "unicode collation2",
98 .efi_guid = EFI_UNICODE_COLLATION2_PROTOCOL_GUID },
99 { .efi_guid_name = "simple network",
100 .efi_guid = EFI_SIMPLE_NETWORK_PROTOCOL },
101 { .efi_guid_name = "simple text output",
102 .efi_guid = SIMPLE_TEXT_OUTPUT_PROTOCOL },
103 { .efi_guid_name = "simple text input",
104 .efi_guid = SIMPLE_TEXT_INPUT_PROTOCOL },
105 { .efi_guid_name = "simple text ex input",
106 .efi_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID },
107 { .efi_guid_name = "console control",
108 .efi_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID },
109 { .efi_guid_name = "stdin", .efi_guid = EFI_CONSOLE_IN_DEVICE_GUID },
110 { .efi_guid_name = "stdout", .efi_guid = EFI_CONSOLE_OUT_DEVICE_GUID },
111 { .efi_guid_name = "stderr",
112 .efi_guid = EFI_STANDARD_ERROR_DEVICE_GUID },
113 { .efi_guid_name = "GOP",
114 .efi_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID },
115 { .efi_guid_name = "UGA draw", .efi_guid = EFI_UGA_DRAW_PROTOCOL_GUID },
116 { .efi_guid_name = "PXE base code",
117 .efi_guid = EFI_PXE_BASE_CODE_PROTOCOL },
118 { .efi_guid_name = "PXE base code callback",
119 .efi_guid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL },
120 { .efi_guid_name = "serial io", .efi_guid = SERIAL_IO_PROTOCOL },
121 { .efi_guid_name = "loaded image", .efi_guid = LOADED_IMAGE_PROTOCOL },
122 { .efi_guid_name = "loaded image device path",
123 .efi_guid = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID },
124 { .efi_guid_name = "ISA io", .efi_guid = EFI_ISA_IO_PROTOCOL_GUID },
125 { .efi_guid_name = "IDE controller init",
126 .efi_guid = EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID },
127 { .efi_guid_name = "ISA ACPI", .efi_guid = EFI_ISA_ACPI_PROTOCOL_GUID },
128 { .efi_guid_name = "PCI", .efi_guid = EFI_PCI_IO_PROTOCOL_GUID },
129 { .efi_guid_name = "PCI root", .efi_guid = EFI_PCI_ROOT_IO_GUID },
130 { .efi_guid_name = "PCI enumeration",
131 .efi_guid = EFI_PCI_ENUMERATION_COMPLETE_GUID },
132 { .efi_guid_name = "Driver diagnostics",
133 .efi_guid = EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID },
134 { .efi_guid_name = "Driver diagnostics2",
135 .efi_guid = EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID },
136 { .efi_guid_name = "simple pointer",
137 .efi_guid = EFI_SIMPLE_POINTER_PROTOCOL_GUID },
138 { .efi_guid_name = "absolute pointer",
139 .efi_guid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID },
140 { .efi_guid_name = "VLAN config",
141 .efi_guid = EFI_VLAN_CONFIG_PROTOCOL_GUID },
142 { .efi_guid_name = "ARP service binding",
143 .efi_guid = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID },
144 { .efi_guid_name = "ARP", .efi_guid = EFI_ARP_PROTOCOL_GUID },
145 { .efi_guid_name = "IPv4 service binding",
146 .efi_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL },
147 { .efi_guid_name = "IPv4", .efi_guid = EFI_IP4_PROTOCOL },
148 { .efi_guid_name = "IPv4 config",
149 .efi_guid = EFI_IP4_CONFIG_PROTOCOL_GUID },
150 { .efi_guid_name = "IPv6 service binding",
151 .efi_guid = EFI_IP6_SERVICE_BINDING_PROTOCOL },
152 { .efi_guid_name = "IPv6", .efi_guid = EFI_IP6_PROTOCOL },
153 { .efi_guid_name = "IPv6 config",
154 .efi_guid = EFI_IP6_CONFIG_PROTOCOL_GUID },
155 { .efi_guid_name = "UDPv4", .efi_guid = EFI_UDP4_PROTOCOL },
156 { .efi_guid_name = "UDPv4 service binding",
157 .efi_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL },
158 { .efi_guid_name = "UDPv6", .efi_guid = EFI_UDP6_PROTOCOL },
159 { .efi_guid_name = "UDPv6 service binding",
160 .efi_guid = EFI_UDP6_SERVICE_BINDING_PROTOCOL },
161 { .efi_guid_name = "TCPv4", .efi_guid = EFI_TCP4_PROTOCOL },
162 { .efi_guid_name = "TCPv4 service binding",
163 .efi_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL },
164 { .efi_guid_name = "TCPv6", .efi_guid = EFI_TCP6_PROTOCOL },
165 { .efi_guid_name = "TCPv6 service binding",
166 .efi_guid = EFI_TCP6_SERVICE_BINDING_PROTOCOL },
167 { .efi_guid_name = "EFI System partition",
168 .efi_guid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID },
169 { .efi_guid_name = "MBR legacy",
170 .efi_guid = EFI_PART_TYPE_LEGACY_MBR_GUID },
171 { .efi_guid_name = "device tree", .efi_guid = EFI_DEVICE_TREE_GUID },
172 { .efi_guid_name = "USB io", .efi_guid = EFI_USB_IO_PROTOCOL_GUID },
173 { .efi_guid_name = "USB2 HC", .efi_guid = EFI_USB2_HC_PROTOCOL_GUID },
174 { .efi_guid_name = "component name",
175 .efi_guid = EFI_COMPONENT_NAME_PROTOCOL_GUID },
176 { .efi_guid_name = "component name2",
177 .efi_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID },
178 { .efi_guid_name = "driver binding",
179 .efi_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID },
180 { .efi_guid_name = "driver configuration",
181 .efi_guid = EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID },
182 { .efi_guid_name = "driver configuration2",
183 .efi_guid = EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID },
184 { .efi_guid_name = "decompress",
185 .efi_guid = EFI_DECOMPRESS_PROTOCOL_GUID },
186 { .efi_guid_name = "ebc interpreter",
187 .efi_guid = EFI_EBC_INTERPRETER_PROTOCOL_GUID },
188 { .efi_guid_name = "network interface identifier",
189 .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL },
190 { .efi_guid_name = "network interface identifier_31",
191 .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 },
192 { .efi_guid_name = "managed network service binding",
193 .efi_guid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID },
194 { .efi_guid_name = "managed network",
195 .efi_guid = EFI_MANAGED_NETWORK_PROTOCOL_GUID },
196 { .efi_guid_name = "form browser",
197 .efi_guid = EFI_FORM_BROWSER2_PROTOCOL_GUID },
198 { .efi_guid_name = "HII config routing",
199 .efi_guid = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID },
200 { .efi_guid_name = "HII database",
201 .efi_guid = EFI_HII_DATABASE_PROTOCOL_GUID },
202 { .efi_guid_name = "HII string",
203 .efi_guid = EFI_HII_STRING_PROTOCOL_GUID },
204 { .efi_guid_name = "HII image",
205 .efi_guid = EFI_HII_IMAGE_PROTOCOL_GUID },
206 { .efi_guid_name = "HII font", .efi_guid = EFI_HII_FONT_PROTOCOL_GUID },
207 { .efi_guid_name = "HII config",
208 .efi_guid = EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID },
209 { .efi_guid_name = "MTFTP4 service binding",
210 .efi_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID },
211 { .efi_guid_name = "MTFTP4", .efi_guid = EFI_MTFTP4_PROTOCOL_GUID },
212 { .efi_guid_name = "MTFTP6 service binding",
213 .efi_guid = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID },
214 { .efi_guid_name = "MTFTP6", .efi_guid = EFI_MTFTP6_PROTOCOL_GUID },
215 { .efi_guid_name = "DHCP4 service binding",
216 .efi_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID },
217 { .efi_guid_name = "DHCP4", .efi_guid = EFI_DHCP4_PROTOCOL_GUID },
218 { .efi_guid_name = "DHCP6 service binding",
219 .efi_guid = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID },
220 { .efi_guid_name = "DHCP6", .efi_guid = EFI_DHCP6_PROTOCOL_GUID },
221 { .efi_guid_name = "SCSI io", .efi_guid = EFI_SCSI_IO_PROTOCOL_GUID },
222 { .efi_guid_name = "SCSI pass thru",
223 .efi_guid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID },
224 { .efi_guid_name = "SCSI pass thru ext",
225 .efi_guid = EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID },
226 { .efi_guid_name = "Capsule arch",
227 .efi_guid = EFI_CAPSULE_ARCH_PROTOCOL_GUID },
228 { .efi_guid_name = "monotonic counter arch",
229 .efi_guid = EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID },
230 { .efi_guid_name = "realtime clock arch",
231 .efi_guid = EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID },
232 { .efi_guid_name = "variable arch",
233 .efi_guid = EFI_VARIABLE_ARCH_PROTOCOL_GUID },
234 { .efi_guid_name = "variable write arch",
235 .efi_guid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID },
236 { .efi_guid_name = "watchdog timer arch",
237 .efi_guid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID },
238 { .efi_guid_name = "ACPI support",
239 .efi_guid = EFI_ACPI_SUPPORT_PROTOCOL_GUID },
240 { .efi_guid_name = "BDS arch", .efi_guid = EFI_BDS_ARCH_PROTOCOL_GUID },
241 { .efi_guid_name = "metronome arch",
242 .efi_guid = EFI_METRONOME_ARCH_PROTOCOL_GUID },
243 { .efi_guid_name = "timer arch",
244 .efi_guid = EFI_TIMER_ARCH_PROTOCOL_GUID },
245 { .efi_guid_name = "DPC", .efi_guid = EFI_DPC_PROTOCOL_GUID },
246 { .efi_guid_name = "print2", .efi_guid = EFI_PRINT2_PROTOCOL_GUID },
247 { .efi_guid_name = "device path to text",
248 .efi_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID },
249 { .efi_guid_name = "reset arch",
250 .efi_guid = EFI_RESET_ARCH_PROTOCOL_GUID },
251 { .efi_guid_name = "CPU arch", .efi_guid = EFI_CPU_ARCH_PROTOCOL_GUID },
252 { .efi_guid_name = "CPU IO2", .efi_guid = EFI_CPU_IO2_PROTOCOL_GUID },
253 { .efi_guid_name = "Legacy 8259",
254 .efi_guid = EFI_LEGACY_8259_PROTOCOL_GUID },
255 { .efi_guid_name = "Security arch",
256 .efi_guid = EFI_SECURITY_ARCH_PROTOCOL_GUID },
257 { .efi_guid_name = "Security2 arch",
258 .efi_guid = EFI_SECURITY2_ARCH_PROTOCOL_GUID },
259 { .efi_guid_name = "Runtime arch",
260 .efi_guid = EFI_RUNTIME_ARCH_PROTOCOL_GUID },
261 { .efi_guid_name = "status code runtime",
262 .efi_guid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID },
263 { .efi_guid_name = "data hub", .efi_guid = EFI_DATA_HUB_PROTOCOL_GUID },
264 { .efi_guid_name = "PCD", .efi_guid = PCD_PROTOCOL_GUID },
265 { .efi_guid_name = "EFI PCD", .efi_guid = EFI_PCD_PROTOCOL_GUID },
266 { .efi_guid_name = "firmware volume block",
267 .efi_guid = EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID },
268 { .efi_guid_name = "firmware volume2",
269 .efi_guid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID },
270 { .efi_guid_name = "firmware volume dispatch",
271 .efi_guid = EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID },
272 { .efi_guid_name = "lzma compress", .efi_guid = LZMA_COMPRESS_GUID },
273 { .efi_guid_name = "MP services",
274 .efi_guid = EFI_MP_SERVICES_PROTOCOL_GUID },
275 { .efi_guid_name = MTC_VARIABLE_NAME, .efi_guid = MTC_VENDOR_GUID },
276 { .efi_guid_name = "RTC", .efi_guid = { 0x378D7B65, 0x8DA9, 0x4773,
277 { 0xB6, 0xE4, 0xA4, 0x78, 0x26, 0xA8, 0x33, 0xE1} } },
278 { .efi_guid_name = "Active EDID",
279 .efi_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID },
280 { .efi_guid_name = "Discovered EDID",
281 .efi_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID }
285 efi_guid_to_str(const EFI_GUID *guid, char **sp)
289 uuid_to_string((const uuid_t *)guid, sp, &status);
290 return (status == uuid_s_ok ? true : false);
294 efi_str_to_guid(const char *s, EFI_GUID *guid)
298 uuid_from_string(s, (uuid_t *)guid, &status);
299 return (status == uuid_s_ok ? true : false);
303 efi_name_to_guid(const char *name, EFI_GUID *guid)
307 for (i = 0; i < nitems(efi_uuid_mapping); i++) {
308 if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) {
309 *guid = efi_uuid_mapping[i].efi_guid;
313 return (efi_str_to_guid(name, guid));
317 efi_guid_to_name(EFI_GUID *guid, char **name)
322 for (i = 0; i < nitems(efi_uuid_mapping); i++) {
323 rv = uuid_equal((uuid_t *)guid,
324 (uuid_t *)&efi_uuid_mapping[i].efi_guid, NULL);
326 *name = strdup(efi_uuid_mapping[i].efi_guid_name);
332 return (efi_guid_to_str(guid, name));
336 efi_init_environment(void)
340 snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
341 ST->Hdr.Revision & 0xffff);
342 env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
345 COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
348 efi_print_other_value(uint8_t *data, UINTN datasz)
351 bool is_ascii = true;
354 for (i = 0; i < datasz - 1; i++) {
356 * Quick hack to see if this ascii-ish string is printable
357 * range plus tab, cr and lf.
359 if ((data[i] < 32 || data[i] > 126)
360 && data[i] != 9 && data[i] != 10 && data[i] != 13) {
365 if (data[datasz - 1] != '\0')
367 if (is_ascii == true) {
369 if (pager_output("\n"))
372 if (pager_output("\n"))
375 * Dump hex bytes grouped by 4.
377 for (i = 0; i < datasz; i++) {
378 printf("%02x ", data[i]);
379 if ((i + 1) % 4 == 0)
381 if ((i + 1) % 20 == 0) {
382 if (pager_output("\n"))
386 if (pager_output("\n"))
393 /* This appears to be some sort of UEFI shell alias table. */
395 efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data,
396 UINTN datasz __unused)
398 printf(" = %S", (CHAR16 *)data);
399 if (pager_output("\n"))
405 efi_memory_type(EFI_MEMORY_TYPE type)
407 const char *types[] = {
413 "RuntimeServicesCode",
414 "RuntimeServicesData",
415 "ConventionalMemory",
420 "MemoryMappedIOPortSpace",
426 case EfiReservedMemoryType:
429 case EfiBootServicesCode:
430 case EfiBootServicesData:
431 case EfiRuntimeServicesCode:
432 case EfiRuntimeServicesData:
433 case EfiConventionalMemory:
434 case EfiUnusableMemory:
435 case EfiACPIReclaimMemory:
436 case EfiACPIMemoryNVS:
437 case EfiMemoryMappedIO:
438 case EfiMemoryMappedIOPortSpace:
440 case EfiPersistentMemory:
441 return (types[type]);
447 /* Print memory type table. */
449 efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
453 EFI_MEMORY_TYPE_INFORMATION *ti;
455 ti = (EFI_MEMORY_TYPE_INFORMATION *)data;
456 if (pager_output(" = \n"))
459 n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION);
460 for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) {
461 printf("\t%23s pages: %u", efi_memory_type(ti[i].Type),
462 ti[i].NumberOfPages);
463 if (pager_output("\n"))
471 * Print FreeBSD variables.
472 * We have LoaderPath and LoaderDev as CHAR16 strings.
475 efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
476 UINTN datasz __unused)
481 if (ucs2_to_utf8(varnamearg, &var) != 0)
484 if (strcmp("LoaderPath", var) == 0 ||
485 strcmp("LoaderDev", var) == 0) {
487 printf("%S", (CHAR16 *)data);
489 if (pager_output("\n"))
499 /* Print global variables. */
501 efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz)
506 if (ucs2_to_utf8(varnamearg, &var) != 0)
509 if (strcmp("AuditMode", var) == 0) {
511 printf("0x%x", *data); /* 8-bit int */
515 if (strcmp("BootOptionSupport", var) == 0) {
517 printf("0x%x", *((uint32_t *)data)); /* UINT32 */
521 if (strcmp("BootCurrent", var) == 0 ||
522 strcmp("BootNext", var) == 0 ||
523 strcmp("Timeout", var) == 0) {
525 printf("%u", *((uint16_t *)data)); /* UINT16 */
529 if (strcmp("BootOrder", var) == 0 ||
530 strcmp("DriverOrder", var) == 0) {
532 UINT16 *u16 = (UINT16 *)data;
535 for (i = 0; i < datasz / sizeof (UINT16); i++)
536 printf(" %u", u16[i]);
539 if (strncmp("Boot", var, 4) == 0 ||
540 strncmp("Driver", var, 5) == 0 ||
541 strncmp("SysPrep", var, 7) == 0 ||
542 strncmp("OsRecovery", var, 10) == 0) {
543 UINT16 filepathlistlen;
548 data += sizeof(UINT32);
549 filepathlistlen = *(uint16_t *)data;
550 data += sizeof (UINT16);
551 text = (CHAR16 *)data;
553 for (desclen = 0; text[desclen] != 0; desclen++)
556 /* Add terminating zero and we have CHAR16. */
557 desclen = (desclen + 1) * 2;
562 if (filepathlistlen != 0) {
563 /* Output pathname from new line. */
564 if (pager_output("\n")) {
568 dp = malloc(filepathlistlen);
572 memcpy(dp, data + desclen, filepathlistlen);
573 text = efi_devpath_name(dp);
575 printf("\t%S", text);
576 efi_free_devpath_name(text);
583 if (strcmp("ConIn", var) == 0 ||
584 strcmp("ConInDev", var) == 0 ||
585 strcmp("ConOut", var) == 0 ||
586 strcmp("ConOutDev", var) == 0 ||
587 strcmp("ErrOut", var) == 0 ||
588 strcmp("ErrOutDev", var) == 0) {
592 text = efi_devpath_name((EFI_DEVICE_PATH *)data);
595 efi_free_devpath_name(text);
600 if (strcmp("PlatformLang", var) == 0 ||
601 strcmp("PlatformLangCodes", var) == 0 ||
602 strcmp("LangCodes", var) == 0 ||
603 strcmp("Lang", var) == 0) {
605 printf("%s", data); /* ASCII string */
610 * Feature bitmap from firmware to OS.
611 * Older UEFI provides UINT32, newer UINT64.
613 if (strcmp("OsIndicationsSupported", var) == 0) {
616 printf("0x%x", *((uint32_t *)data));
618 printf("0x%jx", *((uint64_t *)data));
622 /* Fallback for anything else. */
623 rv = efi_print_other_value(data, datasz);
626 if (pager_output("\n"))
636 efi_print_var_attr(UINT32 attr)
640 if (attr & EFI_VARIABLE_NON_VOLATILE) {
644 if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
650 if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
656 if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
662 if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
671 efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
682 status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL);
683 if (status != EFI_BUFFER_TOO_SMALL) {
684 printf("Can't get the variable: error %#lx\n",
685 EFI_ERROR_CODE(status));
688 data = malloc(datasz);
690 printf("Out of memory\n");
694 status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data);
695 if (status != EFI_SUCCESS) {
696 printf("Can't get the variable: error %#lx\n",
697 EFI_ERROR_CODE(status));
702 if (efi_guid_to_name(matchguid, &str) == false) {
707 efi_print_var_attr(attr);
708 printf(" %S", varnamearg);
711 if (strcmp(str, "global") == 0)
712 rv = efi_print_global(varnamearg, data, datasz);
713 else if (strcmp(str, "freebsd") == 0)
714 rv = efi_print_freebsd(varnamearg, data, datasz);
716 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0)
717 rv = efi_print_mem_type(varnamearg, data, datasz);
719 "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0)
720 rv = efi_print_shell_str(varnamearg, data, datasz);
721 else if (strcmp(str, MTC_VARIABLE_NAME) == 0) {
723 printf("%u", *((uint32_t *)data)); /* UINT32 */
725 if (pager_output("\n"))
728 rv = efi_print_other_value(data, datasz);
729 } else if (pager_output("\n"))
739 command_efi_show(int argc, char *argv[])
745 * print all the env vars tagged with UUID
747 * search all the env vars and print the ones matching var
748 * efi-show -g UUID -v var
750 * print all the env vars that match UUID and var
752 /* NB: We assume EFI_GUID is the same as uuid_t */
753 int aflag = 0, gflag = 0, lflag = 0, vflag = 0;
757 EFI_GUID varguid = ZERO_GUID;
758 EFI_GUID matchguid = ZERO_GUID;
761 CHAR16 varnamearg[128];
769 while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
776 if (efi_name_to_guid(optarg, &matchguid) == false) {
777 printf("uuid %s could not be parsed\n", optarg);
786 if (strlen(optarg) >= nitems(varnamearg)) {
787 printf("Variable %s is longer than %zu "
788 "characters\n", optarg, nitems(varnamearg));
791 cpy8to16(optarg, varnamearg, nitems(varnamearg));
798 if (argc == 1) /* default is -a */
801 if (aflag && (gflag || vflag)) {
802 printf("-a isn't compatible with -g or -v\n");
806 if (aflag && optind < argc) {
807 printf("-a doesn't take any args\n");
815 if (vflag && gflag) {
816 rv = efi_print_var(varnamearg, &matchguid, lflag);
825 if (strlen(optarg) >= nitems(varnamearg)) {
826 printf("Variable %s is longer than %zu characters\n",
827 optarg, nitems(varnamearg));
831 for (i = 0; i < strlen(optarg); i++)
832 varnamearg[i] = optarg[i];
835 if (efi_name_to_guid(optarg, &matchguid) == false) {
836 printf("uuid %s could not be parsed\n", optarg);
840 rv = efi_print_var(varnamearg, &matchguid, lflag);
848 printf("Too many args: %d\n", argc);
854 * Initiate the search -- note the standard takes pain
855 * to specify the initial call must be a poiner to a NULL
859 varname = malloc(varalloc);
860 if (varname == NULL) {
861 printf("Can't allocate memory to get variables\n");
868 status = RS->GetNextVariableName(&varsz, varname, &varguid);
869 if (status == EFI_BUFFER_TOO_SMALL) {
871 newnm = realloc(varname, varalloc);
873 printf("Can't allocate memory to get "
879 continue; /* Try again with bigger buffer */
881 if (status == EFI_NOT_FOUND) {
885 if (status != EFI_SUCCESS) {
891 rv = efi_print_var(varname, &varguid, lflag);
900 if (wcscmp(varnamearg, varname) == 0) {
901 rv = efi_print_var(varname, &varguid, lflag);
911 rv = uuid_equal((uuid_t *)&varguid,
912 (uuid_t *)&matchguid, NULL);
914 rv = efi_print_var(varname, &varguid, lflag);
930 COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
933 command_efi_set(int argc, char *argv[])
935 char *uuid, *var, *val;
938 #if defined(ENABLE_UPDATES)
943 printf("efi-set uuid var new-value\n");
949 if (efi_name_to_guid(uuid, &guid) == false) {
950 printf("Invalid uuid %s\n", uuid);
953 cpy8to16(var, wvar, nitems(wvar));
954 #if defined(ENABLE_UPDATES)
955 err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE |
956 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
957 strlen(val) + 1, val);
958 if (EFI_ERROR(err)) {
959 printf("Failed to set variable: error %lu\n",
960 EFI_ERROR_CODE(err));
964 printf("would set %s %s = %s\n", uuid, var, val);
969 COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
972 command_efi_unset(int argc, char *argv[])
977 #if defined(ENABLE_UPDATES)
982 printf("efi-unset uuid var\n");
987 if (efi_name_to_guid(uuid, &guid) == false) {
988 printf("Invalid uuid %s\n", uuid);
991 cpy8to16(var, wvar, nitems(wvar));
992 #if defined(ENABLE_UPDATES)
993 err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
994 if (EFI_ERROR(err)) {
995 printf("Failed to unset variable: error %lu\n",
996 EFI_ERROR_CODE(err));
1000 printf("would unset %s %s \n", uuid, var);