xref: /illumos-gate/usr/src/boot/efi/libefi/env.c (revision e8d3efa1c56e5f2b5368600a2baeb7b1d54a07f8)
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 #ifdef  __LP64__
730 	env_setenv("efi-systype", EV_VOLATILE, "64", env_noset, env_nounset);
731 	snprintf(var, sizeof (var), "0x%016lx", (uintptr_t)ST);
732 #else
733 	env_setenv("efi-systype", EV_VOLATILE, "32", env_noset, env_nounset);
734 	snprintf(var, sizeof (var), "0x%08x", (uintptr_t)ST);
735 #endif
736 	env_setenv("efi-systab", EV_VOLATILE, var, env_noset, env_nounset);
737 }
738 
739 COMMAND_SET(efishow, "efi-show", "print some or all EFI variables",
740     command_efi_show);
741 
742 static int
743 efi_print_other_value(uint8_t *data, UINTN datasz)
744 {
745 	UINTN i;
746 	bool is_ascii = true;
747 
748 	printf(" = ");
749 	for (i = 0; i < datasz - 1; i++) {
750 		/*
751 		 * Quick hack to see if this ascii-ish string is printable
752 		 * range plus tab, cr and lf.
753 		 */
754 		if ((data[i] < 32 || data[i] > 126) &&
755 		    data[i] != 9 && data[i] != 10 && data[i] != 13) {
756 			is_ascii = false;
757 			break;
758 		}
759 	}
760 	if (data[datasz - 1] != '\0')
761 		is_ascii = false;
762 	if (is_ascii == true) {
763 		printf("%s", data);
764 		if (pager_output("\n"))
765 			return (CMD_WARN);
766 	} else {
767 		if (pager_output("\n"))
768 			return (CMD_WARN);
769 		/*
770 		 * Dump hex bytes grouped by 4.
771 		 */
772 		for (i = 0; i < datasz; i++) {
773 			printf("%02x ", data[i]);
774 			if ((i + 1) % 4 == 0)
775 				printf(" ");
776 			if ((i + 1) % 20 == 0) {
777 				if (pager_output("\n"))
778 					return (CMD_WARN);
779 			}
780 		}
781 		if (pager_output("\n"))
782 			return (CMD_WARN);
783 	}
784 
785 	return (CMD_OK);
786 }
787 
788 /* This appears to be some sort of UEFI shell alias table. */
789 static int
790 efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data,
791     UINTN datasz __unused)
792 {
793 	printf(" = %S", (CHAR16 *)data);
794 	if (pager_output("\n"))
795 		return (CMD_WARN);
796 	return (CMD_OK);
797 }
798 
799 const char *
800 efi_memory_type(EFI_MEMORY_TYPE type)
801 {
802 	const char *types[] = {
803 	    "Reserved",
804 	    "LoaderCode",
805 	    "LoaderData",
806 	    "BootServicesCode",
807 	    "BootServicesData",
808 	    "RuntimeServicesCode",
809 	    "RuntimeServicesData",
810 	    "ConventionalMemory",
811 	    "UnusableMemory",
812 	    "ACPIReclaimMemory",
813 	    "ACPIMemoryNVS",
814 	    "MemoryMappedIO",
815 	    "MemoryMappedIOPortSpace",
816 	    "PalCode",
817 	    "PersistentMemory"
818 	};
819 
820 	switch (type) {
821 	case EfiReservedMemoryType:
822 	case EfiLoaderCode:
823 	case EfiLoaderData:
824 	case EfiBootServicesCode:
825 	case EfiBootServicesData:
826 	case EfiRuntimeServicesCode:
827 	case EfiRuntimeServicesData:
828 	case EfiConventionalMemory:
829 	case EfiUnusableMemory:
830 	case EfiACPIReclaimMemory:
831 	case EfiACPIMemoryNVS:
832 	case EfiMemoryMappedIO:
833 	case EfiMemoryMappedIOPortSpace:
834 	case EfiPalCode:
835 	case EfiPersistentMemory:
836 		return (types[type]);
837 	default:
838 		return ("Unknown");
839 	}
840 }
841 
842 /* Print memory type table. */
843 static int
844 efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
845     UINTN datasz)
846 {
847 	int i, n;
848 	EFI_MEMORY_TYPE_INFORMATION *ti;
849 
850 	ti = (EFI_MEMORY_TYPE_INFORMATION *)data;
851 	if (pager_output(" = \n"))
852 		return (CMD_WARN);
853 
854 	n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION);
855 	for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) {
856 		printf("\t%23s pages: %u", efi_memory_type(ti[i].Type),
857 		    ti[i].NumberOfPages);
858 		if (pager_output("\n"))
859 			return (CMD_WARN);
860 	}
861 
862 	return (CMD_OK);
863 }
864 
865 /*
866  * Print illumos variables.
867  * We have LoaderPath and LoaderDev as CHAR16 strings.
868  */
869 static int
870 efi_print_illumos(const CHAR16 *varnamearg, uint8_t *data,
871     UINTN datasz __unused)
872 {
873 	int rv = -1;
874 	char *var = NULL;
875 
876 	if (ucs2_to_utf8(varnamearg, &var) != 0)
877 		return (CMD_ERROR);
878 
879 	if (strcmp("LoaderPath", var) == 0 ||
880 	    strcmp("LoaderDev", var) == 0) {
881 		printf(" = ");
882 		printf("%S", (CHAR16 *)data);
883 
884 		if (pager_output("\n"))
885 			rv = CMD_WARN;
886 		else
887 			rv = CMD_OK;
888 	}
889 
890 	free(var);
891 	return (rv);
892 }
893 
894 /* Print global variables. */
895 static int
896 efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz)
897 {
898 	int rv = -1;
899 	char *var = NULL;
900 
901 	if (ucs2_to_utf8(varnamearg, &var) != 0)
902 		return (CMD_ERROR);
903 
904 	if (strcmp("AuditMode", var) == 0) {
905 		printf(" = ");
906 		printf("0x%x", *data);	/* 8-bit int */
907 		goto done;
908 	}
909 
910 	if (strcmp("BootOptionSupport", var) == 0) {
911 		printf(" = ");
912 		printf("0x%x", *((uint32_t *)data));	/* UINT32 */
913 		goto done;
914 	}
915 
916 	if (strcmp("BootCurrent", var) == 0 ||
917 	    strcmp("BootNext", var) == 0 ||
918 	    strcmp("Timeout", var) == 0) {
919 		printf(" = ");
920 		printf("%u", *((uint16_t *)data));	/* UINT16 */
921 		goto done;
922 	}
923 
924 	if (strcmp("BootOrder", var) == 0 ||
925 	    strcmp("DriverOrder", var) == 0) {
926 		int i;
927 		UINT16 *u16 = (UINT16 *)data;
928 
929 		printf(" =");
930 		for (i = 0; i < datasz / sizeof (UINT16); i++)
931 			printf(" %u", u16[i]);
932 		goto done;
933 	}
934 	if (strncmp("Boot", var, 4) == 0 ||
935 	    strncmp("Driver", var, 5) == 0 ||
936 	    strncmp("SysPrep", var, 7) == 0 ||
937 	    strncmp("OsRecovery", var, 10) == 0) {
938 		UINT16 filepathlistlen;
939 		CHAR16 *text;
940 		int desclen;
941 		EFI_DEVICE_PATH *dp;
942 
943 		data += sizeof (UINT32);
944 		filepathlistlen = *(uint16_t *)data;
945 		data += sizeof (UINT16);
946 		text = (CHAR16 *)data;
947 
948 		for (desclen = 0; text[desclen] != 0; desclen++)
949 			;
950 		if (desclen != 0) {
951 			/* Add terminating zero and we have CHAR16. */
952 			desclen = (desclen + 1) * 2;
953 		}
954 
955 		printf(" = ");
956 		printf("%S", text);
957 		if (filepathlistlen != 0) {
958 			/* Output pathname from new line. */
959 			if (pager_output("\n")) {
960 				rv = CMD_WARN;
961 				goto done;
962 			}
963 			dp = malloc(filepathlistlen);
964 			if (dp == NULL)
965 				goto done;
966 
967 			memcpy(dp, data + desclen, filepathlistlen);
968 			text = efi_devpath_name(dp);
969 			if (text != NULL) {
970 				printf("\t%S", text);
971 				efi_free_devpath_name(text);
972 			}
973 			free(dp);
974 		}
975 		goto done;
976 	}
977 
978 	if (strcmp("ConIn", var) == 0 ||
979 	    strcmp("ConInDev", var) == 0 ||
980 	    strcmp("ConOut", var) == 0 ||
981 	    strcmp("ConOutDev", var) == 0 ||
982 	    strcmp("ErrOut", var) == 0 ||
983 	    strcmp("ErrOutDev", var) == 0) {
984 		CHAR16 *text;
985 
986 		printf(" = ");
987 		text = efi_devpath_name((EFI_DEVICE_PATH *)data);
988 		if (text != NULL) {
989 			printf("%S", text);
990 			efi_free_devpath_name(text);
991 		}
992 		goto done;
993 	}
994 
995 	if (strcmp("PlatformLang", var) == 0 ||
996 	    strcmp("PlatformLangCodes", var) == 0 ||
997 	    strcmp("LangCodes", var) == 0 ||
998 	    strcmp("Lang", var) == 0) {
999 		printf(" = ");
1000 		printf("%s", data);	/* ASCII string */
1001 		goto done;
1002 	}
1003 
1004 	/*
1005 	 * Feature bitmap from firmware to OS.
1006 	 * Older UEFI provides UINT32, newer UINT64.
1007 	 */
1008 	if (strcmp("OsIndicationsSupported", var) == 0) {
1009 		printf(" = ");
1010 		if (datasz == 4)
1011 			printf("0x%x", *((uint32_t *)data));
1012 		else
1013 			printf("0x%jx", *((uint64_t *)data));
1014 		goto done;
1015 	}
1016 
1017 	/* Fallback for anything else. */
1018 	rv = efi_print_other_value(data, datasz);
1019 done:
1020 	if (rv == -1) {
1021 		if (pager_output("\n"))
1022 			rv = CMD_WARN;
1023 		else
1024 			rv = CMD_OK;
1025 	}
1026 	free(var);
1027 	return (rv);
1028 }
1029 
1030 static void
1031 efi_print_var_attr(UINT32 attr)
1032 {
1033 	bool comma = false;
1034 
1035 	if (attr & EFI_VARIABLE_NON_VOLATILE) {
1036 		printf("NV");
1037 		comma = true;
1038 	}
1039 	if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
1040 		if (comma == true)
1041 			printf(",");
1042 		printf("BS");
1043 		comma = true;
1044 	}
1045 	if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
1046 		if (comma == true)
1047 			printf(",");
1048 		printf("RS");
1049 		comma = true;
1050 	}
1051 	if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1052 		if (comma == true)
1053 			printf(",");
1054 		printf("HR");
1055 		comma = true;
1056 	}
1057 	if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
1058 		if (comma == true)
1059 			printf(",");
1060 		printf("AT");
1061 		comma = true;
1062 	}
1063 }
1064 
1065 static int
1066 efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
1067 {
1068 	UINTN		datasz;
1069 	EFI_STATUS	status;
1070 	UINT32		attr;
1071 	char		*str;
1072 	uint8_t		*data;
1073 	int		rv = CMD_OK;
1074 
1075 	str = NULL;
1076 	datasz = 0;
1077 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL);
1078 	if (status != EFI_BUFFER_TOO_SMALL) {
1079 		printf("Can't get the variable: error %#lx\n",
1080 		    DECODE_ERROR(status));
1081 		return (CMD_ERROR);
1082 	}
1083 	data = malloc(datasz);
1084 	if (data == NULL) {
1085 		printf("Out of memory\n");
1086 		return (CMD_ERROR);
1087 	}
1088 
1089 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data);
1090 	if (status != EFI_SUCCESS) {
1091 		printf("Can't get the variable: error %#lx\n",
1092 		    DECODE_ERROR(status));
1093 		free(data);
1094 		return (CMD_ERROR);
1095 	}
1096 
1097 	if (efi_guid_to_name(matchguid, &str) == false) {
1098 		rv = CMD_ERROR;
1099 		goto done;
1100 	}
1101 	printf("%s ", str);
1102 	efi_print_var_attr(attr);
1103 	printf(" %S", varnamearg);
1104 
1105 	if (lflag == 0) {
1106 		if (strcmp(str, "global") == 0)
1107 			rv = efi_print_global(varnamearg, data, datasz);
1108 		else if (strcmp(str, "illumos") == 0)
1109 			rv = efi_print_illumos(varnamearg, data, datasz);
1110 		else if (strcmp(str,
1111 		    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0)
1112 			rv = efi_print_mem_type(varnamearg, data, datasz);
1113 		else if (strcmp(str,
1114 		    "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0)
1115 			rv = efi_print_shell_str(varnamearg, data, datasz);
1116 		else if (strcmp(str, MTC_VARIABLE_NAME) == 0) {
1117 			printf(" = ");
1118 			printf("%u", *((uint32_t *)data));	/* UINT32 */
1119 			rv = CMD_OK;
1120 			if (pager_output("\n"))
1121 				rv = CMD_WARN;
1122 		} else
1123 			rv = efi_print_other_value(data, datasz);
1124 	} else if (pager_output("\n"))
1125 		rv =  CMD_WARN;
1126 
1127 done:
1128 	free(str);
1129 	free(data);
1130 	return (rv);
1131 }
1132 
1133 static int
1134 command_efi_show(int argc, char *argv[])
1135 {
1136 	/*
1137 	 * efi-show [-a]
1138 	 *	print all the env
1139 	 * efi-show -g UUID
1140 	 *	print all the env vars tagged with UUID
1141 	 * efi-show -v var
1142 	 *	search all the env vars and print the ones matching var
1143 	 * efi-show -g UUID -v var
1144 	 * efi-show UUID var
1145 	 *	print all the env vars that match UUID and var
1146 	 */
1147 	/* NB: We assume EFI_GUID is the same as uuid_t */
1148 	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
1149 	int		ch, rv;
1150 	unsigned	i;
1151 	EFI_STATUS	status;
1152 	EFI_GUID	varguid = ZERO_GUID;
1153 	EFI_GUID	matchguid = ZERO_GUID;
1154 	CHAR16		*varname;
1155 	CHAR16		*newnm;
1156 	CHAR16		varnamearg[128];
1157 	UINTN		varalloc;
1158 	UINTN		varsz;
1159 
1160 	optind = 1;
1161 	optreset = 1;
1162 	opterr = 1;
1163 
1164 	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
1165 		switch (ch) {
1166 		case 'a':
1167 			aflag = 1;
1168 			break;
1169 		case 'g':
1170 			gflag = 1;
1171 			if (efi_name_to_guid(optarg, &matchguid) == false) {
1172 				printf("uuid %s could not be parsed\n", optarg);
1173 				return (CMD_ERROR);
1174 			}
1175 			break;
1176 		case 'l':
1177 			lflag = 1;
1178 			break;
1179 		case 'v':
1180 			vflag = 1;
1181 			if (strlen(optarg) >= nitems(varnamearg)) {
1182 				printf("Variable %s is longer than %zu "
1183 				    "characters\n", optarg, nitems(varnamearg));
1184 				return (CMD_ERROR);
1185 			}
1186 			cpy8to16(optarg, varnamearg, nitems(varnamearg));
1187 			break;
1188 		default:
1189 			return (CMD_ERROR);
1190 		}
1191 	}
1192 
1193 	if (argc == 1)		/* default is -a */
1194 		aflag = 1;
1195 
1196 	if (aflag && (gflag || vflag)) {
1197 		printf("-a isn't compatible with -g or -v\n");
1198 		return (CMD_ERROR);
1199 	}
1200 
1201 	if (aflag && optind < argc) {
1202 		printf("-a doesn't take any args\n");
1203 		return (CMD_ERROR);
1204 	}
1205 
1206 	argc -= optind;
1207 	argv += optind;
1208 
1209 	pager_open();
1210 	if (vflag && gflag) {
1211 		rv = efi_print_var(varnamearg, &matchguid, lflag);
1212 		if (rv == CMD_WARN)
1213 			rv = CMD_OK;
1214 		pager_close();
1215 		return (rv);
1216 	}
1217 
1218 	if (argc == 2) {
1219 		optarg = argv[0];
1220 		if (strlen(optarg) >= nitems(varnamearg)) {
1221 			printf("Variable %s is longer than %zu characters\n",
1222 			    optarg, nitems(varnamearg));
1223 			pager_close();
1224 			return (CMD_ERROR);
1225 		}
1226 		for (i = 0; i < strlen(optarg); i++)
1227 			varnamearg[i] = optarg[i];
1228 		varnamearg[i] = 0;
1229 		optarg = argv[1];
1230 		if (efi_name_to_guid(optarg, &matchguid) == false) {
1231 			printf("uuid %s could not be parsed\n", optarg);
1232 			pager_close();
1233 			return (CMD_ERROR);
1234 		}
1235 		rv = efi_print_var(varnamearg, &matchguid, lflag);
1236 		if (rv == CMD_WARN)
1237 			rv = CMD_OK;
1238 		pager_close();
1239 		return (rv);
1240 	}
1241 
1242 	if (argc > 0) {
1243 		printf("Too many args: %d\n", argc);
1244 		pager_close();
1245 		return (CMD_ERROR);
1246 	}
1247 
1248 	/*
1249 	 * Initiate the search -- note the standard takes pain
1250 	 * to specify the initial call must be a poiner to a NULL
1251 	 * character.
1252 	 */
1253 	varalloc = 1024;
1254 	varname = malloc(varalloc);
1255 	if (varname == NULL) {
1256 		printf("Can't allocate memory to get variables\n");
1257 		pager_close();
1258 		return (CMD_ERROR);
1259 	}
1260 	varname[0] = 0;
1261 	while (1) {
1262 		varsz = varalloc;
1263 		status = RS->GetNextVariableName(&varsz, varname, &varguid);
1264 		if (status == EFI_BUFFER_TOO_SMALL) {
1265 			varalloc = varsz;
1266 			newnm = realloc(varname, varalloc);
1267 			if (newnm == NULL) {
1268 				printf("Can't allocate memory to get "
1269 				    "variables\n");
1270 				rv = CMD_ERROR;
1271 				break;
1272 			}
1273 			varname = newnm;
1274 			continue; /* Try again with bigger buffer */
1275 		}
1276 		if (status == EFI_NOT_FOUND) {
1277 			rv = CMD_OK;
1278 			break;
1279 		}
1280 		if (status != EFI_SUCCESS) {
1281 			rv = CMD_ERROR;
1282 			break;
1283 		}
1284 
1285 		if (aflag) {
1286 			rv = efi_print_var(varname, &varguid, lflag);
1287 			if (rv != CMD_OK) {
1288 				if (rv == CMD_WARN)
1289 					rv = CMD_OK;
1290 				break;
1291 			}
1292 			continue;
1293 		}
1294 		if (vflag) {
1295 			if (wcscmp(varnamearg, varname) == 0) {
1296 				rv = efi_print_var(varname, &varguid, lflag);
1297 				if (rv != CMD_OK) {
1298 					if (rv == CMD_WARN)
1299 						rv = CMD_OK;
1300 					break;
1301 				}
1302 				continue;
1303 			}
1304 		}
1305 		if (gflag) {
1306 			rv = uuid_equal((uuid_t *)&varguid,
1307 			    (uuid_t *)&matchguid, NULL);
1308 			if (rv != 0) {
1309 				rv = efi_print_var(varname, &varguid, lflag);
1310 				if (rv != CMD_OK) {
1311 					if (rv == CMD_WARN)
1312 						rv = CMD_OK;
1313 					break;
1314 				}
1315 				continue;
1316 			}
1317 		}
1318 	}
1319 	free(varname);
1320 	pager_close();
1321 
1322 	return (rv);
1323 }
1324 
1325 COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
1326 
1327 static int
1328 command_efi_set(int argc, char *argv[])
1329 {
1330 	char *uuid, *var, *val;
1331 	CHAR16 wvar[128];
1332 	EFI_GUID guid;
1333 #if defined(ENABLE_UPDATES)
1334 	EFI_STATUS err;
1335 #endif
1336 
1337 	if (argc != 4) {
1338 		printf("efi-set uuid var new-value\n");
1339 		return (CMD_ERROR);
1340 	}
1341 	uuid = argv[1];
1342 	var = argv[2];
1343 	val = argv[3];
1344 	if (efi_name_to_guid(uuid, &guid) == false) {
1345 		printf("Invalid uuid %s\n", uuid);
1346 		return (CMD_ERROR);
1347 	}
1348 	cpy8to16(var, wvar, nitems(wvar));
1349 #if defined(ENABLE_UPDATES)
1350 	err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE |
1351 	    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1352 	    strlen(val) + 1, val);
1353 	if (EFI_ERROR(err)) {
1354 		printf("Failed to set variable: error %lu\n",
1355 		    DECODE_ERROR(err));
1356 		return (CMD_ERROR);
1357 	}
1358 #else
1359 	printf("would set %s %s = %s\n", uuid, var, val);
1360 #endif
1361 	return (CMD_OK);
1362 }
1363 
1364 COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables",
1365     command_efi_unset);
1366 
1367 static int
1368 command_efi_unset(int argc, char *argv[])
1369 {
1370 	char *uuid, *var;
1371 	CHAR16 wvar[128];
1372 	EFI_GUID guid;
1373 #if defined(ENABLE_UPDATES)
1374 	EFI_STATUS err;
1375 #endif
1376 
1377 	if (argc != 3) {
1378 		printf("efi-unset uuid var\n");
1379 		return (CMD_ERROR);
1380 	}
1381 	uuid = argv[1];
1382 	var = argv[2];
1383 	if (efi_name_to_guid(uuid, &guid) == false) {
1384 		printf("Invalid uuid %s\n", uuid);
1385 		return (CMD_ERROR);
1386 	}
1387 	cpy8to16(var, wvar, nitems(wvar));
1388 #if defined(ENABLE_UPDATES)
1389 	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
1390 	if (EFI_ERROR(err)) {
1391 		printf("Failed to unset variable: error %lu\n",
1392 		    DECODE_ERROR(err));
1393 		return (CMD_ERROR);
1394 	}
1395 #else
1396 	printf("would unset %s %s \n", uuid, var);
1397 #endif
1398 	return (CMD_OK);
1399 }
1400 
1401 /*
1402  * Loader interaction words and extras
1403  *
1404  *	efi-setenv  ( value n name n guid n attr -- 0 | -1)
1405  *	efi-getenv  ( guid n addr n -- addr' n' | -1 )
1406  *	efi-unsetenv ( name n guid n'' -- )
1407  */
1408 
1409 /*
1410  * efi-setenv
1411  *	efi-setenv  ( value n name n guid n attr -- 0 | -1)
1412  *
1413  * Set environment variables using the SetVariable EFI runtime service.
1414  *
1415  * Value and guid are passed through in binary form (so guid needs to be
1416  * converted to binary form from its string form). Name is converted from
1417  * ASCII to CHAR16. Since ficl doesn't have support for internationalization,
1418  * there's no native CHAR16 interface provided.
1419  *
1420  * attr is an int in the bitmask of the following attributes for this variable.
1421  *
1422  *	1	Non volatile
1423  *	2	Boot service access
1424  *	4	Run time access
1425  * (corresponding to the same bits in the UEFI spec).
1426  */
1427 static void
1428 ficlEfiSetenv(ficlVm *pVM)
1429 {
1430 	char	*value = NULL, *guid = NULL;
1431 	CHAR16	*name = NULL;
1432 	int	i;
1433 	char	*namep, *valuep, *guidp;
1434 	int	names, values, guids, attr;
1435 	EFI_STATUS status;
1436 	uuid_t	u;
1437 	uint32_t ustatus;
1438 	char	*error = NULL;
1439 	ficlStack *pStack = ficlVmGetDataStack(pVM);
1440 
1441 	FICL_STACK_CHECK(pStack, 6, 0);
1442 
1443 	attr = ficlStackPopInteger(pStack);
1444 	guids = ficlStackPopInteger(pStack);
1445 	guidp = (char *)ficlStackPopPointer(pStack);
1446 	names = ficlStackPopInteger(pStack);
1447 	namep = (char *)ficlStackPopPointer(pStack);
1448 	values = ficlStackPopInteger(pStack);
1449 	valuep = (char *)ficlStackPopPointer(pStack);
1450 
1451 	guid = ficlMalloc(guids);
1452 	if (guid == NULL)
1453 		goto out;
1454 	memcpy(guid, guidp, guids);
1455 	uuid_from_string(guid, &u, &ustatus);
1456 	if (ustatus != uuid_s_ok) {
1457 		switch (ustatus) {
1458 		case uuid_s_bad_version:
1459 			error = "uuid: bad string";
1460 			break;
1461 		case uuid_s_invalid_string_uuid:
1462 			error = "uuid: invalid string";
1463 			break;
1464 		case uuid_s_no_memory:
1465 			error = "Out of memory";
1466 			break;
1467 		default:
1468 			error = "uuid: Unknown error";
1469 			break;
1470 		}
1471 		ficlStackPushInteger(pStack, -1);
1472 		goto out;
1473 	}
1474 
1475 	name = ficlMalloc((names + 1) * sizeof (CHAR16));
1476 	if (name == NULL) {
1477 		error = "Out of memory";
1478 		goto out;
1479 	}
1480 	for (i = 0; i < names; i++)
1481 		name[i] = namep[i];
1482 	name[names] = 0;
1483 
1484 	value = ficlMalloc(values + 1);
1485 	if (value == NULL) {
1486 		error = "Out of memory";
1487 		goto out;
1488 	}
1489 	memcpy(value, valuep, values);
1490 
1491 	status = RS->SetVariable(name, (EFI_GUID *)&u, attr, values, value);
1492 	if (status == EFI_SUCCESS) {
1493 		ficlStackPushInteger(pStack, 0);
1494 	} else {
1495 		ficlStackPushInteger(pStack, -1);
1496 		error = "Error: SetVariable failed";
1497 	}
1498 
1499 out:
1500 	ficlFree(name);
1501 	ficlFree(value);
1502 	ficlFree(guid);
1503 	if (error != NULL)
1504 		ficlVmThrowError(pVM, error);
1505 }
1506 
1507 static void
1508 ficlEfiGetenv(ficlVm *pVM)
1509 {
1510 	char	*name, *value;
1511 	char	*namep;
1512 	int	names;
1513 
1514 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2);
1515 
1516 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
1517 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
1518 
1519 	name = ficlMalloc(names+1);
1520 	if (name == NULL)
1521 		ficlVmThrowError(pVM, "Error: out of memory");
1522 	strncpy(name, namep, names);
1523 	name[names] = '\0';
1524 
1525 	value = getenv(name);
1526 	ficlFree(name);
1527 
1528 	if (value != NULL) {
1529 		ficlStackPushPointer(ficlVmGetDataStack(pVM), value);
1530 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value));
1531 	} else {
1532 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
1533 	}
1534 }
1535 
1536 static void
1537 ficlEfiUnsetenv(ficlVm *pVM)
1538 {
1539 	char	*name;
1540 	char	*namep;
1541 	int	names;
1542 
1543 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
1544 
1545 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
1546 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
1547 
1548 	name = ficlMalloc(names+1);
1549 	if (name == NULL)
1550 		ficlVmThrowError(pVM, "Error: out of memory");
1551 	strncpy(name, namep, names);
1552 	name[names] = '\0';
1553 
1554 	unsetenv(name);
1555 	ficlFree(name);
1556 }
1557 
1558 /*
1559  * Build platform extensions into the system dictionary
1560  */
1561 static void
1562 ficlEfiCompilePlatform(ficlSystem *pSys)
1563 {
1564 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
1565 
1566 	FICL_SYSTEM_ASSERT(pSys, dp);
1567 
1568 	ficlDictionarySetPrimitive(dp, "efi-setenv", ficlEfiSetenv,
1569 	    FICL_WORD_DEFAULT);
1570 	ficlDictionarySetPrimitive(dp, "efi-getenv", ficlEfiGetenv,
1571 	    FICL_WORD_DEFAULT);
1572 	ficlDictionarySetPrimitive(dp, "efi-unsetenv", ficlEfiUnsetenv,
1573 	    FICL_WORD_DEFAULT);
1574 }
1575 
1576 FICL_COMPILE_SET(ficlEfiCompilePlatform);
1577