linux/drivers/firmware/efi/embedded-firmware.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for extracting embedded firmware for peripherals from EFI code,
   4 *
   5 * Copyright (c) 2018 Hans de Goede <hdegoede@redhat.com>
   6 */
   7
   8#include <linux/dmi.h>
   9#include <linux/efi.h>
  10#include <linux/efi_embedded_fw.h>
  11#include <linux/io.h>
  12#include <linux/slab.h>
  13#include <linux/types.h>
  14#include <linux/vmalloc.h>
  15#include <crypto/sha2.h>
  16
  17/* Exported for use by lib/test_firmware.c only */
  18LIST_HEAD(efi_embedded_fw_list);
  19EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, TEST_FIRMWARE);
  20bool efi_embedded_fw_checked;
  21EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, TEST_FIRMWARE);
  22
  23static const struct dmi_system_id * const embedded_fw_table[] = {
  24#ifdef CONFIG_TOUCHSCREEN_DMI
  25        touchscreen_dmi_table,
  26#endif
  27        NULL
  28};
  29
  30/*
  31 * Note the efi_check_for_embedded_firmwares() code currently makes the
  32 * following 2 assumptions. This may needs to be revisited if embedded firmware
  33 * is found where this is not true:
  34 * 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments
  35 * 2) The firmware always starts at an offset which is a multiple of 8 bytes
  36 */
  37static int __init efi_check_md_for_embedded_firmware(
  38        efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc)
  39{
  40        struct efi_embedded_fw *fw;
  41        u8 hash[32];
  42        u64 i, size;
  43        u8 *map;
  44
  45        size = md->num_pages << EFI_PAGE_SHIFT;
  46        map = memremap(md->phys_addr, size, MEMREMAP_WB);
  47        if (!map) {
  48                pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr);
  49                return -ENOMEM;
  50        }
  51
  52        for (i = 0; (i + desc->length) <= size; i += 8) {
  53                if (memcmp(map + i, desc->prefix, EFI_EMBEDDED_FW_PREFIX_LEN))
  54                        continue;
  55
  56                sha256(map + i, desc->length, hash);
  57                if (memcmp(hash, desc->sha256, 32) == 0)
  58                        break;
  59        }
  60        if ((i + desc->length) > size) {
  61                memunmap(map);
  62                return -ENOENT;
  63        }
  64
  65        pr_info("Found EFI embedded fw '%s'\n", desc->name);
  66
  67        fw = kmalloc(sizeof(*fw), GFP_KERNEL);
  68        if (!fw) {
  69                memunmap(map);
  70                return -ENOMEM;
  71        }
  72
  73        fw->data = kmemdup(map + i, desc->length, GFP_KERNEL);
  74        memunmap(map);
  75        if (!fw->data) {
  76                kfree(fw);
  77                return -ENOMEM;
  78        }
  79
  80        fw->name = desc->name;
  81        fw->length = desc->length;
  82        list_add(&fw->list, &efi_embedded_fw_list);
  83
  84        return 0;
  85}
  86
  87void __init efi_check_for_embedded_firmwares(void)
  88{
  89        const struct efi_embedded_fw_desc *fw_desc;
  90        const struct dmi_system_id *dmi_id;
  91        efi_memory_desc_t *md;
  92        int i, r;
  93
  94        for (i = 0; embedded_fw_table[i]; i++) {
  95                dmi_id = dmi_first_match(embedded_fw_table[i]);
  96                if (!dmi_id)
  97                        continue;
  98
  99                fw_desc = dmi_id->driver_data;
 100
 101                /*
 102                 * In some drivers the struct driver_data contains may contain
 103                 * other driver specific data after the fw_desc struct; and
 104                 * the fw_desc struct itself may be empty, skip these.
 105                 */
 106                if (!fw_desc->name)
 107                        continue;
 108
 109                for_each_efi_memory_desc(md) {
 110                        if (md->type != EFI_BOOT_SERVICES_CODE)
 111                                continue;
 112
 113                        r = efi_check_md_for_embedded_firmware(md, fw_desc);
 114                        if (r == 0)
 115                                break;
 116                }
 117        }
 118
 119        efi_embedded_fw_checked = true;
 120}
 121
 122int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
 123{
 124        struct efi_embedded_fw *iter, *fw = NULL;
 125
 126        if (!efi_embedded_fw_checked) {
 127                pr_warn("Warning %s called while we did not check for embedded fw\n",
 128                        __func__);
 129                return -ENOENT;
 130        }
 131
 132        list_for_each_entry(iter, &efi_embedded_fw_list, list) {
 133                if (strcmp(name, iter->name) == 0) {
 134                        fw = iter;
 135                        break;
 136                }
 137        }
 138
 139        if (!fw)
 140                return -ENOENT;
 141
 142        *data = fw->data;
 143        *size = fw->length;
 144
 145        return 0;
 146}
 147EXPORT_SYMBOL_GPL(efi_get_embedded_fw);
 148