xref: /freebsd/stand/efi/libefi/env.c (revision 43b8edb320519c9887a5d953c4cf8a91f0ca8d14)
1 /*
2  * Copyright (c) 2015 Netflix, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/param.h>
27 #include <stand.h>
28 #include <string.h>
29 #include <efi.h>
30 #include <efichar.h>
31 #include <efilib.h>
32 #include <Guid/Acpi.h>
33 #include <Guid/DxeServices.h>
34 #include <Guid/DebugImageInfoTable.h>
35 #include <Guid/GlobalVariable.h>
36 #include <Guid/Gpt.h>
37 #include <Guid/Mps.h>
38 #include <Guid/SmBios.h>
39 #include <Pi/PiFirmwareFile.h>
40 #include <Pi/PiFirmwareVolume.h>
41 #include <Pi/PiMultiPhase.h>
42 #include <Protocol/AbsolutePointer.h>
43 #include <Protocol/Arp.h>
44 #include <Protocol/Bds.h>
45 #include <Protocol/Capsule.h>
46 #include <Protocol/ComponentName.h>
47 #include <Protocol/Cpu.h>
48 #include <Protocol/CpuIo2.h>
49 #include <Protocol/Decompress.h>
50 #include <Protocol/DeviceIo.h>
51 #include <Protocol/DevicePathToText.h>
52 #include <Protocol/Dhcp4.h>
53 #include <Protocol/Dhcp6.h>
54 #include <Protocol/DiskInfo.h>
55 #include <Protocol/DiskIo.h>
56 #include <Protocol/DriverBinding.h>
57 #include <Protocol/DriverConfiguration2.h>
58 #include <Protocol/DriverDiagnostics.h>
59 #include <Protocol/DriverDiagnostics2.h>
60 #include <Protocol/Ebc.h>
61 #include <Protocol/EdidActive.h>
62 #include <Protocol/EdidActive.h>
63 #include <Protocol/EdidDiscovered.h>
64 #include <Protocol/EdidDiscovered.h>
65 #include <Protocol/FirmwareVolume2.h>
66 #include <Protocol/FirmwareVolumeBlock.h>
67 #include <Protocol/FormBrowser2.h>
68 #include <Protocol/GraphicsOutput.h>
69 #include <Protocol/HiiConfigRouting.h>
70 #include <Protocol/HiiDatabase.h>
71 #include <Protocol/HiiFont.h>
72 #include <Protocol/HiiImage.h>
73 #include <Protocol/HiiString.h>
74 #include <Protocol/IdeControllerInit.h>
75 #include <Protocol/Ip4.h>
76 #include <Protocol/Ip4Config.h>
77 #include <Protocol/LoadFile.h>
78 #include <Protocol/ManagedNetwork.h>
79 #include <Protocol/Metronome.h>
80 #include <Protocol/MonotonicCounter.h>
81 #include <Protocol/MpService.h>
82 #include <Protocol/Mtftp4.h>
83 #include <Protocol/Mtftp6.h>
84 #include <Protocol/NetworkInterfaceIdentifier.h>
85 #include <Protocol/Pcd.h>
86 #include <Protocol/PciEnumerationComplete.h>
87 #include <Protocol/PciHostBridgeResourceAllocation.h>
88 #include <Protocol/PciHotPlugInit.h>
89 #include <Protocol/PciHotPlugRequest.h>
90 #include <Protocol/PciIo.h>
91 #include <Protocol/PciOverride.h>
92 #include <Protocol/PciPlatform.h>
93 #include <Protocol/PciRootBridgeIo.h>
94 #include <Protocol/PiPcd.h>
95 #include <Protocol/PxeBaseCode.h>
96 #include <Protocol/PxeBaseCodeCallBack.h>
97 #include <Protocol/Reset.h>
98 #include <Protocol/Runtime.h>
99 #include <Protocol/ScsiIo.h>
100 #include <Protocol/ScsiPassThru.h>
101 #include <Protocol/ScsiPassThruExt.h>
102 #include <Protocol/Security.h>
103 #include <Protocol/Security2.h>
104 #include <Protocol/SerialIo.h>
105 #include <Protocol/SimpleFileSystem.h>
106 #include <Protocol/SimpleNetwork.h>
107 #include <Protocol/SimplePointer.h>
108 #include <Protocol/SimpleTextIn.h>
109 #include <Protocol/SimpleTextInEx.h>
110 #include <Protocol/SimpleTextOut.h>
111 #include <Protocol/StatusCode.h>
112 #include <Protocol/Tcp4.h>
113 #include <Protocol/Tcp6.h>
114 #include <Protocol/Timer.h>
115 #include <Protocol/UgaDraw.h>
116 #include <Protocol/UgaIo.h>
117 #include <Protocol/UnicodeCollation.h>
118 #include <Protocol/Usb2HostController.h>
119 #include <Protocol/UsbIo.h>
120 #include <Protocol/Variable.h>
121 #include <Protocol/VariableWrite.h>
122 #include <Protocol/VlanConfig.h>
123 #include <Protocol/WatchdogTimer.h>
124 #include <uuid.h>
125 #include <stdbool.h>
126 #include "bootstrap.h"
127 
128 
129 
130 #define ZERO_GUID { 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }
131 
132 /*
133  * About ENABLE_UPDATES
134  *
135  * The UEFI variables are identified only by GUID and name, there is no
136  * way to (auto)detect the type for the value, so we need to process the
137  * variables case by case, as we do learn about them.
138  *
139  * While showing the variable name and the value is safe, we must not store
140  * random values nor allow removing (random) variables.
141  *
142  * Since we do have stub code to set/unset the variables, I do want to keep
143  * it to make the future development a bit easier, but the updates are disabled
144  * by default till:
145  *	a) the validation and data translation to values is properly implemented
146  *	b) We have established which variables we do allow to be updated.
147  * Therefore the set/unset code is included only for developers aid.
148  */
149 
150 static struct efi_uuid_mapping {
151 	const char *efi_guid_name;
152 	EFI_GUID efi_guid;
153 } efi_uuid_mapping[] = {
154 	{ .efi_guid_name = "global", .efi_guid = EFI_GLOBAL_VARIABLE },
155 	{ .efi_guid_name = "freebsd", .efi_guid = FREEBSD_BOOT_VAR_GUID },
156 	/* EFI Systab entry names. */
157 	{ .efi_guid_name = "MPS Table", .efi_guid = MPS_TABLE_GUID },
158 	{ .efi_guid_name = "ACPI Table", .efi_guid = ACPI_TABLE_GUID },
159 	{ .efi_guid_name = "ACPI 2.0 Table", .efi_guid = EFI_ACPI_20_TABLE_GUID },
160 	{ .efi_guid_name = "SMBIOS Table", .efi_guid = SMBIOS_TABLE_GUID },
161 	{ .efi_guid_name = "SMBIOS3 Table", .efi_guid = SMBIOS3_TABLE_GUID },
162 	{ .efi_guid_name = "DXE Table", .efi_guid = DXE_SERVICES_TABLE_GUID },
163 //	{ .efi_guid_name = "HOB List Table", .efi_guid = HOB_LIST_TABLE_GUID },
164 //	{ .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
165 //	    .efi_guid = EFI_MEMORY_TYPE_INFORMATION_GUID },
166 	{ .efi_guid_name = "Debug Image Info Table",
167 	    .efi_guid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID },
168 //	{ .efi_guid_name = "FDT Table", .efi_guid = FDT_TABLE_GUID },
169 	/*
170 	 * Protocol names for debug purposes.
171 	 * Can be removed along with lsefi command.
172 	 */
173 	{ .efi_guid_name = "device path", .efi_guid = DEVICE_PATH_PROTOCOL },
174 	{ .efi_guid_name = "block io", .efi_guid = BLOCK_IO_PROTOCOL },
175 	{ .efi_guid_name = "disk io", .efi_guid = EFI_DISK_IO_PROTOCOL_GUID },
176 	{ .efi_guid_name = "disk info", .efi_guid =
177 	    EFI_DISK_INFO_PROTOCOL_GUID },
178 	{ .efi_guid_name = "simple fs",
179 	    .efi_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID },
180 	{ .efi_guid_name = "load file", .efi_guid = LOAD_FILE_PROTOCOL },
181 	{ .efi_guid_name = "device io", .efi_guid = DEVICE_IO_PROTOCOL },
182 	{ .efi_guid_name = "unicode collation",
183 	    .efi_guid = EFI_UNICODE_COLLATION_PROTOCOL_GUID },
184 	{ .efi_guid_name = "unicode collation2",
185 	    .efi_guid = EFI_UNICODE_COLLATION_PROTOCOL2_GUID },
186 	{ .efi_guid_name = "simple network",
187 	    .efi_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID },
188 	{ .efi_guid_name = "simple text output",
189 	    .efi_guid = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID },
190 	{ .efi_guid_name = "simple text input",
191 	    .efi_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID },
192 	{ .efi_guid_name = "simple text ex input",
193 	    .efi_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID },
194 //	{ .efi_guid_name = "console control",
195 //	    .efi_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID },
196 //	{ .efi_guid_name = "stdin", .efi_guid = EFI_CONSOLE_IN_DEVICE_GUID },
197 //	{ .efi_guid_name = "stdout", .efi_guid = EFI_CONSOLE_OUT_DEVICE_GUID },
198 //	{ .efi_guid_name = "stderr",
199 //	    .efi_guid = EFI_STANDARD_ERROR_DEVICE_GUID },
200 	{ .efi_guid_name = "GOP",
201 	    .efi_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID },
202 	{ .efi_guid_name = "UGA draw", .efi_guid = EFI_UGA_DRAW_PROTOCOL_GUID },
203 	{ .efi_guid_name = "PXE base code",
204 	    .efi_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID },
205 	{ .efi_guid_name = "PXE base code callback",
206 	    .efi_guid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_GUID },
207 	{ .efi_guid_name = "serial io", .efi_guid = EFI_SERIAL_IO_PROTOCOL_GUID },
208 	{ .efi_guid_name = "loaded image", .efi_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID },
209 	{ .efi_guid_name = "loaded image device path",
210 	    .efi_guid = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID },
211 //	{ .efi_guid_name = "ISA io", .efi_guid = EFI_ISA_IO_PROTOCOL_GUID },
212 	{ .efi_guid_name = "IDE controller init",
213 	    .efi_guid = EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID },
214 //	{ .efi_guid_name = "ISA ACPI", .efi_guid = EFI_ISA_ACPI_PROTOCOL_GUID },
215 	{ .efi_guid_name = "PCI", .efi_guid = EFI_PCI_IO_PROTOCOL_GUID },
216 //	{ .efi_guid_name = "PCI root", .efi_guid = EFI_PCI_ROOT_IO_GUID },
217 	{ .efi_guid_name = "PCI enumeration",
218 	    .efi_guid = EFI_PCI_ENUMERATION_COMPLETE_GUID },
219         { .efi_guid_name = "Driver diagnostics",
220 	    .efi_guid = EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID },
221         { .efi_guid_name = "Driver diagnostics2",
222 	    .efi_guid = EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID },
223         { .efi_guid_name = "simple pointer",
224 	    .efi_guid = EFI_SIMPLE_POINTER_PROTOCOL_GUID },
225         { .efi_guid_name = "absolute pointer",
226 	    .efi_guid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID },
227         { .efi_guid_name = "VLAN config",
228 	    .efi_guid = EFI_VLAN_CONFIG_PROTOCOL_GUID },
229         { .efi_guid_name = "ARP service binding",
230 	    .efi_guid = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID },
231         { .efi_guid_name = "ARP", .efi_guid = EFI_ARP_PROTOCOL_GUID },
232         { .efi_guid_name = "IPv4 service binding",
233 	    .efi_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID },
234         { .efi_guid_name = "IPv4", .efi_guid = EFI_IP4_PROTOCOL_GUID },
235         { .efi_guid_name = "IPv4 config",
236 	    .efi_guid = EFI_IP4_CONFIG_PROTOCOL_GUID },
237 //        { .efi_guid_name = "IPv6 service binding",
238 //	    .efi_guid = EFI_IP6_SERVICE_BINDING_PROTOCOL_GUID },
239 //        { .efi_guid_name = "IPv6", .efi_guid = EFI_IP6_PROTOCOL },
240 //        { .efi_guid_name = "IPv6 config",
241 //	    .efi_guid = EFI_IP6_CONFIG_PROTOCOL_GUID },
242 //        { .efi_guid_name = "UDPv4", .efi_guid = EFI_UDP4_PROTOCOL },
243 //        { .efi_guid_name = "UDPv4 service binding",
244 //	    .efi_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID },
245 //        { .efi_guid_name = "UDPv6", .efi_guid = EFI_UDP6_PROTOCOL },
246 //        { .efi_guid_name = "UDPv6 service binding",
247 //	    .efi_guid = EFI_UDP6_SERVICE_BINDING_PROTOCOL_GUID },
248         { .efi_guid_name = "TCPv4", .efi_guid = EFI_TCP4_PROTOCOL_GUID },
249         { .efi_guid_name = "TCPv4 service binding",
250 	    .efi_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID },
251         { .efi_guid_name = "TCPv6", .efi_guid = EFI_TCP6_PROTOCOL_GUID },
252         { .efi_guid_name = "TCPv6 service binding",
253 	    .efi_guid = EFI_TCP6_SERVICE_BINDING_PROTOCOL_GUID },
254         { .efi_guid_name = "EFI System partition",
255 	    .efi_guid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID },
256         { .efi_guid_name = "MBR legacy",
257 	    .efi_guid = EFI_PART_TYPE_LEGACY_MBR_GUID },
258 //        { .efi_guid_name = "device tree", .efi_guid = EFI_DEVICE_TREE_GUID },
259         { .efi_guid_name = "USB io", .efi_guid = EFI_USB_IO_PROTOCOL_GUID },
260         { .efi_guid_name = "USB2 HC", .efi_guid = EFI_USB2_HC_PROTOCOL_GUID },
261         { .efi_guid_name = "component name",
262 	    .efi_guid = EFI_COMPONENT_NAME_PROTOCOL_GUID },
263 //        { .efi_guid_name = "component name2",
264 //	    .efi_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID },
265         { .efi_guid_name = "driver binding",
266 	    .efi_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID },
267 //        { .efi_guid_name = "driver configuration",
268 //	    .efi_guid = EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID },
269         { .efi_guid_name = "driver configuration2",
270 	    .efi_guid = EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID },
271         { .efi_guid_name = "decompress",
272 	    .efi_guid = EFI_DECOMPRESS_PROTOCOL_GUID },
273         { .efi_guid_name = "ebc interpreter",
274 	    .efi_guid = EFI_EBC_INTERPRETER_PROTOCOL_GUID },
275         { .efi_guid_name = "network interface identifier",
276 	    .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID },
277         { .efi_guid_name = "network interface identifier_31",
278 	    .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID_31 },
279         { .efi_guid_name = "managed network service binding",
280 	    .efi_guid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID },
281         { .efi_guid_name = "managed network",
282 	    .efi_guid = EFI_MANAGED_NETWORK_PROTOCOL_GUID },
283         { .efi_guid_name = "form browser",
284 	    .efi_guid = EFI_FORM_BROWSER2_PROTOCOL_GUID },
285         { .efi_guid_name = "HII config routing",
286 	    .efi_guid = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID },
287         { .efi_guid_name = "HII database",
288 	    .efi_guid = EFI_HII_DATABASE_PROTOCOL_GUID },
289         { .efi_guid_name = "HII string",
290 	    .efi_guid = EFI_HII_STRING_PROTOCOL_GUID },
291         { .efi_guid_name = "HII image",
292 	    .efi_guid = EFI_HII_IMAGE_PROTOCOL_GUID },
293         { .efi_guid_name = "HII font", .efi_guid = EFI_HII_FONT_PROTOCOL_GUID },
294 //        { .efi_guid_name = "HII config",
295 //	    .efi_guid = EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID },
296         { .efi_guid_name = "MTFTP4 service binding",
297 	    .efi_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID },
298         { .efi_guid_name = "MTFTP4", .efi_guid = EFI_MTFTP4_PROTOCOL_GUID },
299         { .efi_guid_name = "MTFTP6 service binding",
300 	    .efi_guid = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID },
301         { .efi_guid_name = "MTFTP6", .efi_guid = EFI_MTFTP6_PROTOCOL_GUID },
302         { .efi_guid_name = "DHCP4 service binding",
303 	    .efi_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID },
304         { .efi_guid_name = "DHCP4", .efi_guid = EFI_DHCP4_PROTOCOL_GUID },
305         { .efi_guid_name = "DHCP6 service binding",
306 	    .efi_guid = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID },
307         { .efi_guid_name = "DHCP6", .efi_guid = EFI_DHCP6_PROTOCOL_GUID },
308         { .efi_guid_name = "SCSI io", .efi_guid = EFI_SCSI_IO_PROTOCOL_GUID },
309         { .efi_guid_name = "SCSI pass thru",
310 	    .efi_guid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID },
311         { .efi_guid_name = "SCSI pass thru ext",
312 	    .efi_guid = EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID },
313         { .efi_guid_name = "Capsule arch",
314 	    .efi_guid = EFI_CAPSULE_ARCH_PROTOCOL_GUID },
315         { .efi_guid_name = "monotonic counter arch",
316 	    .efi_guid = EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID },
317 //        { .efi_guid_name = "realtime clock arch",
318 //	    .efi_guid = EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID },
319         { .efi_guid_name = "variable arch",
320 	    .efi_guid = EFI_VARIABLE_ARCH_PROTOCOL_GUID },
321         { .efi_guid_name = "variable write arch",
322 	    .efi_guid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID },
323         { .efi_guid_name = "watchdog timer arch",
324 	    .efi_guid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID },
325 //        { .efi_guid_name = "ACPI support",
326 //	    .efi_guid = EFI_ACPI_SUPPORT_PROTOCOL_GUID },
327         { .efi_guid_name = "BDS arch", .efi_guid = EFI_BDS_ARCH_PROTOCOL_GUID },
328         { .efi_guid_name = "metronome arch",
329 	    .efi_guid = EFI_METRONOME_ARCH_PROTOCOL_GUID },
330         { .efi_guid_name = "timer arch",
331 	    .efi_guid = EFI_TIMER_ARCH_PROTOCOL_GUID },
332 //        { .efi_guid_name = "DPC", .efi_guid = EFI_DPC_PROTOCOL_GUID },
333 //        { .efi_guid_name = "print2", .efi_guid = EFI_PRINT2_PROTOCOL_GUID },
334         { .efi_guid_name = "device path to text",
335 	    .efi_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID },
336         { .efi_guid_name = "reset arch",
337 	    .efi_guid = EFI_RESET_ARCH_PROTOCOL_GUID },
338         { .efi_guid_name = "CPU arch", .efi_guid = EFI_CPU_ARCH_PROTOCOL_GUID },
339         { .efi_guid_name = "CPU IO2", .efi_guid = EFI_CPU_IO2_PROTOCOL_GUID },
340 //        { .efi_guid_name = "Legacy 8259",
341 //	    .efi_guid = EFI_LEGACY_8259_PROTOCOL_GUID },
342         { .efi_guid_name = "Security arch",
343 	    .efi_guid = EFI_SECURITY_ARCH_PROTOCOL_GUID },
344         { .efi_guid_name = "Security2 arch",
345 	    .efi_guid = EFI_SECURITY2_ARCH_PROTOCOL_GUID },
346         { .efi_guid_name = "Runtime arch",
347 	    .efi_guid = EFI_RUNTIME_ARCH_PROTOCOL_GUID },
348         { .efi_guid_name = "status code runtime",
349 	    .efi_guid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID },
350 //        { .efi_guid_name = "data hub", .efi_guid = EFI_DATA_HUB_PROTOCOL_GUID },
351         { .efi_guid_name = "PCD", .efi_guid = PCD_PROTOCOL_GUID },
352         { .efi_guid_name = "EFI PCD", .efi_guid = EFI_PCD_PROTOCOL_GUID },
353         { .efi_guid_name = "firmware volume block",
354 	    .efi_guid = EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID },
355         { .efi_guid_name = "firmware volume2",
356 	    .efi_guid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID },
357 //        { .efi_guid_name = "firmware volume dispatch",
358 //	    .efi_guid = EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID },
359 //        { .efi_guid_name = "lzma compress", .efi_guid = LZMA_COMPRESS_GUID },
360         { .efi_guid_name = "MP services",
361 	    .efi_guid = EFI_MP_SERVICES_PROTOCOL_GUID },
362 //        { .efi_guid_name = MTC_VARIABLE_NAME, .efi_guid = MTC_VENDOR_GUID },
363         { .efi_guid_name = "RTC", .efi_guid = { 0x378D7B65, 0x8DA9, 0x4773,
364 	    { 0xB6, 0xE4, 0xA4, 0x78, 0x26, 0xA8, 0x33, 0xE1} } },
365         { .efi_guid_name = "Active EDID",
366 	    .efi_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID },
367         { .efi_guid_name = "Discovered EDID",
368 	    .efi_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID }
369 };
370 
371 bool
efi_guid_to_str(const EFI_GUID * guid,char ** sp)372 efi_guid_to_str(const EFI_GUID *guid, char **sp)
373 {
374 	uint32_t status;
375 
376 	uuid_to_string((const uuid_t *)guid, sp, &status);
377 	return (status == uuid_s_ok ? true : false);
378 }
379 
380 bool
efi_str_to_guid(const char * s,EFI_GUID * guid)381 efi_str_to_guid(const char *s, EFI_GUID *guid)
382 {
383 	uint32_t status;
384 
385 	uuid_from_string(s, (uuid_t *)guid, &status);
386 	return (status == uuid_s_ok ? true : false);
387 }
388 
389 bool
efi_name_to_guid(const char * name,EFI_GUID * guid)390 efi_name_to_guid(const char *name, EFI_GUID *guid)
391 {
392 	uint32_t i;
393 
394 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
395 		if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) {
396 			*guid = efi_uuid_mapping[i].efi_guid;
397 			return (true);
398 		}
399 	}
400 	return (efi_str_to_guid(name, guid));
401 }
402 
403 bool
efi_guid_to_name(EFI_GUID * guid,char ** name)404 efi_guid_to_name(EFI_GUID *guid, char **name)
405 {
406 	uint32_t i;
407 	int rv;
408 
409 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
410 		rv = uuid_equal((uuid_t *)guid,
411 		    (uuid_t *)&efi_uuid_mapping[i].efi_guid, NULL);
412 		if (rv != 0) {
413 			*name = strdup(efi_uuid_mapping[i].efi_guid_name);
414 			if (*name == NULL)
415 				return (false);
416 			return (true);
417 		}
418 	}
419 	return (efi_guid_to_str(guid, name));
420 }
421 
422 void
efi_init_environment(void)423 efi_init_environment(void)
424 {
425 	char var[128];
426 
427 	snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
428 	    ST->Hdr.Revision & 0xffff);
429 	env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
430 }
431 
432 COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
433 
434 static int
efi_print_other_value(uint8_t * data,UINTN datasz)435 efi_print_other_value(uint8_t *data, UINTN datasz)
436 {
437 	UINTN i;
438 	bool is_ascii = true;
439 
440 	printf(" = ");
441 	for (i = 0; i < datasz - 1; i++) {
442 		/*
443 		 * Quick hack to see if this ascii-ish string is printable
444 		 * range plus tab, cr and lf.
445 		 */
446 		if ((data[i] < 32 || data[i] > 126)
447 		    && data[i] != 9 && data[i] != 10 && data[i] != 13) {
448 			is_ascii = false;
449 			break;
450 		}
451 	}
452 	if (data[datasz - 1] != '\0')
453 		is_ascii = false;
454 	if (is_ascii == true) {
455 		printf("%s", data);
456 		if (pager_output("\n"))
457 			return (CMD_WARN);
458 	} else {
459 		if (pager_output("\n"))
460 			return (CMD_WARN);
461 		/*
462 		 * Dump hex bytes grouped by 4.
463 		 */
464 		for (i = 0; i < datasz; i++) {
465 			printf("%02x ", data[i]);
466 			if ((i + 1) % 4 == 0)
467 				printf(" ");
468 			if ((i + 1) % 20 == 0) {
469 				if (pager_output("\n"))
470 					return (CMD_WARN);
471 			}
472 		}
473 		if (pager_output("\n"))
474 			return (CMD_WARN);
475 	}
476 
477 	return (CMD_OK);
478 }
479 
480 /* This appears to be some sort of UEFI shell alias table. */
481 static int
efi_print_shell_str(const CHAR16 * varnamearg __unused,uint8_t * data,UINTN datasz __unused)482 efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data,
483     UINTN datasz __unused)
484 {
485 	printf(" = %S", (CHAR16 *)data);
486 	if (pager_output("\n"))
487 		return (CMD_WARN);
488 	return (CMD_OK);
489 }
490 
491 const char *
efi_memory_type(EFI_MEMORY_TYPE type)492 efi_memory_type(EFI_MEMORY_TYPE type)
493 {
494 	const char *types[] = {
495 	    "Reserved",
496 	    "LoaderCode",
497 	    "LoaderData",
498 	    "BootServicesCode",
499 	    "BootServicesData",
500 	    "RuntimeServicesCode",
501 	    "RuntimeServicesData",
502 	    "ConventionalMemory",
503 	    "UnusableMemory",
504 	    "ACPIReclaimMemory",
505 	    "ACPIMemoryNVS",
506 	    "MemoryMappedIO",
507 	    "MemoryMappedIOPortSpace",
508 	    "PalCode",
509 	    "PersistentMemory"
510 	};
511 
512 	switch (type) {
513 	case EfiReservedMemoryType:
514 	case EfiLoaderCode:
515 	case EfiLoaderData:
516 	case EfiBootServicesCode:
517 	case EfiBootServicesData:
518 	case EfiRuntimeServicesCode:
519 	case EfiRuntimeServicesData:
520 	case EfiConventionalMemory:
521 	case EfiUnusableMemory:
522 	case EfiACPIReclaimMemory:
523 	case EfiACPIMemoryNVS:
524 	case EfiMemoryMappedIO:
525 	case EfiMemoryMappedIOPortSpace:
526 	case EfiPalCode:
527 	case EfiPersistentMemory:
528 		return (types[type]);
529 	default:
530 		return ("Unknown");
531 	}
532 }
533 
534 #if 0
535 /* Print memory type table. */
536 static int
537 efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
538     UINTN datasz)
539 {
540 	int i, n;
541 	EFI_MEMORY_TYPE_INFORMATION *ti;
542 
543 	ti = (EFI_MEMORY_TYPE_INFORMATION *)data;
544 	if (pager_output(" = \n"))
545 		return (CMD_WARN);
546 
547 	n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION);
548 	for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) {
549 		printf("\t%23s pages: %u", efi_memory_type(ti[i].Type),
550 		    ti[i].NumberOfPages);
551 		if (pager_output("\n"))
552 			return (CMD_WARN);
553 	}
554 
555 	return (CMD_OK);
556 }
557 #endif
558 
559 /*
560  * Print FreeBSD variables.
561  * We have LoaderPath and LoaderDev as CHAR16 strings.
562  */
563 static int
efi_print_freebsd(const CHAR16 * varnamearg,uint8_t * data,UINTN datasz __unused)564 efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
565     UINTN datasz __unused)
566 {
567 	int rv = -1;
568 	char *var = NULL;
569 
570 	if (ucs2_to_utf8(varnamearg, &var) != 0)
571 		return (CMD_ERROR);
572 
573 	if (strcmp("LoaderPath", var) == 0 ||
574 	    strcmp("LoaderDev", var) == 0) {
575 		printf(" = ");
576 		printf("%S", (CHAR16 *)data);
577 
578 		if (pager_output("\n"))
579 			rv = CMD_WARN;
580 		else
581 			rv = CMD_OK;
582 	}
583 
584 	free(var);
585 	return (rv);
586 }
587 
588 /* Print global variables. */
589 static int
efi_print_global(const CHAR16 * varnamearg,uint8_t * data,UINTN datasz)590 efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz)
591 {
592 	int rv = -1;
593 	char *var = NULL;
594 
595 	if (ucs2_to_utf8(varnamearg, &var) != 0)
596 		return (CMD_ERROR);
597 
598 	if (strcmp("AuditMode", var) == 0) {
599 		printf(" = ");
600 		printf("0x%x", *data);	/* 8-bit int */
601 		goto done;
602 	}
603 
604 	if (strcmp("BootOptionSupport", var) == 0) {
605 		printf(" = ");
606 		printf("0x%x", *((uint32_t *)data));	/* UINT32 */
607 		goto done;
608 	}
609 
610 	if (strcmp("BootCurrent", var) == 0 ||
611 	    strcmp("BootNext", var) == 0 ||
612 	    strcmp("Timeout", var) == 0) {
613 		printf(" = ");
614 		printf("%u", *((uint16_t *)data));	/* UINT16 */
615 		goto done;
616 	}
617 
618 	if (strcmp("BootOrder", var) == 0 ||
619 	    strcmp("DriverOrder", var) == 0) {
620 		UINTN i;
621 		UINT16 *u16 = (UINT16 *)data;
622 
623 		printf(" =");
624 		for (i = 0; i < datasz / sizeof (UINT16); i++)
625 			printf(" %u", u16[i]);
626 		goto done;
627 	}
628 	if (strncmp("Boot", var, 4) == 0 ||
629 	    strncmp("Driver", var, 6) == 0 ||
630 	    strncmp("SysPrep", var, 7) == 0 ||
631 	    strncmp("OsRecovery", var, 10) == 0) {
632 		UINT16 filepathlistlen;
633 		CHAR16 *text;
634 		int desclen;
635 		EFI_DEVICE_PATH *dp;
636 
637 		data += sizeof(UINT32);
638 		filepathlistlen = *(uint16_t *)data;
639 		data += sizeof (UINT16);
640 		text = (CHAR16 *)data;
641 
642 		for (desclen = 0; text[desclen] != 0; desclen++)
643 			;
644 		if (desclen != 0) {
645 			/* Add terminating zero and we have CHAR16. */
646 			desclen = (desclen + 1) * 2;
647 		}
648 
649 		printf(" = ");
650 		printf("%S", text);
651 		if (filepathlistlen != 0) {
652 			/* Output pathname from new line. */
653 			if (pager_output("\n")) {
654 				rv = CMD_WARN;
655 				goto done;
656 			}
657 			dp = malloc(filepathlistlen);
658 			if (dp == NULL)
659 				goto done;
660 
661 			memcpy(dp, data + desclen, filepathlistlen);
662 			text = efi_devpath_name(dp);
663 			if (text != NULL) {
664 				printf("\t%S", text);
665 				efi_free_devpath_name(text);
666 			}
667 			free(dp);
668 		}
669 		goto done;
670 	}
671 
672 	if (strcmp("ConIn", var) == 0 ||
673 	    strcmp("ConInDev", var) == 0 ||
674 	    strcmp("ConOut", var) == 0 ||
675 	    strcmp("ConOutDev", var) == 0 ||
676 	    strcmp("ErrOut", var) == 0 ||
677 	    strcmp("ErrOutDev", var) == 0) {
678 		CHAR16 *text;
679 
680 		printf(" = ");
681 		text = efi_devpath_name((EFI_DEVICE_PATH *)data);
682 		if (text != NULL) {
683 			printf("%S", text);
684 			efi_free_devpath_name(text);
685 		}
686 		goto done;
687 	}
688 
689 	if (strcmp("PlatformLang", var) == 0 ||
690 	    strcmp("PlatformLangCodes", var) == 0 ||
691 	    strcmp("LangCodes", var) == 0 ||
692 	    strcmp("Lang", var) == 0) {
693 		printf(" = ");
694 		printf("%s", data);	/* ASCII string */
695 		goto done;
696 	}
697 
698 	/*
699 	 * Feature bitmap from firmware to OS.
700 	 * Older UEFI provides UINT32, newer UINT64.
701 	 */
702 	if (strcmp("OsIndicationsSupported", var) == 0) {
703 		printf(" = ");
704 		if (datasz == 4)
705 			printf("0x%x", *((uint32_t *)data));
706 		else
707 			printf("0x%jx", *((uint64_t *)data));
708 		goto done;
709 	}
710 
711 	/* Fallback for anything else. */
712 	rv = efi_print_other_value(data, datasz);
713 done:
714 	if (rv == -1) {
715 		if (pager_output("\n"))
716 			rv = CMD_WARN;
717 		else
718 			rv = CMD_OK;
719 	}
720 	free(var);
721 	return (rv);
722 }
723 
724 static void
efi_print_var_attr(UINT32 attr)725 efi_print_var_attr(UINT32 attr)
726 {
727 	bool comma = false;
728 
729 	if (attr & EFI_VARIABLE_NON_VOLATILE) {
730 		printf("NV");
731 		comma = true;
732 	}
733 	if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
734 		if (comma == true)
735 			printf(",");
736 		printf("BS");
737 		comma = true;
738 	}
739 	if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
740 		if (comma == true)
741 			printf(",");
742 		printf("RS");
743 		comma = true;
744 	}
745 	if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
746 		if (comma == true)
747 			printf(",");
748 		printf("HR");
749 		comma = true;
750 	}
751 	if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
752 		if (comma == true)
753 			printf(",");
754 		printf("AT");
755 		comma = true;
756 	}
757 }
758 
759 static int
efi_print_var(CHAR16 * varnamearg,EFI_GUID * matchguid,int lflag)760 efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
761 {
762 	UINTN		datasz;
763 	EFI_STATUS	status;
764 	UINT32		attr;
765 	char		*str;
766 	uint8_t		*data;
767 	int		rv = CMD_OK;
768 
769 	str = NULL;
770 	datasz = 0;
771 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL);
772 	if (status != EFI_BUFFER_TOO_SMALL) {
773 		printf("Can't get the variable: error %#lx\n",
774 		    DECODE_ERROR(status));
775 		return (CMD_ERROR);
776 	}
777 	data = malloc(datasz);
778 	if (data == NULL) {
779 		printf("Out of memory\n");
780 		return (CMD_ERROR);
781 	}
782 
783 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data);
784 	if (status != EFI_SUCCESS) {
785 		printf("Can't get the variable: error %#lx\n",
786 		    DECODE_ERROR(status));
787 		free(data);
788 		return (CMD_ERROR);
789 	}
790 
791 	if (efi_guid_to_name(matchguid, &str) == false) {
792 		rv = CMD_ERROR;
793 		goto done;
794 	}
795 	printf("%s ", str);
796 	efi_print_var_attr(attr);
797 	printf(" %S", varnamearg);
798 
799 	if (lflag == 0) {
800 		if (strcmp(str, "global") == 0)
801 			rv = efi_print_global(varnamearg, data, datasz);
802 		else if (strcmp(str, "freebsd") == 0)
803 			rv = efi_print_freebsd(varnamearg, data, datasz);
804 		else if (strcmp(str,
805 		    "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0)
806 			rv = efi_print_shell_str(varnamearg, data, datasz);
807 #if 0
808 		else if (strcmp(str,
809 		    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0)
810 			rv = efi_print_mem_type(varnamearg, data, datasz);
811 		else if (strcmp(str, MTC_VARIABLE_NAME) == 0) {
812 			printf(" = ");
813 			printf("%u", *((uint32_t *)data));	/* UINT32 */
814 			rv = CMD_OK;
815 			if (pager_output("\n"))
816 				rv = CMD_WARN;
817 		}
818 #endif
819 		else
820 			rv = efi_print_other_value(data, datasz);
821 	} else if (pager_output("\n"))
822 		rv =  CMD_WARN;
823 
824 done:
825 	free(str);
826 	free(data);
827 	return (rv);
828 }
829 
830 static int
command_efi_show(int argc,char * argv[])831 command_efi_show(int argc, char *argv[])
832 {
833 	/*
834 	 * efi-show [-a]
835 	 *	print all the env
836 	 * efi-show -g UUID
837 	 *	print all the env vars tagged with UUID
838 	 * efi-show -v var
839 	 *	search all the env vars and print the ones matching var
840 	 * efi-show -g UUID -v var
841 	 * efi-show UUID var
842 	 *	print all the env vars that match UUID and var
843 	 */
844 	/* NB: We assume EFI_GUID is the same as uuid_t */
845 	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
846 	int		ch, rv;
847 	unsigned	i;
848 	EFI_STATUS	status;
849 	EFI_GUID	varguid = ZERO_GUID;
850 	EFI_GUID	matchguid = ZERO_GUID;
851 	CHAR16		*varname;
852 	CHAR16		*newnm;
853 	CHAR16		varnamearg[128];
854 	UINTN		varalloc;
855 	UINTN		varsz;
856 
857 	optind = 1;
858 	optreset = 1;
859 	opterr = 1;
860 
861 	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
862 		switch (ch) {
863 		case 'a':
864 			aflag = 1;
865 			break;
866 		case 'g':
867 			gflag = 1;
868 			if (efi_name_to_guid(optarg, &matchguid) == false) {
869 				printf("uuid %s could not be parsed\n", optarg);
870 				return (CMD_ERROR);
871 			}
872 			break;
873 		case 'l':
874 			lflag = 1;
875 			break;
876 		case 'v':
877 			vflag = 1;
878 			if (strlen(optarg) >= nitems(varnamearg)) {
879 				printf("Variable %s is longer than %zu "
880 				    "characters\n", optarg, nitems(varnamearg));
881 				return (CMD_ERROR);
882 			}
883 			cpy8to16(optarg, varnamearg, nitems(varnamearg));
884 			break;
885 		default:
886 			return (CMD_ERROR);
887 		}
888 	}
889 
890 	if (argc == 1)		/* default is -a */
891 		aflag = 1;
892 
893 	if (aflag && (gflag || vflag)) {
894 		printf("-a isn't compatible with -g or -v\n");
895 		return (CMD_ERROR);
896 	}
897 
898 	if (aflag && optind < argc) {
899 		printf("-a doesn't take any args\n");
900 		return (CMD_ERROR);
901 	}
902 
903 	argc -= optind;
904 	argv += optind;
905 
906 	pager_open();
907 	if (vflag && gflag) {
908 		rv = efi_print_var(varnamearg, &matchguid, lflag);
909 		if (rv == CMD_WARN)
910 			rv = CMD_OK;
911 		pager_close();
912 		return (rv);
913 	}
914 
915 	if (argc == 2) {
916 		optarg = argv[0];
917 		if (strlen(optarg) >= nitems(varnamearg)) {
918 			printf("Variable %s is longer than %zu characters\n",
919 			    optarg, nitems(varnamearg));
920 			pager_close();
921 			return (CMD_ERROR);
922 		}
923 		for (i = 0; i < strlen(optarg); i++)
924 			varnamearg[i] = optarg[i];
925 		varnamearg[i] = 0;
926 		optarg = argv[1];
927 		if (efi_name_to_guid(optarg, &matchguid) == false) {
928 			printf("uuid %s could not be parsed\n", optarg);
929 			pager_close();
930 			return (CMD_ERROR);
931 		}
932 		rv = efi_print_var(varnamearg, &matchguid, lflag);
933 		if (rv == CMD_WARN)
934 			rv = CMD_OK;
935 		pager_close();
936 		return (rv);
937 	}
938 
939 	if (argc > 0) {
940 		printf("Too many args: %d\n", argc);
941 		pager_close();
942 		return (CMD_ERROR);
943 	}
944 
945 	/*
946 	 * Initiate the search -- note the standard takes pain
947 	 * to specify the initial call must be a poiner to a NULL
948 	 * character.
949 	 */
950 	varalloc = 1024;
951 	varname = malloc(varalloc);
952 	if (varname == NULL) {
953 		printf("Can't allocate memory to get variables\n");
954 		pager_close();
955 		return (CMD_ERROR);
956 	}
957 	varname[0] = 0;
958 	while (1) {
959 		varsz = varalloc;
960 		status = RS->GetNextVariableName(&varsz, varname, &varguid);
961 		if (status == EFI_BUFFER_TOO_SMALL) {
962 			varalloc = varsz;
963 			newnm = realloc(varname, varalloc);
964 			if (newnm == NULL) {
965 				printf("Can't allocate memory to get "
966 				    "variables\n");
967 				rv = CMD_ERROR;
968 				break;
969 			}
970 			varname = newnm;
971 			continue; /* Try again with bigger buffer */
972 		}
973 		if (status == EFI_NOT_FOUND) {
974 			rv = CMD_OK;
975 			break;
976 		}
977 		if (status != EFI_SUCCESS) {
978 			rv = CMD_ERROR;
979 			break;
980 		}
981 
982 		if (aflag) {
983 			rv = efi_print_var(varname, &varguid, lflag);
984 			if (rv != CMD_OK) {
985 				if (rv == CMD_WARN)
986 					rv = CMD_OK;
987 				break;
988 			}
989 			continue;
990 		}
991 		if (vflag) {
992 			if (wcscmp(varnamearg, varname) == 0) {
993 				rv = efi_print_var(varname, &varguid, lflag);
994 				if (rv != CMD_OK) {
995 					if (rv == CMD_WARN)
996 						rv = CMD_OK;
997 					break;
998 				}
999 				continue;
1000 			}
1001 		}
1002 		if (gflag) {
1003 			rv = uuid_equal((uuid_t *)&varguid,
1004 			    (uuid_t *)&matchguid, NULL);
1005 			if (rv != 0) {
1006 				rv = efi_print_var(varname, &varguid, lflag);
1007 				if (rv != CMD_OK) {
1008 					if (rv == CMD_WARN)
1009 						rv = CMD_OK;
1010 					break;
1011 				}
1012 				continue;
1013 			}
1014 		}
1015 	}
1016 	free(varname);
1017 	pager_close();
1018 
1019 	return (rv);
1020 }
1021 
1022 COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
1023 
1024 static int
command_efi_set(int argc,char * argv[])1025 command_efi_set(int argc, char *argv[])
1026 {
1027 	char *uuid, *var, *val;
1028 	CHAR16 wvar[128];
1029 	EFI_GUID guid;
1030 #if defined(ENABLE_UPDATES)
1031 	EFI_STATUS err;
1032 #endif
1033 
1034 	if (argc != 4) {
1035 		printf("efi-set uuid var new-value\n");
1036 		return (CMD_ERROR);
1037 	}
1038 	uuid = argv[1];
1039 	var = argv[2];
1040 	val = argv[3];
1041 	if (efi_name_to_guid(uuid, &guid) == false) {
1042 		printf("Invalid uuid %s\n", uuid);
1043 		return (CMD_ERROR);
1044 	}
1045 	cpy8to16(var, wvar, nitems(wvar));
1046 #if defined(ENABLE_UPDATES)
1047 	err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE |
1048 	    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1049 	    strlen(val) + 1, val);
1050 	if (EFI_ERROR(err)) {
1051 		printf("Failed to set variable: error %lu\n",
1052 		    DECODE_ERROR(err));
1053 		return (CMD_ERROR);
1054 	}
1055 #else
1056 	printf("would set %s %s = %s\n", uuid, var, val);
1057 #endif
1058 	return (CMD_OK);
1059 }
1060 
1061 COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
1062 
1063 static int
command_efi_unset(int argc,char * argv[])1064 command_efi_unset(int argc, char *argv[])
1065 {
1066 	char *uuid, *var;
1067 	CHAR16 wvar[128];
1068 	EFI_GUID guid;
1069 #if defined(ENABLE_UPDATES)
1070 	EFI_STATUS err;
1071 #endif
1072 
1073 	if (argc != 3) {
1074 		printf("efi-unset uuid var\n");
1075 		return (CMD_ERROR);
1076 	}
1077 	uuid = argv[1];
1078 	var = argv[2];
1079 	if (efi_name_to_guid(uuid, &guid) == false) {
1080 		printf("Invalid uuid %s\n", uuid);
1081 		return (CMD_ERROR);
1082 	}
1083 	cpy8to16(var, wvar, nitems(wvar));
1084 #if defined(ENABLE_UPDATES)
1085 	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
1086 	if (EFI_ERROR(err)) {
1087 		printf("Failed to unset variable: error %lu\n",
1088 		    DECODE_ERROR(err));
1089 		return (CMD_ERROR);
1090 	}
1091 #else
1092 	printf("would unset %s %s \n", uuid, var);
1093 #endif
1094 	return (CMD_OK);
1095 }
1096