forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'stable-shared-branch-for-driver-tree' of git://git.kernel.…
…org/pub/scm/linux/kernel/git/efi/efi into driver-core-next Ard writes: Stable shared branch between EFI and driver tree Stable shared branch to ease the integration of Hans's series to support device firmware loaded from EFI boot service memory regions. [PATCH v12 00/10] efi/firmware/platform-x86: Add EFI embedded fw support https://lore.kernel.org/linux-efi/[email protected]/ * tag 'stable-shared-branch-for-driver-tree' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efi: Add embedded peripheral firmware support efi: Export boot-services code and data as debugfs-blobs
- Loading branch information
Showing
8 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Support for extracting embedded firmware for peripherals from EFI code, | ||
* | ||
* Copyright (c) 2018 Hans de Goede <[email protected]> | ||
*/ | ||
|
||
#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_GPL(efi_embedded_fw_list); | ||
|
||
static bool checked_for_fw; | ||
|
||
static const struct dmi_system_id * const embedded_fw_table[] = { | ||
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 sha256_state sctx; | ||
struct efi_embedded_fw *fw; | ||
u8 sha256[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_init(&sctx); | ||
sha256_update(&sctx, map + i, desc->length); | ||
sha256_final(&sctx, sha256); | ||
if (memcmp(sha256, 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; | ||
} | ||
} | ||
|
||
checked_for_fw = true; | ||
} | ||
|
||
int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size) | ||
{ | ||
struct efi_embedded_fw *iter, *fw = NULL; | ||
|
||
if (!checked_for_fw) { | ||
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
#ifndef _LINUX_EFI_EMBEDDED_FW_H | ||
#define _LINUX_EFI_EMBEDDED_FW_H | ||
|
||
#include <linux/list.h> | ||
#include <linux/mod_devicetable.h> | ||
|
||
#define EFI_EMBEDDED_FW_PREFIX_LEN 8 | ||
|
||
/* | ||
* This struct and efi_embedded_fw_list are private to the efi-embedded fw | ||
* implementation they are in this header for use by lib/test_firmware.c only! | ||
*/ | ||
struct efi_embedded_fw { | ||
struct list_head list; | ||
const char *name; | ||
const u8 *data; | ||
size_t length; | ||
}; | ||
|
||
extern struct list_head efi_embedded_fw_list; | ||
|
||
/** | ||
* struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw | ||
* code to search for embedded firmwares. | ||
* | ||
* @name: Name to register the firmware with if found | ||
* @prefix: First 8 bytes of the firmware | ||
* @length: Length of the firmware in bytes including prefix | ||
* @sha256: SHA256 of the firmware | ||
*/ | ||
struct efi_embedded_fw_desc { | ||
const char *name; | ||
u8 prefix[EFI_EMBEDDED_FW_PREFIX_LEN]; | ||
u32 length; | ||
u8 sha256[32]; | ||
}; | ||
|
||
int efi_get_embedded_fw(const char *name, const u8 **dat, size_t *sz); | ||
|
||
#endif |