Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// 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/sha.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(sizeof(*fw), GFP_KERNEL);
<------>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);