1 /* 2 * efi.c - EFI subsystem 3 * 4 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> 5 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> 6 * Copyright (C) 2013 Tom Gundersen <teg@jklm.no> 7 * 8 * This code registers /sys/firmware/efi{,/efivars} when EFI is supported, 9 * allowing the efivarfs to be mounted or the efivars module to be loaded. 10 * The existance of /sys/firmware/efi may also be used by userspace to 11 * determine that the system supports EFI. 12 * 13 * This file is released under the GPLv2. 14 */ 15 16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18 #include <linux/kobject.h> 19 #include <linux/module.h> 20 #include <linux/init.h> 21 #include <linux/device.h> 22 #include <linux/efi.h> 23 #include <linux/of.h> 24 #include <linux/of_fdt.h> 25 #include <linux/io.h> 26 #include <linux/platform_device.h> 27 #include <linux/slab.h> 28 #include <linux/acpi.h> 29 #include <linux/ucs2_string.h> 30 #include <linux/memblock.h> 31 32 #include <asm/early_ioremap.h> 33 34 struct efi __read_mostly efi = { 35 .mps = EFI_INVALID_TABLE_ADDR, 36 .acpi = EFI_INVALID_TABLE_ADDR, 37 .acpi20 = EFI_INVALID_TABLE_ADDR, 38 .smbios = EFI_INVALID_TABLE_ADDR, 39 .smbios3 = EFI_INVALID_TABLE_ADDR, 40 .sal_systab = EFI_INVALID_TABLE_ADDR, 41 .boot_info = EFI_INVALID_TABLE_ADDR, 42 .hcdp = EFI_INVALID_TABLE_ADDR, 43 .uga = EFI_INVALID_TABLE_ADDR, 44 .uv_systab = EFI_INVALID_TABLE_ADDR, 45 .fw_vendor = EFI_INVALID_TABLE_ADDR, 46 .runtime = EFI_INVALID_TABLE_ADDR, 47 .config_table = EFI_INVALID_TABLE_ADDR, 48 .esrt = EFI_INVALID_TABLE_ADDR, 49 .properties_table = EFI_INVALID_TABLE_ADDR, 50 .mem_attr_table = EFI_INVALID_TABLE_ADDR, 51 }; 52 EXPORT_SYMBOL(efi); 53 54 static bool disable_runtime; 55 static int __init setup_noefi(char *arg) 56 { 57 disable_runtime = true; 58 return 0; 59 } 60 early_param("noefi", setup_noefi); 61 62 bool efi_runtime_disabled(void) 63 { 64 return disable_runtime; 65 } 66 67 static int __init parse_efi_cmdline(char *str) 68 { 69 if (!str) { 70 pr_warn("need at least one option\n"); 71 return -EINVAL; 72 } 73 74 if (parse_option_str(str, "debug")) 75 set_bit(EFI_DBG, &efi.flags); 76 77 if (parse_option_str(str, "noruntime")) 78 disable_runtime = true; 79 80 return 0; 81 } 82 early_param("efi", parse_efi_cmdline); 83 84 struct kobject *efi_kobj; 85 86 /* 87 * Let's not leave out systab information that snuck into 88 * the efivars driver 89 */ 90 static ssize_t systab_show(struct kobject *kobj, 91 struct kobj_attribute *attr, char *buf) 92 { 93 char *str = buf; 94 95 if (!kobj || !buf) 96 return -EINVAL; 97 98 if (efi.mps != EFI_INVALID_TABLE_ADDR) 99 str += sprintf(str, "MPS=0x%lx\n", efi.mps); 100 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) 101 str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); 102 if (efi.acpi != EFI_INVALID_TABLE_ADDR) 103 str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); 104 /* 105 * If both SMBIOS and SMBIOS3 entry points are implemented, the 106 * SMBIOS3 entry point shall be preferred, so we list it first to 107 * let applications stop parsing after the first match. 108 */ 109 if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) 110 str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3); 111 if (efi.smbios != EFI_INVALID_TABLE_ADDR) 112 str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); 113 if (efi.hcdp != EFI_INVALID_TABLE_ADDR) 114 str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); 115 if (efi.boot_info != EFI_INVALID_TABLE_ADDR) 116 str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); 117 if (efi.uga != EFI_INVALID_TABLE_ADDR) 118 str += sprintf(str, "UGA=0x%lx\n", efi.uga); 119 120 return str - buf; 121 } 122 123 static struct kobj_attribute efi_attr_systab = 124 __ATTR(systab, 0400, systab_show, NULL); 125 126 #define EFI_FIELD(var) efi.var 127 128 #define EFI_ATTR_SHOW(name) \ 129 static ssize_t name##_show(struct kobject *kobj, \ 130 struct kobj_attribute *attr, char *buf) \ 131 { \ 132 return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \ 133 } 134 135 EFI_ATTR_SHOW(fw_vendor); 136 EFI_ATTR_SHOW(runtime); 137 EFI_ATTR_SHOW(config_table); 138 139 static ssize_t fw_platform_size_show(struct kobject *kobj, 140 struct kobj_attribute *attr, char *buf) 141 { 142 return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32); 143 } 144 145 static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor); 146 static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime); 147 static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table); 148 static struct kobj_attribute efi_attr_fw_platform_size = 149 __ATTR_RO(fw_platform_size); 150 151 static struct attribute *efi_subsys_attrs[] = { 152 &efi_attr_systab.attr, 153 &efi_attr_fw_vendor.attr, 154 &efi_attr_runtime.attr, 155 &efi_attr_config_table.attr, 156 &efi_attr_fw_platform_size.attr, 157 NULL, 158 }; 159 160 static umode_t efi_attr_is_visible(struct kobject *kobj, 161 struct attribute *attr, int n) 162 { 163 if (attr == &efi_attr_fw_vendor.attr) { 164 if (efi_enabled(EFI_PARAVIRT) || 165 efi.fw_vendor == EFI_INVALID_TABLE_ADDR) 166 return 0; 167 } else if (attr == &efi_attr_runtime.attr) { 168 if (efi.runtime == EFI_INVALID_TABLE_ADDR) 169 return 0; 170 } else if (attr == &efi_attr_config_table.attr) { 171 if (efi.config_table == EFI_INVALID_TABLE_ADDR) 172 return 0; 173 } 174 175 return attr->mode; 176 } 177 178 static struct attribute_group efi_subsys_attr_group = { 179 .attrs = efi_subsys_attrs, 180 .is_visible = efi_attr_is_visible, 181 }; 182 183 static struct efivars generic_efivars; 184 static struct efivar_operations generic_ops; 185 186 static int generic_ops_register(void) 187 { 188 generic_ops.get_variable = efi.get_variable; 189 generic_ops.set_variable = efi.set_variable; 190 generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; 191 generic_ops.get_next_variable = efi.get_next_variable; 192 generic_ops.query_variable_store = efi_query_variable_store; 193 194 return efivars_register(&generic_efivars, &generic_ops, efi_kobj); 195 } 196 197 static void generic_ops_unregister(void) 198 { 199 efivars_unregister(&generic_efivars); 200 } 201 202 #if IS_ENABLED(CONFIG_ACPI) 203 #define EFIVAR_SSDT_NAME_MAX 16 204 static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; 205 static int __init efivar_ssdt_setup(char *str) 206 { 207 if (strlen(str) < sizeof(efivar_ssdt)) 208 memcpy(efivar_ssdt, str, strlen(str)); 209 else 210 pr_warn("efivar_ssdt: name too long: %s\n", str); 211 return 0; 212 } 213 __setup("efivar_ssdt=", efivar_ssdt_setup); 214 215 static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor, 216 unsigned long name_size, void *data) 217 { 218 struct efivar_entry *entry; 219 struct list_head *list = data; 220 char utf8_name[EFIVAR_SSDT_NAME_MAX]; 221 int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size); 222 223 ucs2_as_utf8(utf8_name, name, limit - 1); 224 if (strncmp(utf8_name, efivar_ssdt, limit) != 0) 225 return 0; 226 227 entry = kmalloc(sizeof(*entry), GFP_KERNEL); 228 if (!entry) 229 return 0; 230 231 memcpy(entry->var.VariableName, name, name_size); 232 memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t)); 233 234 efivar_entry_add(entry, list); 235 236 return 0; 237 } 238 239 static __init int efivar_ssdt_load(void) 240 { 241 LIST_HEAD(entries); 242 struct efivar_entry *entry, *aux; 243 unsigned long size; 244 void *data; 245 int ret; 246 247 ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries); 248 249 list_for_each_entry_safe(entry, aux, &entries, list) { 250 pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, 251 &entry->var.VendorGuid); 252 253 list_del(&entry->list); 254 255 ret = efivar_entry_size(entry, &size); 256 if (ret) { 257 pr_err("failed to get var size\n"); 258 goto free_entry; 259 } 260 261 data = kmalloc(size, GFP_KERNEL); 262 if (!data) 263 goto free_entry; 264 265 ret = efivar_entry_get(entry, NULL, &size, data); 266 if (ret) { 267 pr_err("failed to get var data\n"); 268 goto free_data; 269 } 270 271 ret = acpi_load_table(data); 272 if (ret) { 273 pr_err("failed to load table: %d\n", ret); 274 goto free_data; 275 } 276 277 goto free_entry; 278 279 free_data: 280 kfree(data); 281 282 free_entry: 283 kfree(entry); 284 } 285 286 return ret; 287 } 288 #else 289 static inline int efivar_ssdt_load(void) { return 0; } 290 #endif 291 292 /* 293 * We register the efi subsystem with the firmware subsystem and the 294 * efivars subsystem with the efi subsystem, if the system was booted with 295 * EFI. 296 */ 297 static int __init efisubsys_init(void) 298 { 299 int error; 300 301 if (!efi_enabled(EFI_BOOT)) 302 return 0; 303 304 /* We register the efi directory at /sys/firmware/efi */ 305 efi_kobj = kobject_create_and_add("efi", firmware_kobj); 306 if (!efi_kobj) { 307 pr_err("efi: Firmware registration failed.\n"); 308 return -ENOMEM; 309 } 310 311 error = generic_ops_register(); 312 if (error) 313 goto err_put; 314 315 if (efi_enabled(EFI_RUNTIME_SERVICES)) 316 efivar_ssdt_load(); 317 318 error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); 319 if (error) { 320 pr_err("efi: Sysfs attribute export failed with error %d.\n", 321 error); 322 goto err_unregister; 323 } 324 325 error = efi_runtime_map_init(efi_kobj); 326 if (error) 327 goto err_remove_group; 328 329 /* and the standard mountpoint for efivarfs */ 330 error = sysfs_create_mount_point(efi_kobj, "efivars"); 331 if (error) { 332 pr_err("efivars: Subsystem registration failed.\n"); 333 goto err_remove_group; 334 } 335 336 return 0; 337 338 err_remove_group: 339 sysfs_remove_group(efi_kobj, &efi_subsys_attr_group); 340 err_unregister: 341 generic_ops_unregister(); 342 err_put: 343 kobject_put(efi_kobj); 344 return error; 345 } 346 347 subsys_initcall(efisubsys_init); 348 349 /* 350 * Find the efi memory descriptor for a given physical address. Given a 351 * physical address, determine if it exists within an EFI Memory Map entry, 352 * and if so, populate the supplied memory descriptor with the appropriate 353 * data. 354 */ 355 int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) 356 { 357 efi_memory_desc_t *md; 358 359 if (!efi_enabled(EFI_MEMMAP)) { 360 pr_err_once("EFI_MEMMAP is not enabled.\n"); 361 return -EINVAL; 362 } 363 364 if (!out_md) { 365 pr_err_once("out_md is null.\n"); 366 return -EINVAL; 367 } 368 369 for_each_efi_memory_desc(md) { 370 u64 size; 371 u64 end; 372 373 if (!(md->attribute & EFI_MEMORY_RUNTIME) && 374 md->type != EFI_BOOT_SERVICES_DATA && 375 md->type != EFI_RUNTIME_SERVICES_DATA) { 376 continue; 377 } 378 379 size = md->num_pages << EFI_PAGE_SHIFT; 380 end = md->phys_addr + size; 381 if (phys_addr >= md->phys_addr && phys_addr < end) { 382 memcpy(out_md, md, sizeof(*out_md)); 383 return 0; 384 } 385 } 386 pr_err_once("requested map not found.\n"); 387 return -ENOENT; 388 } 389 390 /* 391 * Calculate the highest address of an efi memory descriptor. 392 */ 393 u64 __init efi_mem_desc_end(efi_memory_desc_t *md) 394 { 395 u64 size = md->num_pages << EFI_PAGE_SHIFT; 396 u64 end = md->phys_addr + size; 397 return end; 398 } 399 400 void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {} 401 402 /** 403 * efi_mem_reserve - Reserve an EFI memory region 404 * @addr: Physical address to reserve 405 * @size: Size of reservation 406 * 407 * Mark a region as reserved from general kernel allocation and 408 * prevent it being released by efi_free_boot_services(). 409 * 410 * This function should be called drivers once they've parsed EFI 411 * configuration tables to figure out where their data lives, e.g. 412 * efi_esrt_init(). 413 */ 414 void __init efi_mem_reserve(phys_addr_t addr, u64 size) 415 { 416 if (!memblock_is_region_reserved(addr, size)) 417 memblock_reserve(addr, size); 418 419 /* 420 * Some architectures (x86) reserve all boot services ranges 421 * until efi_free_boot_services() because of buggy firmware 422 * implementations. This means the above memblock_reserve() is 423 * superfluous on x86 and instead what it needs to do is 424 * ensure the @start, @size is not freed. 425 */ 426 efi_arch_mem_reserve(addr, size); 427 } 428 429 static __initdata efi_config_table_type_t common_tables[] = { 430 {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, 431 {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, 432 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, 433 {MPS_TABLE_GUID, "MPS", &efi.mps}, 434 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, 435 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, 436 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, 437 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, 438 {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt}, 439 {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table}, 440 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, 441 {NULL_GUID, NULL, NULL}, 442 }; 443 444 static __init int match_config_table(efi_guid_t *guid, 445 unsigned long table, 446 efi_config_table_type_t *table_types) 447 { 448 int i; 449 450 if (table_types) { 451 for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { 452 if (!efi_guidcmp(*guid, table_types[i].guid)) { 453 *(table_types[i].ptr) = table; 454 if (table_types[i].name) 455 pr_cont(" %s=0x%lx ", 456 table_types[i].name, table); 457 return 1; 458 } 459 } 460 } 461 462 return 0; 463 } 464 465 int __init efi_config_parse_tables(void *config_tables, int count, int sz, 466 efi_config_table_type_t *arch_tables) 467 { 468 void *tablep; 469 int i; 470 471 tablep = config_tables; 472 pr_info(""); 473 for (i = 0; i < count; i++) { 474 efi_guid_t guid; 475 unsigned long table; 476 477 if (efi_enabled(EFI_64BIT)) { 478 u64 table64; 479 guid = ((efi_config_table_64_t *)tablep)->guid; 480 table64 = ((efi_config_table_64_t *)tablep)->table; 481 table = table64; 482 #ifndef CONFIG_64BIT 483 if (table64 >> 32) { 484 pr_cont("\n"); 485 pr_err("Table located above 4GB, disabling EFI.\n"); 486 return -EINVAL; 487 } 488 #endif 489 } else { 490 guid = ((efi_config_table_32_t *)tablep)->guid; 491 table = ((efi_config_table_32_t *)tablep)->table; 492 } 493 494 if (!match_config_table(&guid, table, common_tables)) 495 match_config_table(&guid, table, arch_tables); 496 497 tablep += sz; 498 } 499 pr_cont("\n"); 500 set_bit(EFI_CONFIG_TABLES, &efi.flags); 501 502 /* Parse the EFI Properties table if it exists */ 503 if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { 504 efi_properties_table_t *tbl; 505 506 tbl = early_memremap(efi.properties_table, sizeof(*tbl)); 507 if (tbl == NULL) { 508 pr_err("Could not map Properties table!\n"); 509 return -ENOMEM; 510 } 511 512 if (tbl->memory_protection_attribute & 513 EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) 514 set_bit(EFI_NX_PE_DATA, &efi.flags); 515 516 early_memunmap(tbl, sizeof(*tbl)); 517 } 518 519 return 0; 520 } 521 522 int __init efi_config_init(efi_config_table_type_t *arch_tables) 523 { 524 void *config_tables; 525 int sz, ret; 526 527 if (efi_enabled(EFI_64BIT)) 528 sz = sizeof(efi_config_table_64_t); 529 else 530 sz = sizeof(efi_config_table_32_t); 531 532 /* 533 * Let's see what config tables the firmware passed to us. 534 */ 535 config_tables = early_memremap(efi.systab->tables, 536 efi.systab->nr_tables * sz); 537 if (config_tables == NULL) { 538 pr_err("Could not map Configuration table!\n"); 539 return -ENOMEM; 540 } 541 542 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz, 543 arch_tables); 544 545 early_memunmap(config_tables, efi.systab->nr_tables * sz); 546 return ret; 547 } 548 549 #ifdef CONFIG_EFI_VARS_MODULE 550 static int __init efi_load_efivars(void) 551 { 552 struct platform_device *pdev; 553 554 if (!efi_enabled(EFI_RUNTIME_SERVICES)) 555 return 0; 556 557 pdev = platform_device_register_simple("efivars", 0, NULL, 0); 558 return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; 559 } 560 device_initcall(efi_load_efivars); 561 #endif 562 563 #ifdef CONFIG_EFI_PARAMS_FROM_FDT 564 565 #define UEFI_PARAM(name, prop, field) \ 566 { \ 567 { name }, \ 568 { prop }, \ 569 offsetof(struct efi_fdt_params, field), \ 570 FIELD_SIZEOF(struct efi_fdt_params, field) \ 571 } 572 573 struct params { 574 const char name[32]; 575 const char propname[32]; 576 int offset; 577 int size; 578 }; 579 580 static __initdata struct params fdt_params[] = { 581 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table), 582 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap), 583 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size), 584 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size), 585 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver) 586 }; 587 588 static __initdata struct params xen_fdt_params[] = { 589 UEFI_PARAM("System Table", "xen,uefi-system-table", system_table), 590 UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap), 591 UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size), 592 UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size), 593 UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver) 594 }; 595 596 #define EFI_FDT_PARAMS_SIZE ARRAY_SIZE(fdt_params) 597 598 static __initdata struct { 599 const char *uname; 600 const char *subnode; 601 struct params *params; 602 } dt_params[] = { 603 { "hypervisor", "uefi", xen_fdt_params }, 604 { "chosen", NULL, fdt_params }, 605 }; 606 607 struct param_info { 608 int found; 609 void *params; 610 const char *missing; 611 }; 612 613 static int __init __find_uefi_params(unsigned long node, 614 struct param_info *info, 615 struct params *params) 616 { 617 const void *prop; 618 void *dest; 619 u64 val; 620 int i, len; 621 622 for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) { 623 prop = of_get_flat_dt_prop(node, params[i].propname, &len); 624 if (!prop) { 625 info->missing = params[i].name; 626 return 0; 627 } 628 629 dest = info->params + params[i].offset; 630 info->found++; 631 632 val = of_read_number(prop, len / sizeof(u32)); 633 634 if (params[i].size == sizeof(u32)) 635 *(u32 *)dest = val; 636 else 637 *(u64 *)dest = val; 638 639 if (efi_enabled(EFI_DBG)) 640 pr_info(" %s: 0x%0*llx\n", params[i].name, 641 params[i].size * 2, val); 642 } 643 644 return 1; 645 } 646 647 static int __init fdt_find_uefi_params(unsigned long node, const char *uname, 648 int depth, void *data) 649 { 650 struct param_info *info = data; 651 int i; 652 653 for (i = 0; i < ARRAY_SIZE(dt_params); i++) { 654 const char *subnode = dt_params[i].subnode; 655 656 if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) { 657 info->missing = dt_params[i].params[0].name; 658 continue; 659 } 660 661 if (subnode) { 662 int err = of_get_flat_dt_subnode_by_name(node, subnode); 663 664 if (err < 0) 665 return 0; 666 667 node = err; 668 } 669 670 return __find_uefi_params(node, info, dt_params[i].params); 671 } 672 673 return 0; 674 } 675 676 int __init efi_get_fdt_params(struct efi_fdt_params *params) 677 { 678 struct param_info info; 679 int ret; 680 681 pr_info("Getting EFI parameters from FDT:\n"); 682 683 info.found = 0; 684 info.params = params; 685 686 ret = of_scan_flat_dt(fdt_find_uefi_params, &info); 687 if (!info.found) 688 pr_info("UEFI not found.\n"); 689 else if (!ret) 690 pr_err("Can't find '%s' in device tree!\n", 691 info.missing); 692 693 return ret; 694 } 695 #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ 696 697 static __initdata char memory_type_name[][20] = { 698 "Reserved", 699 "Loader Code", 700 "Loader Data", 701 "Boot Code", 702 "Boot Data", 703 "Runtime Code", 704 "Runtime Data", 705 "Conventional Memory", 706 "Unusable Memory", 707 "ACPI Reclaim Memory", 708 "ACPI Memory NVS", 709 "Memory Mapped I/O", 710 "MMIO Port Space", 711 "PAL Code", 712 "Persistent Memory", 713 }; 714 715 char * __init efi_md_typeattr_format(char *buf, size_t size, 716 const efi_memory_desc_t *md) 717 { 718 char *pos; 719 int type_len; 720 u64 attr; 721 722 pos = buf; 723 if (md->type >= ARRAY_SIZE(memory_type_name)) 724 type_len = snprintf(pos, size, "[type=%u", md->type); 725 else 726 type_len = snprintf(pos, size, "[%-*s", 727 (int)(sizeof(memory_type_name[0]) - 1), 728 memory_type_name[md->type]); 729 if (type_len >= size) 730 return buf; 731 732 pos += type_len; 733 size -= type_len; 734 735 attr = md->attribute; 736 if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | 737 EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO | 738 EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP | 739 EFI_MEMORY_NV | 740 EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE)) 741 snprintf(pos, size, "|attr=0x%016llx]", 742 (unsigned long long)attr); 743 else 744 snprintf(pos, size, 745 "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", 746 attr & EFI_MEMORY_RUNTIME ? "RUN" : "", 747 attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "", 748 attr & EFI_MEMORY_NV ? "NV" : "", 749 attr & EFI_MEMORY_XP ? "XP" : "", 750 attr & EFI_MEMORY_RP ? "RP" : "", 751 attr & EFI_MEMORY_WP ? "WP" : "", 752 attr & EFI_MEMORY_RO ? "RO" : "", 753 attr & EFI_MEMORY_UCE ? "UCE" : "", 754 attr & EFI_MEMORY_WB ? "WB" : "", 755 attr & EFI_MEMORY_WT ? "WT" : "", 756 attr & EFI_MEMORY_WC ? "WC" : "", 757 attr & EFI_MEMORY_UC ? "UC" : ""); 758 return buf; 759 } 760 761 /* 762 * efi_mem_attributes - lookup memmap attributes for physical address 763 * @phys_addr: the physical address to lookup 764 * 765 * Search in the EFI memory map for the region covering 766 * @phys_addr. Returns the EFI memory attributes if the region 767 * was found in the memory map, 0 otherwise. 768 * 769 * Despite being marked __weak, most architectures should *not* 770 * override this function. It is __weak solely for the benefit 771 * of ia64 which has a funky EFI memory map that doesn't work 772 * the same way as other architectures. 773 */ 774 u64 __weak efi_mem_attributes(unsigned long phys_addr) 775 { 776 efi_memory_desc_t *md; 777 778 if (!efi_enabled(EFI_MEMMAP)) 779 return 0; 780 781 for_each_efi_memory_desc(md) { 782 if ((md->phys_addr <= phys_addr) && 783 (phys_addr < (md->phys_addr + 784 (md->num_pages << EFI_PAGE_SHIFT)))) 785 return md->attribute; 786 } 787 return 0; 788 } 789 790 int efi_status_to_err(efi_status_t status) 791 { 792 int err; 793 794 switch (status) { 795 case EFI_SUCCESS: 796 err = 0; 797 break; 798 case EFI_INVALID_PARAMETER: 799 err = -EINVAL; 800 break; 801 case EFI_OUT_OF_RESOURCES: 802 err = -ENOSPC; 803 break; 804 case EFI_DEVICE_ERROR: 805 err = -EIO; 806 break; 807 case EFI_WRITE_PROTECTED: 808 err = -EROFS; 809 break; 810 case EFI_SECURITY_VIOLATION: 811 err = -EACCES; 812 break; 813 case EFI_NOT_FOUND: 814 err = -ENOENT; 815 break; 816 case EFI_ABORTED: 817 err = -EINTR; 818 break; 819 default: 820 err = -EINVAL; 821 } 822 823 return err; 824 } 825