xref: /illumos-gate/usr/src/boot/efi/libefi/env.c (revision 7655c6d53c36750b508636f48c73a2de57754e5a)
1 /*
2  * Copyright (c) 2015 Netflix, Inc. All Rights Reserved.
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/cdefs.h>
27 
28 #include <stand.h>
29 #include <string.h>
30 #include <efi.h>
31 #include <efichar.h>
32 #include <efilib.h>
33 #include <eficonsctl.h>
34 #include <Guid/Acpi.h>
35 #include <Guid/ConsoleInDevice.h>
36 #include <Guid/ConsoleOutDevice.h>
37 #include <Guid/DebugImageInfoTable.h>
38 #include <Guid/DxeServices.h>
39 #include <Guid/Fdt.h>
40 #include <Guid/GlobalVariable.h>
41 #include <Guid/Gpt.h>
42 #include <Guid/HobList.h>
43 #include <Guid/MemoryTypeInformation.h>
44 #include <Guid/Mps.h>
45 #include <Guid/MtcVendor.h>
46 #include <Guid/SmBios.h>
47 #include <Guid/StandardErrorDevice.h>
48 #include <Guid/ZeroGuid.h>
49 #include <Pi/PiStatusCode.h>
50 #include <Protocol/AbsolutePointer.h>
51 #include <Protocol/AdapterInformation.h>
52 #include <Protocol/Arp.h>
53 #include <Protocol/AtaPassThru.h>
54 #include <Protocol/Bds.h>
55 #include <Protocol/BlockIo.h>
56 #include <Protocol/BlockIo2.h>
57 #include <Protocol/BusSpecificDriverOverride.h>
58 #include <Protocol/Capsule.h>
59 #include <Protocol/ComponentName.h>
60 #include <Protocol/ComponentName2.h>
61 #include <Protocol/Cpu.h>
62 #include <Protocol/CpuIo2.h>
63 #include <Protocol/DataHub.h>
64 #include <Protocol/Decompress.h>
65 #include <Protocol/DeviceIo.h>
66 #include <Protocol/DevicePath.h>
67 #include <Protocol/DevicePathFromText.h>
68 #include <Protocol/DevicePathToText.h>
69 #include <Protocol/DevicePathUtilities.h>
70 #include <Protocol/Dhcp4.h>
71 #include <Protocol/Dhcp6.h>
72 #include <Protocol/DiskInfo.h>
73 #include <Protocol/DiskIo.h>
74 #include <Protocol/DiskIo2.h>
75 #include <Protocol/Dpc.h>
76 #include <Protocol/DriverBinding.h>
77 #include <Protocol/DriverConfiguration.h>
78 #include <Protocol/DriverConfiguration2.h>
79 #include <Protocol/DriverDiagnostics.h>
80 #include <Protocol/DriverDiagnostics2.h>
81 #include <Protocol/DriverFamilyOverride.h>
82 #include <Protocol/DriverHealth.h>
83 #include <Protocol/DriverSupportedEfiVersion.h>
84 #include <Protocol/Ebc.h>
85 #include <Protocol/EdidActive.h>
86 #include <Protocol/EdidDiscovered.h>
87 #include <Pi/PiFirmwareVolume.h>
88 #include <Protocol/FirmwareVolumeBlock.h>
89 #include <Uefi/UefiInternalFormRepresentation.h>
90 #include <Protocol/FormBrowser2.h>
91 #include <Protocol/GraphicsOutput.h>
92 #include <Protocol/HiiConfigAccess.h>
93 #include <Protocol/HiiConfigKeyword.h>
94 #include <Protocol/HiiConfigRouting.h>
95 #include <Protocol/HiiFont.h>
96 #include <Protocol/HiiImage.h>
97 #include <Protocol/HiiDatabase.h>
98 #include <Protocol/HiiString.h>
99 #include <Protocol/IdeControllerInit.h>
100 #include <Protocol/Ip4.h>
101 #include <Protocol/Ip4Config.h>
102 #include <Protocol/Ip4Config2.h>
103 #include <Protocol/Ip6.h>
104 #include <Protocol/Ip6Config.h>
105 #include <Protocol/IpSec.h>
106 #include <Protocol/IpSecConfig.h>
107 #include <Protocol/IsaAcpi.h>
108 #include <Protocol/IsaIo.h>
109 #include <Protocol/Kms.h>
110 #include <Protocol/Legacy8259.h>
111 #include <Protocol/LoadFile.h>
112 #include <Protocol/LoadFile2.h>
113 #include <Protocol/Metronome.h>
114 #include <Protocol/MonotonicCounter.h>
115 #include <Pi/PiMultiPhase.h>
116 #include <Protocol/MpService.h>
117 #include <Protocol/Mtftp4.h>
118 #include <Protocol/Mtftp6.h>
119 #include <Protocol/NetworkInterfaceIdentifier.h>
120 #include <Protocol/NvmExpressPassthru.h>
121 #include <Protocol/PciIo.h>
122 #include <Protocol/Pcd.h>
123 #include <Protocol/PciEnumerationComplete.h>
124 #include <Protocol/PciRootBridgeIo.h>
125 #include <Protocol/PiPcd.h>
126 #include <Protocol/PlatformDriverOverride.h>
127 #include <Protocol/PlatformToDriverConfiguration.h>
128 #include <Protocol/Print2.h>
129 #include <Protocol/PxeBaseCode.h>
130 #include <Protocol/PxeBaseCodeCallBack.h>
131 #include <Protocol/RealTimeClock.h>
132 #include <Protocol/ReportStatusCodeHandler.h>
133 #include <Protocol/Reset.h>
134 #include <Protocol/Rng.h>
135 #include <Protocol/Runtime.h>
136 #include <Protocol/ScsiIo.h>
137 #include <Protocol/ScsiPassThru.h>
138 #include <Protocol/ScsiPassThruExt.h>
139 #include <Protocol/Security.h>
140 #include <Protocol/Security2.h>
141 #include <Protocol/SecurityPolicy.h>
142 #include <Protocol/SerialIo.h>
143 #include <Protocol/SimpleFileSystem.h>
144 #include <Protocol/SimplePointer.h>
145 #include <Protocol/SimpleTextIn.h>
146 #include <Protocol/SimpleTextInEx.h>
147 #include <Protocol/SimpleTextOut.h>
148 #include <Protocol/SmartCardReader.h>
149 #include <Protocol/StatusCode.h>
150 #include <Protocol/StorageSecurityCommand.h>
151 #include <Protocol/Tcg2Protocol.h>
152 #include <Protocol/Tcp4.h>
153 #include <Protocol/Tcp6.h>
154 #include <Protocol/Timer.h>
155 #include <Protocol/Udp4.h>
156 #include <Protocol/Udp6.h>
157 #include <Protocol/UgaDraw.h>
158 #include <Protocol/UgaIo.h>
159 #include <Protocol/UnicodeCollation.h>
160 #include <Protocol/UsbIo.h>
161 #include <Protocol/Usb2HostController.h>
162 #include <Protocol/Variable.h>
163 #include <Protocol/VariableWrite.h>
164 #include <Protocol/VlanConfig.h>
165 #include <Protocol/WatchdogTimer.h>
166 #include <Protocol/IsaAcpi.h>
167 #include <Protocol/IsaIo.h>
168 #include <Protocol/SerialIo.h>
169 #include <Protocol/SuperIo.h>
170 #include <uuid.h>
171 #include <stdbool.h>
172 #include <sys/param.h>
173 #include "bootstrap.h"
174 #include "ficl.h"
175 
176 /*
177  * About ENABLE_UPDATES
178  *
179  * The UEFI variables are identified only by GUID and name, there is no
180  * way to (auto)detect the type for the value, so we need to process the
181  * variables case by case, as we do learn about them.
182  *
183  * While showing the variable name and the value is safe, we must not store
184  * random values nor allow removing (random) variables.
185  *
186  * Since we do have stub code to set/unset the variables, I do want to keep
187  * it to make the future development a bit easier, but the updates are disabled
188  * by default till:
189  *	a) the validation and data translation to values is properly implemented
190  *	b) We have established which variables we do allow to be updated.
191  * Therefore the set/unset code is included only for developers aid.
192  */
193 
194 /* If GUID is not defined elsewhere, define it here. */
195 EFI_GUID gEfiAbsolutePointerProtocolGuid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID;
196 EFI_GUID gEfiAdapterInformationProtocolGuid =
197     EFI_ADAPTER_INFORMATION_PROTOCOL_GUID;
198 EFI_GUID gEfiAtaPassThruProtocolGuid = EFI_ATA_PASS_THRU_PROTOCOL_GUID;
199 EFI_GUID gEfiBdsArchProtocolGuid = EFI_BDS_ARCH_PROTOCOL_GUID;
200 EFI_GUID gEfiBusSpecificDriverOverrideProtocolGuid =
201     EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID;
202 EFI_GUID gEfiCapsuleArchProtocolGuid = EFI_CAPSULE_ARCH_PROTOCOL_GUID;
203 EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID;
204 EFI_GUID gEfiComponentName2ProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
205 EFI_GUID gEfiCpuArchProtocolGuid = EFI_CPU_ARCH_PROTOCOL_GUID;
206 EFI_GUID gEfiCpuIo2ProtocolGuid = EFI_CPU_IO2_PROTOCOL_GUID;
207 EFI_GUID gEfiDataHubProtocolGuid = EFI_DATA_HUB_PROTOCOL_GUID;
208 EFI_GUID gEfiDebugImageInfoTableGuid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
209 EFI_GUID gEfiDecompressProtocolGuid = EFI_DECOMPRESS_PROTOCOL_GUID;
210 EFI_GUID gEfiDeviceIoProtocolGuid = EFI_DEVICE_IO_PROTOCOL_GUID;
211 EFI_GUID gEfiDhcp4ProtocolGuid = EFI_DHCP4_PROTOCOL_GUID;
212 EFI_GUID gEfiDhcp4ServiceBindingProtocolGuid =
213     EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
214 EFI_GUID gEfiDhcp6ProtocolGuid = EFI_DHCP4_PROTOCOL_GUID;
215 EFI_GUID gEfiDhcp6ServiceBindingProtocolGuid =
216     EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
217 EFI_GUID gEfiDiskInfoProtocolGuid = EFI_DISK_INFO_PROTOCOL_GUID;
218 EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID;
219 EFI_GUID gEfiDiskIo2ProtocolGuid = EFI_DISK_IO2_PROTOCOL_GUID;
220 EFI_GUID gEfiDpcProtocolGuid = EFI_DPC_PROTOCOL_GUID;
221 EFI_GUID gEfiDriverConfigurationProtocolGuid =
222     EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID;
223 EFI_GUID gEfiDriverConfiguration2ProtocolGuid =
224     EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID;
225 EFI_GUID gEfiDriverDiagnosticsProtocolGuid =
226     EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID;
227 EFI_GUID gEfiDriverDiagnostics2ProtocolGuid =
228     EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID;
229 EFI_GUID gEfiDriverFamilyOverrideProtocolGuid =
230     EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL_GUID;
231 EFI_GUID gEfiDriverHealthProtocolGuid =
232     EFI_DRIVER_HEALTH_PROTOCOL_GUID;
233 EFI_GUID gEfiDriverSupportedEfiVersionProtocolGuid =
234     EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL_GUID;
235 EFI_GUID gEfiDxeServicesTableGuid = DXE_SERVICES_TABLE_GUID;
236 EFI_GUID gEfiEbcProtocolGuid = EFI_EBC_INTERPRETER_PROTOCOL_GUID;
237 EFI_GUID gEfiFormBrowser2ProtocolGuid = EFI_FORM_BROWSER2_PROTOCOL_GUID;
238 EFI_GUID gEfiFirmwareVolumeBlockProtocolGuid =
239     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID;
240 EFI_GUID gEfiFirmwareVolumeBlock2ProtocolGuid =
241     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL_GUID;
242 EFI_GUID gEfiHiiConfigAccessProtocolGuid = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
243 EFI_GUID gEfiConfigKeywordHandlerProtocolGuid =
244     EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL_GUID;
245 EFI_GUID gEfiHiiConfigRoutingProtocolGuid =
246     EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID;
247 EFI_GUID gEfiHiiFontProtocolGuid = EFI_HII_FONT_PROTOCOL_GUID;
248 EFI_GUID gEfiHiiImageProtocolGuid = EFI_HII_IMAGE_PROTOCOL_GUID;
249 EFI_GUID gEfiHiiStringProtocolGuid = EFI_HII_STRING_PROTOCOL_GUID;
250 EFI_GUID gEfiHiiDatabaseProtocolGuid = EFI_HII_DATABASE_PROTOCOL_GUID;
251 EFI_GUID gEfiHobListGuid = HOB_LIST_GUID;
252 EFI_GUID gEfiIdeControllerInitProtocolGuid =
253     EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID;
254 EFI_GUID gEfiIp4ProtocolGuid = EFI_IP4_PROTOCOL_GUID;
255 EFI_GUID gEfiIp4ServiceBindingProtocolGuid =
256     EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID;
257 EFI_GUID gEfiIp4ConfigProtocolGuid = EFI_IP4_CONFIG_PROTOCOL_GUID;
258 EFI_GUID gEfiIp4Config2ProtocolGuid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
259 EFI_GUID gEfiIp6ProtocolGuid = EFI_IP6_PROTOCOL_GUID;
260 EFI_GUID gEfiIp6ServiceBindingProtocolGuid =
261     EFI_IP6_SERVICE_BINDING_PROTOCOL_GUID;
262 EFI_GUID gEfiIp6ConfigProtocolGuid = EFI_IP6_CONFIG_PROTOCOL_GUID;
263 EFI_GUID gEfiIpSecProtocolGuid = EFI_IPSEC_PROTOCOL_GUID;
264 EFI_GUID gEfiIpSec2ProtocolGuid = EFI_IPSEC2_PROTOCOL_GUID;
265 EFI_GUID gEfiIpSecConfigProtocolGuid = EFI_IPSEC_CONFIG_PROTOCOL_GUID;
266 EFI_GUID gEfiIsaAcpiProtocolGuid = EFI_ISA_ACPI_PROTOCOL_GUID;
267 EFI_GUID gEfiKmsProtocolGuid = EFI_KMS_PROTOCOL_GUID;
268 EFI_GUID gEfiLegacy8259ProtocolGuid = EFI_LEGACY_8259_PROTOCOL_GUID;
269 EFI_GUID gEfiLoadFileProtocolGuid = EFI_LOAD_FILE_PROTOCOL_GUID;
270 EFI_GUID gEfiLoadFile2ProtocolGuid = EFI_LOAD_FILE2_PROTOCOL_GUID;
271 EFI_GUID gEfiManagedNetworkProtocolGuid = EFI_MANAGED_NETWORK_PROTOCOL_GUID;
272 EFI_GUID gEfiManagedNetworkServiceBindingProtocolGuid =
273     EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID;
274 EFI_GUID gEfiMemoryTypeInformationGuid = EFI_MEMORY_TYPE_INFORMATION_GUID;
275 EFI_GUID gEfiMetronomeArchProtocolGuid = EFI_METRONOME_ARCH_PROTOCOL_GUID;
276 EFI_GUID gEfiMonotonicCounterArchProtocolGuid =
277     EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID;
278 EFI_GUID gEfiMpServiceProtocolGuid = EFI_MP_SERVICES_PROTOCOL_GUID;
279 EFI_GUID gEfiMpsTableGuid = MPS_TABLE_GUID;
280 EFI_GUID gEfiMtftp4ProtocolGuid = EFI_MTFTP4_PROTOCOL_GUID;
281 EFI_GUID gEfiMtftp4ServiceBindingProtocolGuid =
282     EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID;
283 EFI_GUID gEfiMtftp6ProtocolGuid = EFI_MTFTP6_PROTOCOL_GUID;
284 EFI_GUID gEfiMtftp6ServiceBindingProtocolGuid =
285     EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID;
286 EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid =
287     EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
288 EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31 =
289     EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID_31;
290 EFI_GUID gEfiNvmExpressPassThruProtocolGuid =
291     EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL_GUID;
292 EFI_GUID gEfiPartTypeLegacyMbrGuid = EFI_PART_TYPE_LEGACY_MBR_GUID;
293 EFI_GUID gEfiPartTypeSystemPartGuid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID;
294 EFI_GUID gEfiPcdProtocolGuid = EFI_PCD_PROTOCOL_GUID;
295 EFI_GUID gEfiPciEnumerationCompleteProtocolGuid =
296     EFI_PCI_ENUMERATION_COMPLETE_GUID;
297 EFI_GUID gEfiPciRootBridgeIoProtocolGuid =
298     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID;
299 EFI_GUID gEfiPlatformDriverOverrideProtocolGuid =
300     EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL_GUID;
301 EFI_GUID gEfiPlatformToDriverConfigurationProtocolGuid =
302     EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID;
303 EFI_GUID gEfiPrint2SProtocolGuid = EFI_PRINT2_PROTOCOL_GUID;
304 EFI_GUID gEfiPxeBaseCodeProtocolGuid = EFI_PXE_BASE_CODE_PROTOCOL_GUID;
305 EFI_GUID gEfiPxeBaseCodeCallbackProtocolGuid =
306     EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_GUID;
307 EFI_GUID gEfiRealTimeClockArchProtocolGuid =
308     EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL_GUID;
309 EFI_GUID gEfiResetArchProtocolGuid = EFI_RESET_ARCH_PROTOCOL_GUID;
310 EFI_GUID gEfiRngProtocolGuid = EFI_RNG_PROTOCOL_GUID;
311 EFI_GUID gEfiRuntimeArchProtocolGuid = EFI_RUNTIME_ARCH_PROTOCOL_GUID;
312 EFI_GUID gEfiScsiIoProtocolGuid = EFI_SCSI_IO_PROTOCOL_GUID;
313 EFI_GUID gEfiScsiPassThruProtocolGuid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID;
314 EFI_GUID gEfiExtScsiPassThruProtocolGuid =
315     EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID;
316 EFI_GUID gEfiSecurityArchProtocolGuid = EFI_SECURITY_ARCH_PROTOCOL_GUID;
317 EFI_GUID gEfiSecurity2ArchProtocolGuid = EFI_SECURITY2_ARCH_PROTOCOL_GUID;
318 EFI_GUID gEfiSecurityPolicyProtocolGuid = EFI_SECURITY_POLICY_PROTOCOL_GUID;
319 EFI_GUID gEfiSimpleFileSystemProtocolGuid =
320     EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
321 EFI_GUID gEfiSimplePointerProtocolGuid = EFI_SIMPLE_POINTER_PROTOCOL_GUID;
322 EFI_GUID gEfiSmartCardReaderProtocolGuid = EFI_SMART_CARD_READER_PROTOCOL_GUID;
323 EFI_GUID gEfiStatusCodeRuntimeProtocolGuid =
324     EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID;
325 EFI_GUID gEfiStorageSecurityCommandProtocolGuid =
326     EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID;
327 EFI_GUID gEfiTcg2ProtocolGuid = EFI_TCG2_PROTOCOL_GUID;
328 EFI_GUID gEfiTcp4ProtocolGuid = EFI_TCP4_PROTOCOL_GUID;
329 EFI_GUID gEfiTcp4ServiceBindingProtocolGuid =
330     EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID;
331 EFI_GUID gEfiTcp6ProtocolGuid = EFI_TCP6_PROTOCOL_GUID;
332 EFI_GUID gEfiTcp6ServiceBindingProtocolGuid =
333     EFI_TCP6_SERVICE_BINDING_PROTOCOL_GUID;
334 EFI_GUID gEfiTimerArchProtocolGuid = EFI_TIMER_ARCH_PROTOCOL_GUID;
335 EFI_GUID gEfiUdp4ProtocolGuid = EFI_UDP4_PROTOCOL_GUID;
336 EFI_GUID gEfiUdp4ServiceBindingProtocolGuid =
337     EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID;
338 EFI_GUID gEfiUdp6ProtocolGuid = EFI_UDP6_PROTOCOL_GUID;
339 EFI_GUID gEfiUdp6ServiceBindingProtocolGuid =
340     EFI_UDP6_SERVICE_BINDING_PROTOCOL_GUID;
341 EFI_GUID gEfiUnicodeCollationProtocolGuid = EFI_UNICODE_COLLATION_PROTOCOL_GUID;
342 EFI_GUID gEfiUnicodeCollation2ProtocolGuid =
343     EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
344 EFI_GUID gEfiUsbIoProtocolGuid = EFI_USB_IO_PROTOCOL_GUID;
345 EFI_GUID gEfiUsb2HcProtocolGuid = EFI_USB2_HC_PROTOCOL_GUID;
346 EFI_GUID gEfiVariableArchProtocolGuid = EFI_VARIABLE_ARCH_PROTOCOL_GUID;
347 EFI_GUID gEfiVariableWriteArchProtocolGuid =
348     EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID;
349 EFI_GUID gEfiWatchdogTimerArchProtocolGuid =
350     EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID;
351 EFI_GUID gFdtTableGuid = FDT_TABLE_GUID;
352 EFI_GUID gLzmaCompress = LZMA_COMPRESS_GUID;
353 EFI_GUID gMtcVendorGuid = MTC_VENDOR_GUID;
354 EFI_GUID gPcdProtocolGuid = PCD_PROTOCOL_GUID;
355 
356 static struct efi_uuid_mapping {
357 	const char *efi_guid_name;
358 	EFI_GUID *efi_guid;
359 } efi_uuid_mapping[] = {
360 	{ .efi_guid_name = "global",
361 	    .efi_guid = &gEfiGlobalVariableGuid },
362 	{ .efi_guid_name = "illumos",
363 	    .efi_guid = &gillumosBootVarGuid },
364 	/* EFI Systab entry names. */
365 	{ .efi_guid_name = "MPS Table",
366 	    .efi_guid = &gEfiMpsTableGuid },
367 	{ .efi_guid_name = "ACPI Table",
368 	    .efi_guid = &gEfiAcpiTableGuid },
369 	{ .efi_guid_name = "ACPI 2.0 Table",
370 	    .efi_guid = &gEfiAcpi20TableGuid },
371 	{ .efi_guid_name = "ATA pass thru",
372 	    .efi_guid = &gEfiAtaPassThruProtocolGuid },
373 	{ .efi_guid_name = "SMBIOS Table",
374 	    .efi_guid = &gEfiSmbiosTableGuid },
375 	{ .efi_guid_name = "SMBIOS3 Table",
376 	    .efi_guid = &gEfiSmbios3TableGuid },
377 	{ .efi_guid_name = "DXE Table",
378 	    .efi_guid = &gEfiDxeServicesTableGuid },
379 	{ .efi_guid_name = "HOB List Table",
380 	    .efi_guid = &gEfiHobListGuid },
381 	{ .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
382 	    .efi_guid = &gEfiMemoryTypeInformationGuid },
383 	{ .efi_guid_name = "Debug Image Info Table",
384 	    .efi_guid = &gEfiDebugImageInfoTableGuid },
385 	{ .efi_guid_name = "FDT Table",
386 	    .efi_guid = &gFdtTableGuid },
387 	/*
388 	 * Protocol names for debug purposes.
389 	 * Can be removed along with lsefi command.
390 	 */
391 	{ .efi_guid_name = "absolute pointer",
392 	    .efi_guid = &gEfiAbsolutePointerProtocolGuid },
393 	{ .efi_guid_name = "device path",
394 	    .efi_guid = &gEfiDevicePathProtocolGuid },
395 	{ .efi_guid_name = "block io",
396 	    .efi_guid = &gEfiBlockIoProtocolGuid },
397 	{ .efi_guid_name = "block io2",
398 	    .efi_guid = &gEfiBlockIo2ProtocolGuid },
399 	{ .efi_guid_name = "disk io",
400 	    .efi_guid = &gEfiDiskIoProtocolGuid },
401 	{ .efi_guid_name = "disk io2",
402 	    .efi_guid = &gEfiDiskIo2ProtocolGuid },
403 	{ .efi_guid_name = "disk info",
404 	    .efi_guid = &gEfiDiskInfoProtocolGuid },
405 	{ .efi_guid_name = "simple fs",
406 	    .efi_guid = &gEfiSimpleFileSystemProtocolGuid },
407 	{ .efi_guid_name = "load file",
408 	    .efi_guid = &gEfiLoadFileProtocolGuid },
409 	{ .efi_guid_name = "load file2",
410 	    .efi_guid = &gEfiLoadFile2ProtocolGuid },
411 	{ .efi_guid_name = "device io",
412 	    .efi_guid = &gEfiDeviceIoProtocolGuid },
413 	{ .efi_guid_name = "unicode collation",
414 	    .efi_guid = &gEfiUnicodeCollationProtocolGuid },
415 	{ .efi_guid_name = "unicode collation2",
416 	    .efi_guid = &gEfiUnicodeCollation2ProtocolGuid },
417 	{ .efi_guid_name = "simple network",
418 	    .efi_guid = &gEfiSimpleNetworkProtocolGuid },
419 	{ .efi_guid_name = "simple pointer",
420 	    .efi_guid = &gEfiSimplePointerProtocolGuid },
421 	{ .efi_guid_name = "simple text output",
422 	    .efi_guid = &gEfiSimpleTextOutProtocolGuid },
423 	{ .efi_guid_name = "simple text input",
424 	    .efi_guid = &gEfiSimpleTextInProtocolGuid },
425 	{ .efi_guid_name = "simple text ex input",
426 	    .efi_guid = &gEfiSimpleTextInputExProtocolGuid },
427 	{ .efi_guid_name = "console control",
428 	    .efi_guid = &gEfiConsoleControlProtocolGuid },
429 	{ .efi_guid_name = "stdin",
430 	    .efi_guid = &gEfiConsoleInDeviceGuid },
431 	{ .efi_guid_name = "stdout",
432 	    .efi_guid = &gEfiConsoleOutDeviceGuid },
433 	{ .efi_guid_name = "stderr",
434 	    .efi_guid = &gEfiStandardErrorDeviceGuid },
435 	{ .efi_guid_name = "GOP",
436 	    .efi_guid = &gEfiGraphicsOutputProtocolGuid },
437 	{ .efi_guid_name = "UGA draw",
438 	    .efi_guid = &gEfiUgaDrawProtocolGuid },
439 	{ .efi_guid_name = "UGA io",
440 	    .efi_guid = &gEfiUgaIoProtocolGuid },
441 	{ .efi_guid_name = "PXE base code",
442 	    .efi_guid = &gEfiPxeBaseCodeProtocolGuid },
443 	{ .efi_guid_name = "PXE base code callback",
444 	    .efi_guid = &gEfiPxeBaseCodeCallbackProtocolGuid },
445 	{ .efi_guid_name = "serial io",
446 	    .efi_guid = &gEfiSerialIoProtocolGuid },
447 	{ .efi_guid_name = "serial device type",
448 	    .efi_guid = &gEfiSerialTerminalDeviceTypeGuid },
449 	{ .efi_guid_name = "loaded image",
450 	    .efi_guid = &gEfiLoadedImageProtocolGuid },
451 	{ .efi_guid_name = "loaded image device path",
452 	    .efi_guid = &gEfiLoadedImageDevicePathProtocolGuid },
453 	{ .efi_guid_name = "ISA ACPI",
454 	    .efi_guid = &gEfiIsaAcpiProtocolGuid },
455 	{ .efi_guid_name = "ISA io",
456 	    .efi_guid = &gEfiIsaIoProtocolGuid },
457 	{ .efi_guid_name = "Super io", .efi_guid = &gEfiSioProtocolGuid },
458 	{ .efi_guid_name = "IDE controller init",
459 	    .efi_guid = &gEfiIdeControllerInitProtocolGuid },
460 	{ .efi_guid_name = "PCI",
461 	    .efi_guid = &gEfiPciIoProtocolGuid },
462 	{ .efi_guid_name = "PCI enumeration",
463 	    .efi_guid = &gEfiPciEnumerationCompleteProtocolGuid },
464 	{ .efi_guid_name = "PCI root bridge",
465 	    .efi_guid = &gEfiPciRootBridgeIoProtocolGuid },
466 	{ .efi_guid_name = "driver binding",
467 	    .efi_guid = &gEfiDriverBindingProtocolGuid },
468 	{ .efi_guid_name = "driver configuration",
469 	    .efi_guid = &gEfiDriverConfigurationProtocolGuid },
470 	{ .efi_guid_name = "driver configuration2",
471 	    .efi_guid = &gEfiDriverConfiguration2ProtocolGuid },
472 	{ .efi_guid_name = "driver diagnostics",
473 	    .efi_guid = &gEfiDriverDiagnosticsProtocolGuid },
474 	{ .efi_guid_name = "driver diagnostics2",
475 	    .efi_guid = &gEfiDriverDiagnostics2ProtocolGuid },
476 	{ .efi_guid_name = "driver override",
477 	    .efi_guid = &gEfiPlatformDriverOverrideProtocolGuid },
478 	{ .efi_guid_name = "bus specific driver override",
479 	    .efi_guid = &gEfiBusSpecificDriverOverrideProtocolGuid },
480 	{ .efi_guid_name = "platform to driver configuration",
481 	    .efi_guid = &gEfiPlatformToDriverConfigurationProtocolGuid },
482 	{ .efi_guid_name = "driver supported EFI version",
483 	    .efi_guid = &gEfiDriverSupportedEfiVersionProtocolGuid },
484 	{ .efi_guid_name = "driver family override",
485 	    .efi_guid = &gEfiDriverFamilyOverrideProtocolGuid },
486 	{ .efi_guid_name = "driver health",
487 	    .efi_guid = &gEfiDriverHealthProtocolGuid },
488 	{ .efi_guid_name = "adapter information",
489 	    .efi_guid = &gEfiAdapterInformationProtocolGuid },
490 	{ .efi_guid_name = "VLAN config",
491 	    .efi_guid = &gEfiVlanConfigProtocolGuid },
492 	{ .efi_guid_name = "ARP service binding",
493 	    .efi_guid = &gEfiArpServiceBindingProtocolGuid },
494 	{ .efi_guid_name = "ARP",
495 	    .efi_guid = &gEfiArpProtocolGuid },
496 	{ .efi_guid_name = "IPv4 service binding",
497 	    .efi_guid = &gEfiIp4ServiceBindingProtocolGuid },
498 	{ .efi_guid_name = "IPv4",
499 	    .efi_guid = &gEfiIp4ProtocolGuid },
500 	{ .efi_guid_name = "IPv4 config",
501 	    .efi_guid = &gEfiIp4ConfigProtocolGuid },
502 	{ .efi_guid_name = "IPv4 config2",
503 	    .efi_guid = &gEfiIp4Config2ProtocolGuid },
504 	{ .efi_guid_name = "IPv6 service binding",
505 	    .efi_guid = &gEfiIp6ServiceBindingProtocolGuid },
506 	{ .efi_guid_name = "IPv6",
507 	    .efi_guid = &gEfiIp6ProtocolGuid },
508 	{ .efi_guid_name = "IPv6 config",
509 	    .efi_guid = &gEfiIp6ConfigProtocolGuid },
510 	{ .efi_guid_name = "NVMe pass thru",
511 	    .efi_guid = &gEfiNvmExpressPassThruProtocolGuid },
512 	{ .efi_guid_name = "UDPv4",
513 	    .efi_guid = &gEfiUdp4ProtocolGuid },
514 	{ .efi_guid_name = "UDPv4 service binding",
515 	    .efi_guid = &gEfiUdp4ServiceBindingProtocolGuid },
516 	{ .efi_guid_name = "UDPv6",
517 	    .efi_guid = &gEfiUdp6ProtocolGuid },
518 	{ .efi_guid_name = "UDPv6 service binding",
519 	    .efi_guid = &gEfiUdp6ServiceBindingProtocolGuid },
520 	{ .efi_guid_name = "TCPv4",
521 	    .efi_guid = &gEfiTcp4ProtocolGuid },
522 	{ .efi_guid_name = "TCPv4 service binding",
523 	    .efi_guid = &gEfiTcp4ServiceBindingProtocolGuid },
524 	{ .efi_guid_name = "TCPv6",
525 	    .efi_guid = &gEfiTcp6ProtocolGuid },
526 	{ .efi_guid_name = "TCPv6 service binding",
527 	    .efi_guid = &gEfiTcp6ServiceBindingProtocolGuid },
528 	{ .efi_guid_name = "EFI System partition",
529 	    .efi_guid = &gEfiPartTypeSystemPartGuid },
530 	{ .efi_guid_name = "MBR legacy",
531 	    .efi_guid = &gEfiPartTypeLegacyMbrGuid },
532 	{ .efi_guid_name = "USB io",
533 	    .efi_guid = &gEfiUsbIoProtocolGuid },
534 	{ .efi_guid_name = "USB2 HC",
535 	    .efi_guid = &gEfiUsb2HcProtocolGuid },
536 	{ .efi_guid_name = "component name",
537 	    .efi_guid = &gEfiComponentNameProtocolGuid },
538 	{ .efi_guid_name = "component name2",
539 	    .efi_guid = &gEfiComponentName2ProtocolGuid },
540 	{ .efi_guid_name = "decompress",
541 	    .efi_guid = &gEfiDecompressProtocolGuid },
542 	{ .efi_guid_name = "ebc interpreter",
543 	    .efi_guid = &gEfiEbcProtocolGuid },
544 	{ .efi_guid_name = "network interface identifier",
545 	    .efi_guid = &gEfiNetworkInterfaceIdentifierProtocolGuid },
546 	{ .efi_guid_name = "network interface identifier_31",
547 	    .efi_guid = &gEfiNetworkInterfaceIdentifierProtocolGuid_31 },
548 	{ .efi_guid_name = "managed network service binding",
549 	    .efi_guid = &gEfiManagedNetworkServiceBindingProtocolGuid },
550 	{ .efi_guid_name = "managed network",
551 	    .efi_guid = &gEfiManagedNetworkProtocolGuid },
552 	{ .efi_guid_name = "form browser",
553 	    .efi_guid = &gEfiFormBrowser2ProtocolGuid },
554 	{ .efi_guid_name = "HII config access",
555 	    .efi_guid = &gEfiHiiConfigAccessProtocolGuid },
556 	{ .efi_guid_name = "HII config keyword handler",
557 	    .efi_guid = &gEfiConfigKeywordHandlerProtocolGuid },
558 	{ .efi_guid_name = "HII config routing",
559 	    .efi_guid = &gEfiHiiConfigRoutingProtocolGuid },
560 	{ .efi_guid_name = "HII database",
561 	    .efi_guid = &gEfiHiiDatabaseProtocolGuid },
562 	{ .efi_guid_name = "HII string",
563 	    .efi_guid = &gEfiHiiStringProtocolGuid },
564 	{ .efi_guid_name = "HII image",
565 	    .efi_guid = &gEfiHiiImageProtocolGuid },
566 	{ .efi_guid_name = "HII font",
567 	    .efi_guid = &gEfiHiiFontProtocolGuid },
568 	{ .efi_guid_name = "MTFTP3 service binding",
569 	    .efi_guid = &gEfiMtftp4ServiceBindingProtocolGuid },
570 	{ .efi_guid_name = "MTFTP4",
571 	    .efi_guid = &gEfiMtftp4ProtocolGuid },
572 	{ .efi_guid_name = "MTFTP6 service binding",
573 	    .efi_guid = &gEfiMtftp6ServiceBindingProtocolGuid },
574 	{ .efi_guid_name = "MTFTP6",
575 	    .efi_guid = &gEfiMtftp6ProtocolGuid },
576 	{ .efi_guid_name = "DHCP4 service binding",
577 	    .efi_guid = &gEfiDhcp4ServiceBindingProtocolGuid },
578 	{ .efi_guid_name = "DHCP4",
579 	    .efi_guid = &gEfiDhcp4ProtocolGuid },
580 	{ .efi_guid_name = "DHCP6 service binding",
581 	    .efi_guid = &gEfiDhcp6ServiceBindingProtocolGuid },
582 	{ .efi_guid_name = "DHCP6",
583 	    .efi_guid = &gEfiDhcp6ProtocolGuid },
584 	{ .efi_guid_name = "SCSI io",
585 	    .efi_guid = &gEfiScsiIoProtocolGuid },
586 	{ .efi_guid_name = "SCSI pass thru",
587 	    .efi_guid = &gEfiScsiPassThruProtocolGuid },
588 	{ .efi_guid_name = "SCSI pass thru ext",
589 	    .efi_guid = &gEfiExtScsiPassThruProtocolGuid },
590 	{ .efi_guid_name = "Capsule arch",
591 	    .efi_guid = &gEfiCapsuleArchProtocolGuid },
592 	{ .efi_guid_name = "monotonic counter arch",
593 	    .efi_guid = &gEfiMonotonicCounterArchProtocolGuid },
594 	{ .efi_guid_name = "realtime clock arch",
595 	    .efi_guid = &gEfiRealTimeClockArchProtocolGuid },
596 	{ .efi_guid_name = "variable arch",
597 	    .efi_guid = &gEfiVariableArchProtocolGuid },
598 	{ .efi_guid_name = "variable write arch",
599 	    .efi_guid = &gEfiVariableWriteArchProtocolGuid },
600 	{ .efi_guid_name = "watchdog timer arch",
601 	    .efi_guid = &gEfiWatchdogTimerArchProtocolGuid },
602 	{ .efi_guid_name = "BDS arch",
603 	    .efi_guid = &gEfiBdsArchProtocolGuid },
604 	{ .efi_guid_name = "metronome arch",
605 	    .efi_guid = &gEfiMetronomeArchProtocolGuid },
606 	{ .efi_guid_name = "timer arch",
607 	    .efi_guid = &gEfiTimerArchProtocolGuid },
608 	{ .efi_guid_name = "DPC",
609 	    .efi_guid = &gEfiDpcProtocolGuid },
610 	{ .efi_guid_name = "print2",
611 	    .efi_guid = &gEfiPrint2SProtocolGuid },
612 	{ .efi_guid_name = "device path to text",
613 	    .efi_guid = &gEfiDevicePathToTextProtocolGuid },
614 	{ .efi_guid_name = "reset arch",
615 	    .efi_guid = &gEfiResetArchProtocolGuid },
616 	{ .efi_guid_name = "CPU arch",
617 	    .efi_guid = &gEfiCpuArchProtocolGuid },
618 	{ .efi_guid_name = "CPU IO2",
619 	    .efi_guid = &gEfiCpuIo2ProtocolGuid },
620 	{ .efi_guid_name = "Legacy 8259",
621 	    .efi_guid = &gEfiLegacy8259ProtocolGuid },
622 	{ .efi_guid_name = "Security arch",
623 	    .efi_guid = &gEfiSecurityArchProtocolGuid },
624 	{ .efi_guid_name = "Security2 arch",
625 	    .efi_guid = &gEfiSecurity2ArchProtocolGuid },
626 	{ .efi_guid_name = "Security Policy",
627 	    .efi_guid = &gEfiSecurityPolicyProtocolGuid },
628 	{ .efi_guid_name = "Runtime arch",
629 	    .efi_guid = &gEfiRuntimeArchProtocolGuid },
630 	{ .efi_guid_name = "status code runtime",
631 	    .efi_guid = &gEfiStatusCodeRuntimeProtocolGuid },
632 	{ .efi_guid_name = "storage security command",
633 	    .efi_guid = &gEfiStorageSecurityCommandProtocolGuid },
634 	{ .efi_guid_name = "data hub",
635 	    .efi_guid = &gEfiDataHubProtocolGuid },
636 	{ .efi_guid_name = "PCD",
637 	    .efi_guid = &gPcdProtocolGuid },
638 	{ .efi_guid_name = "EFI PCD",
639 	    .efi_guid = &gEfiPcdProtocolGuid },
640 	{ .efi_guid_name = "firmware volume block",
641 	    .efi_guid = &gEfiFirmwareVolumeBlockProtocolGuid },
642 	{ .efi_guid_name = "firmware volume2",
643 	    .efi_guid = &gEfiFirmwareVolumeBlock2ProtocolGuid },
644 	{ .efi_guid_name = "lzma compress",
645 	    .efi_guid = &gLzmaCompress },
646 	{ .efi_guid_name = "MP services",
647 	    .efi_guid = &gEfiMpServiceProtocolGuid },
648 	{ .efi_guid_name = MTC_VARIABLE_NAME,
649 	    .efi_guid = &gMtcVendorGuid },
650 	{ .efi_guid_name = "Active EDID",
651 	    .efi_guid = &gEfiEdidActiveProtocolGuid },
652 	{ .efi_guid_name = "Discovered EDID",
653 	    .efi_guid = &gEfiEdidDiscoveredProtocolGuid },
654 	{ .efi_guid_name = "key management service",
655 	    .efi_guid = &gEfiKmsProtocolGuid },
656 	{ .efi_guid_name = "smart card reader",
657 	    .efi_guid = &gEfiSmartCardReaderProtocolGuid },
658 	{ .efi_guid_name = "rng source",
659 	    .efi_guid = &gEfiRngProtocolGuid },
660 	{ .efi_guid_name = "IPsec config",
661 	    .efi_guid = &gEfiIpSecConfigProtocolGuid },
662 	{ .efi_guid_name = "IPsec",
663 	    .efi_guid = &gEfiIpSecProtocolGuid },
664 	{ .efi_guid_name = "IPsec2",
665 	    .efi_guid = &gEfiIpSec2ProtocolGuid },
666 	{ .efi_guid_name = "TCG2 tpm",
667 	    .efi_guid = &gEfiTcg2ProtocolGuid }
668 };
669 
670 bool
671 efi_guid_to_str(const EFI_GUID *guid, char **sp)
672 {
673 	uint32_t status;
674 
675 	uuid_to_string((const uuid_t *)guid, sp, &status);
676 	return (status == uuid_s_ok ? true : false);
677 }
678 
679 bool
680 efi_str_to_guid(const char *s, EFI_GUID *guid)
681 {
682 	uint32_t status;
683 
684 	uuid_from_string(s, (uuid_t *)guid, &status);
685 	return (status == uuid_s_ok ? true : false);
686 }
687 
688 bool
689 efi_name_to_guid(const char *name, EFI_GUID *guid)
690 {
691 	uint32_t i;
692 
693 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
694 		if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) {
695 			*guid = *efi_uuid_mapping[i].efi_guid;
696 			return (true);
697 		}
698 	}
699 	return (efi_str_to_guid(name, guid));
700 }
701 
702 bool
703 efi_guid_to_name(EFI_GUID *guid, char **name)
704 {
705 	uint32_t i;
706 	int rv;
707 
708 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
709 		rv = uuid_equal((uuid_t *)guid,
710 		    (uuid_t *)efi_uuid_mapping[i].efi_guid, NULL);
711 		if (rv != 0) {
712 			*name = strdup(efi_uuid_mapping[i].efi_guid_name);
713 			if (*name == NULL)
714 				return (false);
715 			return (true);
716 		}
717 	}
718 	return (efi_guid_to_str(guid, name));
719 }
720 
721 void
722 efi_init_environment(void)
723 {
724 	char var[128];
725 
726 	snprintf(var, sizeof (var), "%d.%02d", ST->Hdr.Revision >> 16,
727 	    ST->Hdr.Revision & 0xffff);
728 	env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
729 }
730 
731 COMMAND_SET(efishow, "efi-show", "print some or all EFI variables",
732     command_efi_show);
733 
734 static int
735 efi_print_other_value(uint8_t *data, UINTN datasz)
736 {
737 	UINTN i;
738 	bool is_ascii = true;
739 
740 	printf(" = ");
741 	for (i = 0; i < datasz - 1; i++) {
742 		/*
743 		 * Quick hack to see if this ascii-ish string is printable
744 		 * range plus tab, cr and lf.
745 		 */
746 		if ((data[i] < 32 || data[i] > 126) &&
747 		    data[i] != 9 && data[i] != 10 && data[i] != 13) {
748 			is_ascii = false;
749 			break;
750 		}
751 	}
752 	if (data[datasz - 1] != '\0')
753 		is_ascii = false;
754 	if (is_ascii == true) {
755 		printf("%s", data);
756 		if (pager_output("\n"))
757 			return (CMD_WARN);
758 	} else {
759 		if (pager_output("\n"))
760 			return (CMD_WARN);
761 		/*
762 		 * Dump hex bytes grouped by 4.
763 		 */
764 		for (i = 0; i < datasz; i++) {
765 			printf("%02x ", data[i]);
766 			if ((i + 1) % 4 == 0)
767 				printf(" ");
768 			if ((i + 1) % 20 == 0) {
769 				if (pager_output("\n"))
770 					return (CMD_WARN);
771 			}
772 		}
773 		if (pager_output("\n"))
774 			return (CMD_WARN);
775 	}
776 
777 	return (CMD_OK);
778 }
779 
780 /* This appears to be some sort of UEFI shell alias table. */
781 static int
782 efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data,
783     UINTN datasz __unused)
784 {
785 	printf(" = %S", (CHAR16 *)data);
786 	if (pager_output("\n"))
787 		return (CMD_WARN);
788 	return (CMD_OK);
789 }
790 
791 const char *
792 efi_memory_type(EFI_MEMORY_TYPE type)
793 {
794 	const char *types[] = {
795 	    "Reserved",
796 	    "LoaderCode",
797 	    "LoaderData",
798 	    "BootServicesCode",
799 	    "BootServicesData",
800 	    "RuntimeServicesCode",
801 	    "RuntimeServicesData",
802 	    "ConventionalMemory",
803 	    "UnusableMemory",
804 	    "ACPIReclaimMemory",
805 	    "ACPIMemoryNVS",
806 	    "MemoryMappedIO",
807 	    "MemoryMappedIOPortSpace",
808 	    "PalCode",
809 	    "PersistentMemory"
810 	};
811 
812 	switch (type) {
813 	case EfiReservedMemoryType:
814 	case EfiLoaderCode:
815 	case EfiLoaderData:
816 	case EfiBootServicesCode:
817 	case EfiBootServicesData:
818 	case EfiRuntimeServicesCode:
819 	case EfiRuntimeServicesData:
820 	case EfiConventionalMemory:
821 	case EfiUnusableMemory:
822 	case EfiACPIReclaimMemory:
823 	case EfiACPIMemoryNVS:
824 	case EfiMemoryMappedIO:
825 	case EfiMemoryMappedIOPortSpace:
826 	case EfiPalCode:
827 	case EfiPersistentMemory:
828 		return (types[type]);
829 	default:
830 		return ("Unknown");
831 	}
832 }
833 
834 /* Print memory type table. */
835 static int
836 efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
837     UINTN datasz)
838 {
839 	int i, n;
840 	EFI_MEMORY_TYPE_INFORMATION *ti;
841 
842 	ti = (EFI_MEMORY_TYPE_INFORMATION *)data;
843 	if (pager_output(" = \n"))
844 		return (CMD_WARN);
845 
846 	n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION);
847 	for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) {
848 		printf("\t%23s pages: %u", efi_memory_type(ti[i].Type),
849 		    ti[i].NumberOfPages);
850 		if (pager_output("\n"))
851 			return (CMD_WARN);
852 	}
853 
854 	return (CMD_OK);
855 }
856 
857 /*
858  * Print illumos variables.
859  * We have LoaderPath and LoaderDev as CHAR16 strings.
860  */
861 static int
862 efi_print_illumos(const CHAR16 *varnamearg, uint8_t *data,
863     UINTN datasz __unused)
864 {
865 	int rv = -1;
866 	char *var = NULL;
867 
868 	if (ucs2_to_utf8(varnamearg, &var) != 0)
869 		return (CMD_ERROR);
870 
871 	if (strcmp("LoaderPath", var) == 0 ||
872 	    strcmp("LoaderDev", var) == 0) {
873 		printf(" = ");
874 		printf("%S", (CHAR16 *)data);
875 
876 		if (pager_output("\n"))
877 			rv = CMD_WARN;
878 		else
879 			rv = CMD_OK;
880 	}
881 
882 	free(var);
883 	return (rv);
884 }
885 
886 /* Print global variables. */
887 static int
888 efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz)
889 {
890 	int rv = -1;
891 	char *var = NULL;
892 
893 	if (ucs2_to_utf8(varnamearg, &var) != 0)
894 		return (CMD_ERROR);
895 
896 	if (strcmp("AuditMode", var) == 0) {
897 		printf(" = ");
898 		printf("0x%x", *data);	/* 8-bit int */
899 		goto done;
900 	}
901 
902 	if (strcmp("BootOptionSupport", var) == 0) {
903 		printf(" = ");
904 		printf("0x%x", *((uint32_t *)data));	/* UINT32 */
905 		goto done;
906 	}
907 
908 	if (strcmp("BootCurrent", var) == 0 ||
909 	    strcmp("BootNext", var) == 0 ||
910 	    strcmp("Timeout", var) == 0) {
911 		printf(" = ");
912 		printf("%u", *((uint16_t *)data));	/* UINT16 */
913 		goto done;
914 	}
915 
916 	if (strcmp("BootOrder", var) == 0 ||
917 	    strcmp("DriverOrder", var) == 0) {
918 		int i;
919 		UINT16 *u16 = (UINT16 *)data;
920 
921 		printf(" =");
922 		for (i = 0; i < datasz / sizeof (UINT16); i++)
923 			printf(" %u", u16[i]);
924 		goto done;
925 	}
926 	if (strncmp("Boot", var, 4) == 0 ||
927 	    strncmp("Driver", var, 5) == 0 ||
928 	    strncmp("SysPrep", var, 7) == 0 ||
929 	    strncmp("OsRecovery", var, 10) == 0) {
930 		UINT16 filepathlistlen;
931 		CHAR16 *text;
932 		int desclen;
933 		EFI_DEVICE_PATH *dp;
934 
935 		data += sizeof (UINT32);
936 		filepathlistlen = *(uint16_t *)data;
937 		data += sizeof (UINT16);
938 		text = (CHAR16 *)data;
939 
940 		for (desclen = 0; text[desclen] != 0; desclen++)
941 			;
942 		if (desclen != 0) {
943 			/* Add terminating zero and we have CHAR16. */
944 			desclen = (desclen + 1) * 2;
945 		}
946 
947 		printf(" = ");
948 		printf("%S", text);
949 		if (filepathlistlen != 0) {
950 			/* Output pathname from new line. */
951 			if (pager_output("\n")) {
952 				rv = CMD_WARN;
953 				goto done;
954 			}
955 			dp = malloc(filepathlistlen);
956 			if (dp == NULL)
957 				goto done;
958 
959 			memcpy(dp, data + desclen, filepathlistlen);
960 			text = efi_devpath_name(dp);
961 			if (text != NULL) {
962 				printf("\t%S", text);
963 				efi_free_devpath_name(text);
964 			}
965 			free(dp);
966 		}
967 		goto done;
968 	}
969 
970 	if (strcmp("ConIn", var) == 0 ||
971 	    strcmp("ConInDev", var) == 0 ||
972 	    strcmp("ConOut", var) == 0 ||
973 	    strcmp("ConOutDev", var) == 0 ||
974 	    strcmp("ErrOut", var) == 0 ||
975 	    strcmp("ErrOutDev", var) == 0) {
976 		CHAR16 *text;
977 
978 		printf(" = ");
979 		text = efi_devpath_name((EFI_DEVICE_PATH *)data);
980 		if (text != NULL) {
981 			printf("%S", text);
982 			efi_free_devpath_name(text);
983 		}
984 		goto done;
985 	}
986 
987 	if (strcmp("PlatformLang", var) == 0 ||
988 	    strcmp("PlatformLangCodes", var) == 0 ||
989 	    strcmp("LangCodes", var) == 0 ||
990 	    strcmp("Lang", var) == 0) {
991 		printf(" = ");
992 		printf("%s", data);	/* ASCII string */
993 		goto done;
994 	}
995 
996 	/*
997 	 * Feature bitmap from firmware to OS.
998 	 * Older UEFI provides UINT32, newer UINT64.
999 	 */
1000 	if (strcmp("OsIndicationsSupported", var) == 0) {
1001 		printf(" = ");
1002 		if (datasz == 4)
1003 			printf("0x%x", *((uint32_t *)data));
1004 		else
1005 			printf("0x%jx", *((uint64_t *)data));
1006 		goto done;
1007 	}
1008 
1009 	/* Fallback for anything else. */
1010 	rv = efi_print_other_value(data, datasz);
1011 done:
1012 	if (rv == -1) {
1013 		if (pager_output("\n"))
1014 			rv = CMD_WARN;
1015 		else
1016 			rv = CMD_OK;
1017 	}
1018 	free(var);
1019 	return (rv);
1020 }
1021 
1022 static void
1023 efi_print_var_attr(UINT32 attr)
1024 {
1025 	bool comma = false;
1026 
1027 	if (attr & EFI_VARIABLE_NON_VOLATILE) {
1028 		printf("NV");
1029 		comma = true;
1030 	}
1031 	if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
1032 		if (comma == true)
1033 			printf(",");
1034 		printf("BS");
1035 		comma = true;
1036 	}
1037 	if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
1038 		if (comma == true)
1039 			printf(",");
1040 		printf("RS");
1041 		comma = true;
1042 	}
1043 	if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1044 		if (comma == true)
1045 			printf(",");
1046 		printf("HR");
1047 		comma = true;
1048 	}
1049 	if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
1050 		if (comma == true)
1051 			printf(",");
1052 		printf("AT");
1053 		comma = true;
1054 	}
1055 }
1056 
1057 static int
1058 efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
1059 {
1060 	UINTN		datasz;
1061 	EFI_STATUS	status;
1062 	UINT32		attr;
1063 	char		*str;
1064 	uint8_t		*data;
1065 	int		rv = CMD_OK;
1066 
1067 	str = NULL;
1068 	datasz = 0;
1069 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL);
1070 	if (status != EFI_BUFFER_TOO_SMALL) {
1071 		printf("Can't get the variable: error %#lx\n",
1072 		    DECODE_ERROR(status));
1073 		return (CMD_ERROR);
1074 	}
1075 	data = malloc(datasz);
1076 	if (data == NULL) {
1077 		printf("Out of memory\n");
1078 		return (CMD_ERROR);
1079 	}
1080 
1081 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data);
1082 	if (status != EFI_SUCCESS) {
1083 		printf("Can't get the variable: error %#lx\n",
1084 		    DECODE_ERROR(status));
1085 		free(data);
1086 		return (CMD_ERROR);
1087 	}
1088 
1089 	if (efi_guid_to_name(matchguid, &str) == false) {
1090 		rv = CMD_ERROR;
1091 		goto done;
1092 	}
1093 	printf("%s ", str);
1094 	efi_print_var_attr(attr);
1095 	printf(" %S", varnamearg);
1096 
1097 	if (lflag == 0) {
1098 		if (strcmp(str, "global") == 0)
1099 			rv = efi_print_global(varnamearg, data, datasz);
1100 		else if (strcmp(str, "illumos") == 0)
1101 			rv = efi_print_illumos(varnamearg, data, datasz);
1102 		else if (strcmp(str,
1103 		    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0)
1104 			rv = efi_print_mem_type(varnamearg, data, datasz);
1105 		else if (strcmp(str,
1106 		    "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0)
1107 			rv = efi_print_shell_str(varnamearg, data, datasz);
1108 		else if (strcmp(str, MTC_VARIABLE_NAME) == 0) {
1109 			printf(" = ");
1110 			printf("%u", *((uint32_t *)data));	/* UINT32 */
1111 			rv = CMD_OK;
1112 			if (pager_output("\n"))
1113 				rv = CMD_WARN;
1114 		} else
1115 			rv = efi_print_other_value(data, datasz);
1116 	} else if (pager_output("\n"))
1117 		rv =  CMD_WARN;
1118 
1119 done:
1120 	free(str);
1121 	free(data);
1122 	return (rv);
1123 }
1124 
1125 static int
1126 command_efi_show(int argc, char *argv[])
1127 {
1128 	/*
1129 	 * efi-show [-a]
1130 	 *	print all the env
1131 	 * efi-show -g UUID
1132 	 *	print all the env vars tagged with UUID
1133 	 * efi-show -v var
1134 	 *	search all the env vars and print the ones matching var
1135 	 * efi-show -g UUID -v var
1136 	 * efi-show UUID var
1137 	 *	print all the env vars that match UUID and var
1138 	 */
1139 	/* NB: We assume EFI_GUID is the same as uuid_t */
1140 	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
1141 	int		ch, rv;
1142 	unsigned	i;
1143 	EFI_STATUS	status;
1144 	EFI_GUID	varguid = ZERO_GUID;
1145 	EFI_GUID	matchguid = ZERO_GUID;
1146 	CHAR16		*varname;
1147 	CHAR16		*newnm;
1148 	CHAR16		varnamearg[128];
1149 	UINTN		varalloc;
1150 	UINTN		varsz;
1151 
1152 	optind = 1;
1153 	optreset = 1;
1154 	opterr = 1;
1155 
1156 	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
1157 		switch (ch) {
1158 		case 'a':
1159 			aflag = 1;
1160 			break;
1161 		case 'g':
1162 			gflag = 1;
1163 			if (efi_name_to_guid(optarg, &matchguid) == false) {
1164 				printf("uuid %s could not be parsed\n", optarg);
1165 				return (CMD_ERROR);
1166 			}
1167 			break;
1168 		case 'l':
1169 			lflag = 1;
1170 			break;
1171 		case 'v':
1172 			vflag = 1;
1173 			if (strlen(optarg) >= nitems(varnamearg)) {
1174 				printf("Variable %s is longer than %zu "
1175 				    "characters\n", optarg, nitems(varnamearg));
1176 				return (CMD_ERROR);
1177 			}
1178 			cpy8to16(optarg, varnamearg, nitems(varnamearg));
1179 			break;
1180 		default:
1181 			return (CMD_ERROR);
1182 		}
1183 	}
1184 
1185 	if (argc == 1)		/* default is -a */
1186 		aflag = 1;
1187 
1188 	if (aflag && (gflag || vflag)) {
1189 		printf("-a isn't compatible with -g or -v\n");
1190 		return (CMD_ERROR);
1191 	}
1192 
1193 	if (aflag && optind < argc) {
1194 		printf("-a doesn't take any args\n");
1195 		return (CMD_ERROR);
1196 	}
1197 
1198 	argc -= optind;
1199 	argv += optind;
1200 
1201 	pager_open();
1202 	if (vflag && gflag) {
1203 		rv = efi_print_var(varnamearg, &matchguid, lflag);
1204 		if (rv == CMD_WARN)
1205 			rv = CMD_OK;
1206 		pager_close();
1207 		return (rv);
1208 	}
1209 
1210 	if (argc == 2) {
1211 		optarg = argv[0];
1212 		if (strlen(optarg) >= nitems(varnamearg)) {
1213 			printf("Variable %s is longer than %zu characters\n",
1214 			    optarg, nitems(varnamearg));
1215 			pager_close();
1216 			return (CMD_ERROR);
1217 		}
1218 		for (i = 0; i < strlen(optarg); i++)
1219 			varnamearg[i] = optarg[i];
1220 		varnamearg[i] = 0;
1221 		optarg = argv[1];
1222 		if (efi_name_to_guid(optarg, &matchguid) == false) {
1223 			printf("uuid %s could not be parsed\n", optarg);
1224 			pager_close();
1225 			return (CMD_ERROR);
1226 		}
1227 		rv = efi_print_var(varnamearg, &matchguid, lflag);
1228 		if (rv == CMD_WARN)
1229 			rv = CMD_OK;
1230 		pager_close();
1231 		return (rv);
1232 	}
1233 
1234 	if (argc > 0) {
1235 		printf("Too many args: %d\n", argc);
1236 		pager_close();
1237 		return (CMD_ERROR);
1238 	}
1239 
1240 	/*
1241 	 * Initiate the search -- note the standard takes pain
1242 	 * to specify the initial call must be a poiner to a NULL
1243 	 * character.
1244 	 */
1245 	varalloc = 1024;
1246 	varname = malloc(varalloc);
1247 	if (varname == NULL) {
1248 		printf("Can't allocate memory to get variables\n");
1249 		pager_close();
1250 		return (CMD_ERROR);
1251 	}
1252 	varname[0] = 0;
1253 	while (1) {
1254 		varsz = varalloc;
1255 		status = RS->GetNextVariableName(&varsz, varname, &varguid);
1256 		if (status == EFI_BUFFER_TOO_SMALL) {
1257 			varalloc = varsz;
1258 			newnm = realloc(varname, varalloc);
1259 			if (newnm == NULL) {
1260 				printf("Can't allocate memory to get "
1261 				    "variables\n");
1262 				rv = CMD_ERROR;
1263 				break;
1264 			}
1265 			varname = newnm;
1266 			continue; /* Try again with bigger buffer */
1267 		}
1268 		if (status == EFI_NOT_FOUND) {
1269 			rv = CMD_OK;
1270 			break;
1271 		}
1272 		if (status != EFI_SUCCESS) {
1273 			rv = CMD_ERROR;
1274 			break;
1275 		}
1276 
1277 		if (aflag) {
1278 			rv = efi_print_var(varname, &varguid, lflag);
1279 			if (rv != CMD_OK) {
1280 				if (rv == CMD_WARN)
1281 					rv = CMD_OK;
1282 				break;
1283 			}
1284 			continue;
1285 		}
1286 		if (vflag) {
1287 			if (wcscmp(varnamearg, varname) == 0) {
1288 				rv = efi_print_var(varname, &varguid, lflag);
1289 				if (rv != CMD_OK) {
1290 					if (rv == CMD_WARN)
1291 						rv = CMD_OK;
1292 					break;
1293 				}
1294 				continue;
1295 			}
1296 		}
1297 		if (gflag) {
1298 			rv = uuid_equal((uuid_t *)&varguid,
1299 			    (uuid_t *)&matchguid, NULL);
1300 			if (rv != 0) {
1301 				rv = efi_print_var(varname, &varguid, lflag);
1302 				if (rv != CMD_OK) {
1303 					if (rv == CMD_WARN)
1304 						rv = CMD_OK;
1305 					break;
1306 				}
1307 				continue;
1308 			}
1309 		}
1310 	}
1311 	free(varname);
1312 	pager_close();
1313 
1314 	return (rv);
1315 }
1316 
1317 COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
1318 
1319 static int
1320 command_efi_set(int argc, char *argv[])
1321 {
1322 	char *uuid, *var, *val;
1323 	CHAR16 wvar[128];
1324 	EFI_GUID guid;
1325 #if defined(ENABLE_UPDATES)
1326 	EFI_STATUS err;
1327 #endif
1328 
1329 	if (argc != 4) {
1330 		printf("efi-set uuid var new-value\n");
1331 		return (CMD_ERROR);
1332 	}
1333 	uuid = argv[1];
1334 	var = argv[2];
1335 	val = argv[3];
1336 	if (efi_name_to_guid(uuid, &guid) == false) {
1337 		printf("Invalid uuid %s\n", uuid);
1338 		return (CMD_ERROR);
1339 	}
1340 	cpy8to16(var, wvar, nitems(wvar));
1341 #if defined(ENABLE_UPDATES)
1342 	err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE |
1343 	    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1344 	    strlen(val) + 1, val);
1345 	if (EFI_ERROR(err)) {
1346 		printf("Failed to set variable: error %lu\n",
1347 		    DECODE_ERROR(err));
1348 		return (CMD_ERROR);
1349 	}
1350 #else
1351 	printf("would set %s %s = %s\n", uuid, var, val);
1352 #endif
1353 	return (CMD_OK);
1354 }
1355 
1356 COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables",
1357     command_efi_unset);
1358 
1359 static int
1360 command_efi_unset(int argc, char *argv[])
1361 {
1362 	char *uuid, *var;
1363 	CHAR16 wvar[128];
1364 	EFI_GUID guid;
1365 #if defined(ENABLE_UPDATES)
1366 	EFI_STATUS err;
1367 #endif
1368 
1369 	if (argc != 3) {
1370 		printf("efi-unset uuid var\n");
1371 		return (CMD_ERROR);
1372 	}
1373 	uuid = argv[1];
1374 	var = argv[2];
1375 	if (efi_name_to_guid(uuid, &guid) == false) {
1376 		printf("Invalid uuid %s\n", uuid);
1377 		return (CMD_ERROR);
1378 	}
1379 	cpy8to16(var, wvar, nitems(wvar));
1380 #if defined(ENABLE_UPDATES)
1381 	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
1382 	if (EFI_ERROR(err)) {
1383 		printf("Failed to unset variable: error %lu\n",
1384 		    DECODE_ERROR(err));
1385 		return (CMD_ERROR);
1386 	}
1387 #else
1388 	printf("would unset %s %s \n", uuid, var);
1389 #endif
1390 	return (CMD_OK);
1391 }
1392 
1393 /*
1394  * Loader interaction words and extras
1395  *
1396  *	efi-setenv  ( value n name n guid n attr -- 0 | -1)
1397  *	efi-getenv  ( guid n addr n -- addr' n' | -1 )
1398  *	efi-unsetenv ( name n guid n'' -- )
1399  */
1400 
1401 /*
1402  * efi-setenv
1403  *	efi-setenv  ( value n name n guid n attr -- 0 | -1)
1404  *
1405  * Set environment variables using the SetVariable EFI runtime service.
1406  *
1407  * Value and guid are passed through in binary form (so guid needs to be
1408  * converted to binary form from its string form). Name is converted from
1409  * ASCII to CHAR16. Since ficl doesn't have support for internationalization,
1410  * there's no native CHAR16 interface provided.
1411  *
1412  * attr is an int in the bitmask of the following attributes for this variable.
1413  *
1414  *	1	Non volatile
1415  *	2	Boot service access
1416  *	4	Run time access
1417  * (corresponding to the same bits in the UEFI spec).
1418  */
1419 static void
1420 ficlEfiSetenv(ficlVm *pVM)
1421 {
1422 	char	*value = NULL, *guid = NULL;
1423 	CHAR16	*name = NULL;
1424 	int	i;
1425 	char	*namep, *valuep, *guidp;
1426 	int	names, values, guids, attr;
1427 	EFI_STATUS status;
1428 	uuid_t	u;
1429 	uint32_t ustatus;
1430 	char	*error = NULL;
1431 	ficlStack *pStack = ficlVmGetDataStack(pVM);
1432 
1433 	FICL_STACK_CHECK(pStack, 6, 0);
1434 
1435 	attr = ficlStackPopInteger(pStack);
1436 	guids = ficlStackPopInteger(pStack);
1437 	guidp = (char *)ficlStackPopPointer(pStack);
1438 	names = ficlStackPopInteger(pStack);
1439 	namep = (char *)ficlStackPopPointer(pStack);
1440 	values = ficlStackPopInteger(pStack);
1441 	valuep = (char *)ficlStackPopPointer(pStack);
1442 
1443 	guid = ficlMalloc(guids);
1444 	if (guid == NULL)
1445 		goto out;
1446 	memcpy(guid, guidp, guids);
1447 	uuid_from_string(guid, &u, &ustatus);
1448 	if (ustatus != uuid_s_ok) {
1449 		switch (ustatus) {
1450 		case uuid_s_bad_version:
1451 			error = "uuid: bad string";
1452 			break;
1453 		case uuid_s_invalid_string_uuid:
1454 			error = "uuid: invalid string";
1455 			break;
1456 		case uuid_s_no_memory:
1457 			error = "Out of memory";
1458 			break;
1459 		default:
1460 			error = "uuid: Unknown error";
1461 			break;
1462 		}
1463 		ficlStackPushInteger(pStack, -1);
1464 		goto out;
1465 	}
1466 
1467 	name = ficlMalloc((names + 1) * sizeof (CHAR16));
1468 	if (name == NULL) {
1469 		error = "Out of memory";
1470 		goto out;
1471 	}
1472 	for (i = 0; i < names; i++)
1473 		name[i] = namep[i];
1474 	name[names] = 0;
1475 
1476 	value = ficlMalloc(values + 1);
1477 	if (value == NULL) {
1478 		error = "Out of memory";
1479 		goto out;
1480 	}
1481 	memcpy(value, valuep, values);
1482 
1483 	status = RS->SetVariable(name, (EFI_GUID *)&u, attr, values, value);
1484 	if (status == EFI_SUCCESS) {
1485 		ficlStackPushInteger(pStack, 0);
1486 	} else {
1487 		ficlStackPushInteger(pStack, -1);
1488 		error = "Error: SetVariable failed";
1489 	}
1490 
1491 out:
1492 	ficlFree(name);
1493 	ficlFree(value);
1494 	ficlFree(guid);
1495 	if (error != NULL)
1496 		ficlVmThrowError(pVM, error);
1497 }
1498 
1499 static void
1500 ficlEfiGetenv(ficlVm *pVM)
1501 {
1502 	char	*name, *value;
1503 	char	*namep;
1504 	int	names;
1505 
1506 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2);
1507 
1508 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
1509 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
1510 
1511 	name = ficlMalloc(names+1);
1512 	if (name == NULL)
1513 		ficlVmThrowError(pVM, "Error: out of memory");
1514 	strncpy(name, namep, names);
1515 	name[names] = '\0';
1516 
1517 	value = getenv(name);
1518 	ficlFree(name);
1519 
1520 	if (value != NULL) {
1521 		ficlStackPushPointer(ficlVmGetDataStack(pVM), value);
1522 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value));
1523 	} else {
1524 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
1525 	}
1526 }
1527 
1528 static void
1529 ficlEfiUnsetenv(ficlVm *pVM)
1530 {
1531 	char	*name;
1532 	char	*namep;
1533 	int	names;
1534 
1535 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
1536 
1537 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
1538 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
1539 
1540 	name = ficlMalloc(names+1);
1541 	if (name == NULL)
1542 		ficlVmThrowError(pVM, "Error: out of memory");
1543 	strncpy(name, namep, names);
1544 	name[names] = '\0';
1545 
1546 	unsetenv(name);
1547 	ficlFree(name);
1548 }
1549 
1550 /*
1551  * Build platform extensions into the system dictionary
1552  */
1553 static void
1554 ficlEfiCompilePlatform(ficlSystem *pSys)
1555 {
1556 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
1557 
1558 	FICL_SYSTEM_ASSERT(pSys, dp);
1559 
1560 	ficlDictionarySetPrimitive(dp, "efi-setenv", ficlEfiSetenv,
1561 	    FICL_WORD_DEFAULT);
1562 	ficlDictionarySetPrimitive(dp, "efi-getenv", ficlEfiGetenv,
1563 	    FICL_WORD_DEFAULT);
1564 	ficlDictionarySetPrimitive(dp, "efi-unsetenv", ficlEfiUnsetenv,
1565 	    FICL_WORD_DEFAULT);
1566 }
1567 
1568 FICL_COMPILE_SET(ficlEfiCompilePlatform);
1569