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