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