diff options
| -rw-r--r-- | drivers/firmware/efi/capsule-loader.c | 2 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi-bgrt.c | 7 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi.c | 31 | ||||
| -rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 12 | ||||
| -rw-r--r-- | drivers/firmware/efi/memattr.c | 37 | ||||
| -rw-r--r-- | include/linux/efi.h | 21 | ||||
| -rw-r--r-- | include/linux/memblock.h | 1 | ||||
| -rw-r--r-- | mm/memblock.c | 15 |
8 files changed, 68 insertions, 58 deletions
diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 2c628a127091..8e8f81f0a5a0 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) cap_info->pages = temp_page; temp_page = krealloc(cap_info->phys, - pages_needed * sizeof(phys_addr_t *), + pages_needed * sizeof(phys_addr_t), GFP_KERNEL | __GFP_ZERO); if (!temp_page) return -ENOMEM; diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 6aafdb67dbca..1da451582812 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -29,11 +29,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table) void *image; struct bmp_header bmp_header; struct acpi_table_bgrt *bgrt = &bgrt_tab; + int mem_type; if (acpi_disabled) return; - if (!efi_enabled(EFI_MEMMAP)) + if (!efi_enabled(EFI_MEMMAP) && !efi_enabled(EFI_PARAVIRT)) return; if (table->length < sizeof(bgrt_tab)) { @@ -62,7 +63,9 @@ void __init efi_bgrt_init(struct acpi_table_header *table) goto out; } - if (efi_mem_type(bgrt->image_address) != EFI_BOOT_SERVICES_DATA) { + mem_type = efi_mem_type(bgrt->image_address); + if (mem_type != EFI_BOOT_SERVICES_DATA && + mem_type != EFI_ACPI_RECLAIM_MEMORY) { pr_notice("Ignoring BGRT: invalid image address\n"); goto out; } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 3dab284a7754..d04be38f1750 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -600,7 +600,9 @@ void __init efi_mem_reserve(phys_addr_t addr, u64 size) return; if (!memblock_is_region_reserved(addr, size)) - memblock_reserve(addr, size); + memblock_reserve_kern(addr, size); + else + memblock_reserved_mark_kern(addr, size); /* * Some architectures (x86) reserve all boot services ranges @@ -983,18 +985,12 @@ char * __init efi_md_typeattr_format(char *buf, size_t size, */ u64 efi_mem_attributes(unsigned long phys_addr) { - efi_memory_desc_t *md; + efi_memory_desc_t md; - if (!efi_enabled(EFI_MEMMAP)) + if (efi_mem_desc_lookup(phys_addr, &md)) return 0; - for_each_efi_memory_desc(md) { - if ((md->phys_addr <= phys_addr) && - (phys_addr < (md->phys_addr + - (md->num_pages << EFI_PAGE_SHIFT)))) - return md->attribute; - } - return 0; + return md.attribute; } /* @@ -1007,18 +1003,15 @@ u64 efi_mem_attributes(unsigned long phys_addr) */ int efi_mem_type(unsigned long phys_addr) { - const efi_memory_desc_t *md; + efi_memory_desc_t md; - if (!efi_enabled(EFI_MEMMAP)) + if (!efi_enabled(EFI_MEMMAP) && !efi_enabled(EFI_PARAVIRT)) return -ENOTSUPP; - for_each_efi_memory_desc(md) { - if ((md->phys_addr <= phys_addr) && - (phys_addr < (md->phys_addr + - (md->num_pages << EFI_PAGE_SHIFT)))) - return md->type; - } - return -EINVAL; + if (efi_mem_desc_lookup(phys_addr, &md)) + return -EINVAL; + + return md.type; } int efi_status_to_err(efi_status_t status) diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 6a337f1f8787..23b3543d3041 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -32,8 +32,8 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size, { int node, num_rsv; int status; - u32 fdt_val32; - u64 fdt_val64; + fdt32_t fdt_val32; + fdt64_t fdt_val64; /* Do some checks on provided FDT, if it exists: */ if (orig_fdt) { @@ -100,13 +100,13 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size, if (status) goto fdt_set_fail; - fdt_val64 = U64_MAX; /* placeholder */ + fdt_val64 = cpu_to_fdt64(U64_MAX); /* placeholder */ status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-start", fdt_val64); if (status) goto fdt_set_fail; - fdt_val32 = U32_MAX; /* placeholder */ + fdt_val32 = cpu_to_fdt32(U32_MAX); /* placeholder */ status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-size", fdt_val32); if (status) @@ -147,8 +147,8 @@ fdt_set_fail: static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map) { int node = fdt_path_offset(fdt, "/chosen"); - u64 fdt_val64; - u32 fdt_val32; + fdt64_t fdt_val64; + fdt32_t fdt_val32; int err; if (node < 0) diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index e727cc5909cb..5edbffd4e4b7 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -22,7 +22,6 @@ unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR; void __init efi_memattr_init(void) { efi_memory_attributes_table_t *tbl; - unsigned long size; if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR) return; @@ -40,22 +39,42 @@ void __init efi_memattr_init(void) goto unmap; } + /* + * The EFI memory attributes table descriptors might potentially be + * smaller than those used by the EFI memory map, as long as they can + * fit a efi_memory_desc_t. However, a larger descriptor size makes no + * sense, and might be an indication that the table is corrupted. + * + * The only exception is kexec_load(), where the EFI memory map is + * reconstructed by user space, and may use a smaller descriptor size + * than the original. Given that, ignoring this companion table is + * still the right thing to do here, but don't complain too loudly when + * this happens. + */ + if (tbl->desc_size < sizeof(efi_memory_desc_t) || + tbl->desc_size > efi.memmap.desc_size) { + pr_warn("Unexpected EFI Memory Attributes descriptor size %u (expected: %lu)\n", + tbl->desc_size, efi.memmap.desc_size); + goto unmap; + } /* - * Sanity check: the Memory Attributes Table contains up to 3 entries - * for each entry of type EfiRuntimeServicesCode in the EFI memory map. - * So if the size of the table exceeds 3x the size of the entire EFI - * memory map, there is clearly something wrong, and the table should - * just be ignored altogether. + * Sanity check: the Memory Attributes Table contains multiple entries + * for each EFI runtime services code or data region in the EFI memory + * map, each with the permission attributes that may be applied when + * mapping the region. There is no upper bound for the number of + * entries, as it could conceivably contain more entries than the EFI + * memory map itself. So pick an arbitrary limit of 64k, which is + * ludicrously high. This prevents a corrupted table from eating all + * system RAM. */ - size = tbl->num_entries * tbl->desc_size; - if (size > 3 * efi.memmap.nr_map * efi.memmap.desc_size) { + if (tbl->num_entries > SZ_64K) { pr_warn(FW_BUG "Corrupted EFI Memory Attributes Table detected! (version == %u, desc_size == %u, num_entries == %u)\n", tbl->version, tbl->desc_size, tbl->num_entries); goto unmap; } - tbl_size = sizeof(*tbl) + size; + tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size; memblock_reserve(efi_mem_attr_table, tbl_size); set_bit(EFI_MEM_ATTR, &efi.flags); diff --git a/include/linux/efi.h b/include/linux/efi.h index 664898d09ff5..72e76ec54641 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -832,27 +832,6 @@ extern int __init parse_efi_signature_list( const void *data, size_t size, efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *)); -/** - * efi_range_is_wc - check the WC bit on an address range - * @start: starting kvirt address - * @len: length of range - * - * Consult the EFI memory map and make sure it's ok to set this range WC. - * Returns true or false. - */ -static inline int efi_range_is_wc(unsigned long start, unsigned long len) -{ - unsigned long i; - - for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { - unsigned long paddr = __pa(start + i); - if (!(efi_mem_attributes(paddr) & EFI_MEMORY_WC)) - return 0; - } - /* The range checked out */ - return 1; -} - /* * We play games with efi_enabled so that the compiler will, if * possible, remove EFI-related code altogether. diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 6ec5e9ac0699..9eac4f268359 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -155,6 +155,7 @@ int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); int memblock_clear_nomap(phys_addr_t base, phys_addr_t size); int memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size); +int memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size); int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size); int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size); diff --git a/mm/memblock.c b/mm/memblock.c index b3ddfdec7a80..2505ce8b319c 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1116,6 +1116,21 @@ int __init_memblock memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t } /** + * memblock_reserved_mark_kern - Mark a reserved memory region with flag + * MEMBLOCK_RSRV_KERN + * + * @base: the base phys addr of the region + * @size: the size of the region + * + * Return: 0 on success, -errno on failure. + */ +int __init_memblock memblock_reserved_mark_kern(phys_addr_t base, phys_addr_t size) +{ + return memblock_setclr_flag(&memblock.reserved, base, size, 1, + MEMBLOCK_RSRV_KERN); +} + +/** * memblock_mark_kho_scratch - Mark a memory region as MEMBLOCK_KHO_SCRATCH. * @base: the base phys addr of the region * @size: the size of the region |
