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