diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firmware/efi/cper_cxl.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efi/earlycon.c | 41 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-init.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 74 | ||||
-rw-r--r-- | drivers/firmware/efi/esrt.c | 15 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 67 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 23 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/zboot.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/memattr.c | 7 | ||||
-rw-r--r-- | drivers/firmware/efi/sysfb_efi.c | 8 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 38 | ||||
-rw-r--r-- | drivers/firmware/google/gsmi.c | 2 | ||||
-rw-r--r-- | drivers/xen/efi.c | 61 |
13 files changed, 293 insertions, 59 deletions
diff --git a/drivers/firmware/efi/cper_cxl.c b/drivers/firmware/efi/cper_cxl.c index 53e435c4f310..a55771b99a97 100644 --- a/drivers/firmware/efi/cper_cxl.c +++ b/drivers/firmware/efi/cper_cxl.c @@ -9,7 +9,6 @@ #include <linux/cper.h> #include "cper_cxl.h" -#include <linux/cxl_err.h> #define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0) #define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1) @@ -19,6 +18,17 @@ #define PROT_ERR_VALID_DVSEC BIT_ULL(5) #define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6) +/* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */ +struct cxl_ras_capability_regs { + u32 uncor_status; + u32 uncor_mask; + u32 uncor_severity; + u32 cor_status; + u32 cor_mask; + u32 cap_control; + u32 header_log[16]; +}; + static const char * const prot_err_agent_type_strs[] = { "Restricted CXL Device", "Restricted CXL Host Downstream Port", diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c index 4d6c5327471a..f54e6fdf08e2 100644 --- a/drivers/firmware/efi/earlycon.c +++ b/drivers/firmware/efi/earlycon.c @@ -10,11 +10,14 @@ #include <linux/kernel.h> #include <linux/serial_core.h> #include <linux/screen_info.h> +#include <linux/string.h> #include <asm/early_ioremap.h> static const struct console *earlycon_console __initdata; static const struct font_desc *font; +static u16 cur_line_y, max_line_y; +static u32 efi_x_array[1024]; static u32 efi_x, efi_y; static u64 fb_base; static bool fb_wb; @@ -85,9 +88,17 @@ static void efi_earlycon_clear_scanline(unsigned int y) static void efi_earlycon_scroll_up(void) { unsigned long *dst, *src; + u16 maxlen = 0; u16 len; u32 i, height; + /* Find the cached maximum x coordinate */ + for (i = 0; i < max_line_y; i++) { + if (efi_x_array[i] > maxlen) + maxlen = efi_x_array[i]; + } + maxlen *= 4; + len = screen_info.lfb_linelength; height = screen_info.lfb_height; @@ -102,7 +113,7 @@ static void efi_earlycon_scroll_up(void) return; } - memmove(dst, src, len); + memmove(dst, src, maxlen); efi_earlycon_unmap(src, len); efi_earlycon_unmap(dst, len); @@ -135,6 +146,7 @@ static void efi_earlycon_write(struct console *con, const char *str, unsigned int num) { struct screen_info *si; + u32 cur_efi_x = efi_x; unsigned int len; const char *s; void *dst; @@ -143,16 +155,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) len = si->lfb_linelength; while (num) { - unsigned int linemax; - unsigned int h, count = 0; - - for (s = str; *s && *s != '\n'; s++) { - if (count == num) - break; - count++; - } + unsigned int linemax = (si->lfb_width - efi_x) / font->width; + unsigned int h, count; - linemax = (si->lfb_width - efi_x) / font->width; + count = strnchrnul(str, num, '\n') - str; if (count > linemax) count = linemax; @@ -181,6 +187,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) str += count; if (num > 0 && *s == '\n') { + cur_efi_x = efi_x; efi_x = 0; efi_y += font->height; str++; @@ -188,6 +195,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) } if (efi_x + font->width > si->lfb_width) { + cur_efi_x = efi_x; efi_x = 0; efi_y += font->height; } @@ -195,6 +203,9 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) if (efi_y + font->height > si->lfb_height) { u32 i; + efi_x_array[cur_line_y] = cur_efi_x; + cur_line_y = (cur_line_y + 1) % max_line_y; + efi_y -= font->height; efi_earlycon_scroll_up(); @@ -235,7 +246,15 @@ static int __init efi_earlycon_setup(struct earlycon_device *device, if (!font) return -ENODEV; - efi_y = rounddown(yres, font->height) - font->height; + /* Fill the cache with maximum possible value of x coordinate */ + memset32(efi_x_array, rounddown(xres, font->width), ARRAY_SIZE(efi_x_array)); + efi_y = rounddown(yres, font->height); + + /* Make sure we have cache for the x coordinate for the full screen */ + max_line_y = efi_y / font->height + 1; + cur_line_y = 0; + + efi_y -= font->height; for (i = 0; i < (yres - efi_y) / font->height; i++) efi_earlycon_scroll_up(); diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index 1639159493e3..2c16080e1f71 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -92,7 +92,7 @@ static int __init uefi_init(u64 efi_system_table) if (IS_ENABLED(CONFIG_64BIT)) set_bit(EFI_64BIT, &efi.flags); - retval = efi_systab_check_header(&systab->hdr, 2); + retval = efi_systab_check_header(&systab->hdr); if (retval) goto out; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1e0b016fdc2b..abeff7dc0b58 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -187,8 +187,27 @@ static const struct attribute_group efi_subsys_attr_group = { static struct efivars generic_efivars; static struct efivar_operations generic_ops; +static bool generic_ops_supported(void) +{ + unsigned long name_size; + efi_status_t status; + efi_char16_t name; + efi_guid_t guid; + + name_size = sizeof(name); + + status = efi.get_next_variable(&name_size, &name, &guid); + if (status == EFI_UNSUPPORTED) + return false; + + return true; +} + static int generic_ops_register(void) { + if (!generic_ops_supported()) + return 0; + generic_ops.get_variable = efi.get_variable; generic_ops.get_next_variable = efi.get_next_variable; generic_ops.query_variable_store = efi_query_variable_store; @@ -197,11 +216,14 @@ static int generic_ops_register(void) generic_ops.set_variable = efi.set_variable; generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; } - return efivars_register(&generic_efivars, &generic_ops, efi_kobj); + return efivars_register(&generic_efivars, &generic_ops); } static void generic_ops_unregister(void) { + if (!generic_ops.get_variable) + return; + efivars_unregister(&generic_efivars); } @@ -481,7 +503,7 @@ void __init efi_find_mirror(void) * and if so, populate the supplied memory descriptor with the appropriate * data. */ -int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) +int __efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) { efi_memory_desc_t *md; @@ -499,6 +521,12 @@ int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) u64 size; u64 end; + /* skip bogus entries (including empty ones) */ + if ((md->phys_addr & (EFI_PAGE_SIZE - 1)) || + (md->num_pages <= 0) || + (md->num_pages > (U64_MAX - md->phys_addr) >> EFI_PAGE_SHIFT)) + continue; + size = md->num_pages << EFI_PAGE_SHIFT; end = md->phys_addr + size; if (phys_addr >= md->phys_addr && phys_addr < end) { @@ -509,6 +537,9 @@ int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) return -ENOENT; } +extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) + __weak __alias(__efi_mem_desc_lookup); + /* * Calculate the highest address of an efi memory descriptor. */ @@ -535,6 +566,10 @@ void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {} */ void __init efi_mem_reserve(phys_addr_t addr, u64 size) { + /* efi_mem_reserve() does not work under Xen */ + if (WARN_ON_ONCE(efi_enabled(EFI_PARAVIRT))) + return; + if (!memblock_is_region_reserved(addr, size)) memblock_reserve(addr, size); @@ -583,13 +618,20 @@ static __init int match_config_table(const efi_guid_t *guid, int i; for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { - if (!efi_guidcmp(*guid, table_types[i].guid)) { - *(table_types[i].ptr) = table; + if (efi_guidcmp(*guid, table_types[i].guid)) + continue; + + if (!efi_config_table_is_usable(guid, table)) { if (table_types[i].name[0]) - pr_cont("%s=0x%lx ", + pr_cont("(%s=0x%lx unusable) ", table_types[i].name, table); return 1; } + + *(table_types[i].ptr) = table; + if (table_types[i].name[0]) + pr_cont("%s=0x%lx ", table_types[i].name, table); + return 1; } return 0; @@ -720,20 +762,13 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables, return 0; } -int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr, - int min_major_version) +int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr) { if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) { pr_err("System table signature incorrect!\n"); return -EINVAL; } - if ((systab_hdr->revision >> 16) < min_major_version) - pr_err("Warning: System table version %d.%02d, expected %d.00 or greater!\n", - systab_hdr->revision >> 16, - systab_hdr->revision & 0xffff, - min_major_version); - return 0; } @@ -764,6 +799,7 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr, char vendor[100] = "unknown"; const efi_char16_t *c16; size_t i; + u16 rev; c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t)); if (c16) { @@ -774,10 +810,14 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr, unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t)); } - pr_info("EFI v%u.%.02u by %s\n", - systab_hdr->revision >> 16, - systab_hdr->revision & 0xffff, - vendor); + rev = (u16)systab_hdr->revision; + pr_info("EFI v%u.%u", systab_hdr->revision >> 16, rev / 10); + + rev %= 10; + if (rev) + pr_cont(".%u", rev); + + pr_cont(" by %s\n", vendor); if (IS_ENABLED(CONFIG_X86_64) && systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION && diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 2a2f52b017e7..87729c365be1 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -247,7 +247,7 @@ void __init efi_esrt_init(void) int rc; phys_addr_t end; - if (!efi_enabled(EFI_MEMMAP)) + if (!efi_enabled(EFI_MEMMAP) && !efi_enabled(EFI_PARAVIRT)) return; pr_debug("esrt-init: loading.\n"); @@ -258,20 +258,15 @@ void __init efi_esrt_init(void) if (rc < 0 || (!(md.attribute & EFI_MEMORY_RUNTIME) && md.type != EFI_BOOT_SERVICES_DATA && - md.type != EFI_RUNTIME_SERVICES_DATA)) { + md.type != EFI_RUNTIME_SERVICES_DATA && + md.type != EFI_ACPI_RECLAIM_MEMORY && + md.type != EFI_ACPI_MEMORY_NVS)) { pr_warn("ESRT header is not in the memory map.\n"); return; } - max = efi_mem_desc_end(&md); - if (max < efi.esrt) { - pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n", - (void *)efi.esrt, (void *)max); - return; - } - + max = efi_mem_desc_end(&md) - efi.esrt; size = sizeof(*esrt); - max -= efi.esrt; if (max < size) { pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n", diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index f5a4bdacac64..1e0203d74691 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -651,3 +651,70 @@ efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key) return status; } + +/** + * efi_remap_image - Remap a loaded image with the appropriate permissions + * for code and data + * + * @image_base: the base of the image in memory + * @alloc_size: the size of the area in memory occupied by the image + * @code_size: the size of the leading part of the image containing code + * and read-only data + * + * efi_remap_image() uses the EFI memory attribute protocol to remap the code + * region of the loaded image read-only/executable, and the remainder + * read-write/non-executable. The code region is assumed to start at the base + * of the image, and will therefore cover the PE/COFF header as well. + */ +void efi_remap_image(unsigned long image_base, unsigned alloc_size, + unsigned long code_size) +{ + efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; + efi_memory_attribute_protocol_t *memattr; + efi_status_t status; + u64 attr; + + /* + * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's + * invoke it to remap the text/rodata region of the decompressed image + * as read-only and the data/bss region as non-executable. + */ + status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr); + if (status != EFI_SUCCESS) + return; + + // Get the current attributes for the entire region + status = memattr->get_memory_attributes(memattr, image_base, + alloc_size, &attr); + if (status != EFI_SUCCESS) { + efi_warn("Failed to retrieve memory attributes for image region: 0x%lx\n", + status); + return; + } + + // Mark the code region as read-only + status = memattr->set_memory_attributes(memattr, image_base, code_size, + EFI_MEMORY_RO); + if (status != EFI_SUCCESS) { + efi_warn("Failed to remap code region read-only\n"); + return; + } + + // If the entire region was already mapped as non-exec, clear the + // attribute from the code region. Otherwise, set it on the data + // region. + if (attr & EFI_MEMORY_XP) { + status = memattr->clear_memory_attributes(memattr, image_base, + code_size, + EFI_MEMORY_XP); + if (status != EFI_SUCCESS) + efi_warn("Failed to remap code region executable\n"); + } else { + status = memattr->set_memory_attributes(memattr, + image_base + code_size, + alloc_size - code_size, + EFI_MEMORY_XP); + if (status != EFI_SUCCESS) + efi_warn("Failed to remap data region non-executable\n"); + } +} diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 5b8f2c411ed8..6bd3bb86d967 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -442,6 +442,26 @@ union efi_dxe_services_table { } mixed_mode; }; +typedef union efi_memory_attribute_protocol efi_memory_attribute_protocol_t; + +union efi_memory_attribute_protocol { + struct { + efi_status_t (__efiapi *get_memory_attributes)( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64 *); + + efi_status_t (__efiapi *set_memory_attributes)( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64); + + efi_status_t (__efiapi *clear_memory_attributes)( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64); + }; + struct { + u32 get_memory_attributes; + u32 set_memory_attributes; + u32 clear_memory_attributes; + } mixed_mode; +}; + typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t; union efi_uga_draw_protocol { @@ -1076,4 +1096,7 @@ struct efi_smbios_type1_record { const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize); +void efi_remap_image(unsigned long image_base, unsigned alloc_size, + unsigned long code_size); + #endif diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index 66be5fdc6b58..ba234e062a1a 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -137,6 +137,8 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) efi_cache_sync_image(image_base, alloc_size, code_size); + efi_remap_image(image_base, alloc_size, code_size); + status = efi_stub_common(handle, image, image_base, cmdline_ptr); free_image: diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index f178b2984dfb..ab85bf8e165a 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -129,6 +129,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm, efi_memattr_perm_setter fn) { efi_memory_attributes_table_t *tbl; + bool has_bti = false; int i, ret; if (tbl_size <= sizeof(*tbl)) @@ -150,6 +151,10 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm, return -ENOMEM; } + if (tbl->version > 1 && + (tbl->flags & EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD)) + has_bti = true; + if (efi_enabled(EFI_DBG)) pr_info("Processing EFI Memory Attributes table:\n"); @@ -169,7 +174,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm, efi_md_typeattr_format(buf, sizeof(buf), &md)); if (valid) { - ret = fn(mm, &md); + ret = fn(mm, &md, has_bti); if (ret) pr_err("Error updating mappings, skipping subsequent md's\n"); } diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c index 7882d4b3f2be..f06fdacc9bc8 100644 --- a/drivers/firmware/efi/sysfb_efi.c +++ b/drivers/firmware/efi/sysfb_efi.c @@ -264,6 +264,14 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { "Lenovo ideapad D330-10IGM"), }, }, + { + /* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, + "IdeaPad Duet 3 10IGL5"), + }, + }, {}, }; diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 0ba9f18312f5..bd75b87f5fc1 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -6,6 +6,8 @@ * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> */ +#define pr_fmt(fmt) "efivars: " fmt + #include <linux/types.h> #include <linux/sizes.h> #include <linux/errno.h> @@ -40,45 +42,47 @@ static efi_status_t check_var_size(bool nonblocking, u32 attributes, } /** - * efivars_kobject - get the kobject for the registered efivars + * efivar_is_available - check if efivars is available * - * If efivars_register() has not been called we return NULL, - * otherwise return the kobject used at registration time. + * @return true iff evivars is currently registered */ -struct kobject *efivars_kobject(void) +bool efivar_is_available(void) { - if (!__efivars) - return NULL; - - return __efivars->kobject; + return __efivars != NULL; } -EXPORT_SYMBOL_GPL(efivars_kobject); +EXPORT_SYMBOL_GPL(efivar_is_available); /** * efivars_register - register an efivars * @efivars: efivars to register * @ops: efivars operations - * @kobject: @efivars-specific kobject * * Only a single efivars can be registered at any time. */ int efivars_register(struct efivars *efivars, - const struct efivar_operations *ops, - struct kobject *kobject) + const struct efivar_operations *ops) { + int rv; + if (down_interruptible(&efivars_lock)) return -EINTR; + if (__efivars) { + pr_warn("efivars already registered\n"); + rv = -EBUSY; + goto out; + } + efivars->ops = ops; - efivars->kobject = kobject; __efivars = efivars; pr_info("Registered efivars operations\n"); - + rv = 0; +out: up(&efivars_lock); - return 0; + return rv; } EXPORT_SYMBOL_GPL(efivars_register); @@ -97,7 +101,7 @@ int efivars_unregister(struct efivars *efivars) return -EINTR; if (!__efivars) { - printk(KERN_ERR "efivars not registered\n"); + pr_err("efivars not registered\n"); rv = -EINVAL; goto out; } @@ -117,7 +121,7 @@ out: } EXPORT_SYMBOL_GPL(efivars_unregister); -int efivar_supports_writes(void) +bool efivar_supports_writes(void) { return __efivars && __efivars->ops->set_variable; } diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 871bedf533a8..96ea1fa76d35 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -1030,7 +1030,7 @@ static __init int gsmi_init(void) } #ifdef CONFIG_EFI - ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); + ret = efivars_register(&efivars, &efivar_ops); if (ret) { printk(KERN_INFO "gsmi: Failed to register efivars\n"); sysfs_remove_files(gsmi_kobj, gsmi_attrs); diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c index d1ff2186ebb4..fb321cd6415a 100644 --- a/drivers/xen/efi.c +++ b/drivers/xen/efi.c @@ -26,6 +26,7 @@ #include <xen/interface/xen.h> #include <xen/interface/platform.h> +#include <xen/page.h> #include <xen/xen.h> #include <xen/xen-ops.h> @@ -292,3 +293,63 @@ void __init xen_efi_runtime_setup(void) efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count; efi.reset_system = xen_efi_reset_system; } + +int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) +{ + static_assert(XEN_PAGE_SHIFT == EFI_PAGE_SHIFT, + "Mismatch between EFI_PAGE_SHIFT and XEN_PAGE_SHIFT"); + struct xen_platform_op op; + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info; + int rc; + + if (!efi_enabled(EFI_PARAVIRT) || efi_enabled(EFI_MEMMAP)) + return __efi_mem_desc_lookup(phys_addr, out_md); + phys_addr &= ~(u64)(EFI_PAGE_SIZE - 1); + op = (struct xen_platform_op) { + .cmd = XENPF_firmware_info, + .u.firmware_info = { + .type = XEN_FW_EFI_INFO, + .index = XEN_FW_EFI_MEM_INFO, + .u.efi_info.mem.addr = phys_addr, + .u.efi_info.mem.size = U64_MAX - phys_addr, + }, + }; + + rc = HYPERVISOR_platform_op(&op); + if (rc) { + pr_warn("Failed to lookup header 0x%llx in Xen memory map: error %d\n", + phys_addr, rc); + } + + out_md->phys_addr = info->mem.addr; + out_md->num_pages = info->mem.size >> EFI_PAGE_SHIFT; + out_md->type = info->mem.type; + out_md->attribute = info->mem.attr; + + return 0; +} + +bool __init xen_efi_config_table_is_usable(const efi_guid_t *guid, + unsigned long table) +{ + efi_memory_desc_t md; + int rc; + + if (!efi_enabled(EFI_PARAVIRT)) + return true; + + rc = efi_mem_desc_lookup(table, &md); + if (rc) + return false; + + switch (md.type) { + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_ACPI_RECLAIM_MEMORY: + case EFI_ACPI_MEMORY_NVS: + case EFI_RESERVED_TYPE: + return true; + default: + return false; + } +} |