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