Files
linux/drivers/firmware/efi/embedded-firmware.c
Linus Torvalds bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00

148 lines
3.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Support for extracting embedded firmware for peripherals from EFI code,
*
* Copyright (c) 2018 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/efi_embedded_fw.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <crypto/sha2.h>
/* Exported for use by lib/test_firmware.c only */
LIST_HEAD(efi_embedded_fw_list);
EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, "TEST_FIRMWARE");
bool efi_embedded_fw_checked;
EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, "TEST_FIRMWARE");
static const struct dmi_system_id * const embedded_fw_table[] = {
#ifdef CONFIG_TOUCHSCREEN_DMI
touchscreen_dmi_table,
#endif
NULL
};
/*
* Note the efi_check_for_embedded_firmwares() code currently makes the
* following 2 assumptions. This may needs to be revisited if embedded firmware
* is found where this is not true:
* 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments
* 2) The firmware always starts at an offset which is a multiple of 8 bytes
*/
static int __init efi_check_md_for_embedded_firmware(
efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc)
{
struct efi_embedded_fw *fw;
u8 hash[32];
u64 i, size;
u8 *map;
size = md->num_pages << EFI_PAGE_SHIFT;
map = memremap(md->phys_addr, size, MEMREMAP_WB);
if (!map) {
pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr);
return -ENOMEM;
}
for (i = 0; (i + desc->length) <= size; i += 8) {
if (memcmp(map + i, desc->prefix, EFI_EMBEDDED_FW_PREFIX_LEN))
continue;
sha256(map + i, desc->length, hash);
if (memcmp(hash, desc->sha256, 32) == 0)
break;
}
if ((i + desc->length) > size) {
memunmap(map);
return -ENOENT;
}
pr_info("Found EFI embedded fw '%s'\n", desc->name);
fw = kmalloc_obj(*fw);
if (!fw) {
memunmap(map);
return -ENOMEM;
}
fw->data = kmemdup(map + i, desc->length, GFP_KERNEL);
memunmap(map);
if (!fw->data) {
kfree(fw);
return -ENOMEM;
}
fw->name = desc->name;
fw->length = desc->length;
list_add(&fw->list, &efi_embedded_fw_list);
return 0;
}
void __init efi_check_for_embedded_firmwares(void)
{
const struct efi_embedded_fw_desc *fw_desc;
const struct dmi_system_id *dmi_id;
efi_memory_desc_t *md;
int i, r;
for (i = 0; embedded_fw_table[i]; i++) {
dmi_id = dmi_first_match(embedded_fw_table[i]);
if (!dmi_id)
continue;
fw_desc = dmi_id->driver_data;
/*
* In some drivers the struct driver_data contains may contain
* other driver specific data after the fw_desc struct; and
* the fw_desc struct itself may be empty, skip these.
*/
if (!fw_desc->name)
continue;
for_each_efi_memory_desc(md) {
if (md->type != EFI_BOOT_SERVICES_CODE)
continue;
r = efi_check_md_for_embedded_firmware(md, fw_desc);
if (r == 0)
break;
}
}
efi_embedded_fw_checked = true;
}
int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
{
struct efi_embedded_fw *iter, *fw = NULL;
if (!efi_embedded_fw_checked) {
pr_warn("Warning %s called while we did not check for embedded fw\n",
__func__);
return -ENOENT;
}
list_for_each_entry(iter, &efi_embedded_fw_list, list) {
if (strcmp(name, iter->name) == 0) {
fw = iter;
break;
}
}
if (!fw)
return -ENOENT;
*data = fw->data;
*size = fw->length;
return 0;
}
EXPORT_SYMBOL_GPL(efi_get_embedded_fw);