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