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