embedded-firmware.c 3.4 KB

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