Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/efi/libefi/env.c
104904 views
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
1097