efi_selftest_esrt.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Test ESRT tables support
  4. *
  5. * Copyright (C) 2021 Arm Ltd.
  6. */
  7. #include <common.h>
  8. #include <efi_loader.h>
  9. #include <efi_selftest.h>
  10. // This value must not exceed 255.
  11. // An FMP cannot contain more than 255 FW images.
  12. #define TEST_ESRT_NUM_ENTRIES 255
  13. static
  14. struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES];
  15. static const struct efi_system_table *local_systable;
  16. static efi_handle_t fmp_handle;
  17. static const efi_guid_t efi_fmp_guid =
  18. EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
  19. static void efi_test_esrt_init_info(void)
  20. {
  21. for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) {
  22. static_img_info[idx].image_index = idx;
  23. // Note: the 16 byte value present in
  24. // static_img_info[idx].image_type_id is not strictly a GUID.
  25. // The value is used for the sake of code testing.
  26. static_img_info[idx].image_type_id.b[0] = idx;
  27. static_img_info[idx].image_id = 0;
  28. static_img_info[idx].image_id_name = NULL;
  29. static_img_info[idx].version = 0;
  30. static_img_info[idx].version_name = NULL;
  31. static_img_info[idx].size = 0;
  32. static_img_info[idx].lowest_supported_image_version = 1;
  33. static_img_info[idx].last_attempt_version = 2;
  34. static_img_info[idx].last_attempt_status = 3;
  35. static_img_info[idx].hardware_instance = 1;
  36. }
  37. }
  38. static efi_status_t
  39. EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this,
  40. efi_uintn_t *image_info_size,
  41. struct efi_firmware_image_descriptor *image_info,
  42. u32 *descriptor_version,
  43. u8 *descriptor_count,
  44. efi_uintn_t *descriptor_size,
  45. u32 *package_version,
  46. u16 **package_version_name)
  47. {
  48. efi_status_t ret = EFI_SUCCESS;
  49. if (!image_info_size)
  50. return EFI_INVALID_PARAMETER;
  51. if (descriptor_version)
  52. *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
  53. if (descriptor_count)
  54. *descriptor_count = TEST_ESRT_NUM_ENTRIES;
  55. if (descriptor_size)
  56. *descriptor_size = sizeof(*image_info);
  57. if (package_version)
  58. *package_version = 0xffffffff;
  59. if (package_version_name)
  60. *package_version_name = NULL;
  61. if (*image_info_size < sizeof(*image_info)) {
  62. *image_info_size = *descriptor_size * *descriptor_count;
  63. return EFI_BUFFER_TOO_SMALL;
  64. }
  65. for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
  66. image_info[idx] = static_img_info[idx];
  67. return ret;
  68. }
  69. static struct efi_firmware_management_protocol efi_test_fmp = {
  70. .get_image_info = efi_test_fmp_get_image_info,
  71. .get_image = NULL,
  72. .set_image = NULL,
  73. .check_image = NULL,
  74. .get_package_info = NULL,
  75. .set_package_info = NULL,
  76. };
  77. static void *lib_test_get_esrt(void)
  78. {
  79. for (int idx = 0; idx < local_systable->nr_tables; idx++)
  80. if (!guidcmp(&efi_esrt_guid, &local_systable->tables[idx].guid))
  81. return local_systable->tables[idx].table;
  82. return NULL;
  83. }
  84. /**
  85. * lib_test_check_uuid_entry: Find an ESRT entry for which the fw_calss field matches
  86. * the image_type_id in the @img_info.
  87. * Ensure that all of the field in the ESRT entry have the same value as the corresponding
  88. * fields in the @img_info.
  89. *
  90. * @esrt: pointer to the ESRT
  91. * @img_info: an image_info_descriptor output by the FMP get_image_info
  92. *
  93. * @return: true if matching ESRT entry is found and if all the ESRT entry fields match the
  94. * corresponding @img_info fields.
  95. */
  96. static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt,
  97. struct efi_firmware_image_descriptor
  98. *img_info)
  99. {
  100. const u32 filled_entries = esrt->fw_resource_count;
  101. struct efi_system_resource_entry *entry = esrt->entries;
  102. for (u32 idx = 0; idx < filled_entries; idx++) {
  103. if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) {
  104. if (entry[idx].fw_version != img_info->version) {
  105. efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
  106. &img_info->image_type_id);
  107. return false;
  108. }
  109. if (entry[idx].lowest_supported_fw_version !=
  110. img_info->lowest_supported_image_version) {
  111. efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
  112. &img_info->image_type_id);
  113. return false;
  114. }
  115. if (entry[idx].last_attempt_version !=
  116. img_info->last_attempt_version) {
  117. efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
  118. &img_info->image_type_id);
  119. return false;
  120. }
  121. if (entry[idx].last_attempt_status !=
  122. img_info->last_attempt_status) {
  123. efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
  124. &img_info->image_type_id);
  125. return false;
  126. }
  127. /*
  128. * The entry with fw_class = img_uuid matches with the
  129. * remainder fmp input.
  130. */
  131. return true;
  132. }
  133. }
  134. /* There exists no entry with fw_class equal to img_uuid in the ESRT. */
  135. efi_st_error("ESRT no entry with fw_class= %pUl\n", &img_info->image_type_id);
  136. return false;
  137. }
  138. /*
  139. * Setup unit test.
  140. *
  141. * Initialize the test FMP datastructure.
  142. *
  143. * @handle: handle of the loaded image
  144. * @systable: system table
  145. * @return: EFI_ST_SUCCESS for success
  146. */
  147. static int setup(const efi_handle_t handle,
  148. const struct efi_system_table *systable)
  149. {
  150. local_systable = systable;
  151. efi_test_esrt_init_info();
  152. return EFI_ST_SUCCESS;
  153. }
  154. /*
  155. * Tear down unit test.
  156. *
  157. * Uninstall the test FMP.
  158. *
  159. * @return: EFI_ST_SUCCESS for success
  160. */
  161. static int teardown(void)
  162. {
  163. efi_status_t ret = EFI_SUCCESS;
  164. struct efi_boot_services *bt;
  165. bt = local_systable->boottime;
  166. if (!bt) {
  167. efi_st_error("Cannot find boottime services structure\n");
  168. return EFI_ST_FAILURE;
  169. }
  170. ret = bt->uninstall_multiple_protocol_interfaces
  171. (fmp_handle, &efi_fmp_guid,
  172. &efi_test_fmp, NULL);
  173. if (ret != EFI_SUCCESS) {
  174. efi_st_error("Failed to uninstall FMP\n");
  175. return EFI_ST_FAILURE;
  176. }
  177. return EFI_ST_SUCCESS;
  178. }
  179. /*
  180. * Perform the test
  181. *
  182. * The test consists of the following steps:
  183. *
  184. * 1) Obtain the ESRT
  185. * 2) Record the number of ESRT entries prior to test start
  186. * 3) Install the test FMP
  187. * 4) Re-obtain the ESRT (the ESRT pointer may have changed with the FMP install)
  188. * 5) verify that the ESRT entries have increased by the number of entries in the
  189. * test FMP.
  190. * 6) Traverse all the elements used as the test FMP input and verify that each
  191. * has a corresponding ESRT entry and that the fields are correctly set.
  192. *
  193. * The failure of any of the above steps results in a test failure.
  194. *
  195. */
  196. static int execute(void)
  197. {
  198. struct efi_system_resource_table *esrt;
  199. efi_status_t ret = EFI_SUCCESS;
  200. u32 base_entry_count;
  201. u32 entry_delta;
  202. struct efi_boot_services *bt;
  203. bt = local_systable->boottime;
  204. if (!bt) {
  205. efi_st_error("Cannot find boottime services structure\n");
  206. return EFI_ST_FAILURE;
  207. }
  208. esrt = lib_test_get_esrt();
  209. if (!esrt) {
  210. efi_st_error("ESRT table not present\n");
  211. return EFI_ST_FAILURE;
  212. }
  213. base_entry_count = esrt->fw_resource_count;
  214. ret = bt->install_multiple_protocol_interfaces(&fmp_handle,
  215. &efi_fmp_guid,
  216. &efi_test_fmp,
  217. NULL);
  218. if (ret != EFI_SUCCESS) {
  219. efi_st_error("Failed to install FMP\n");
  220. return EFI_ST_FAILURE;
  221. }
  222. esrt = lib_test_get_esrt();
  223. if (!esrt) {
  224. efi_st_error("ESRT table not present\n");
  225. return EFI_ST_FAILURE;
  226. }
  227. entry_delta = esrt->fw_resource_count - base_entry_count;
  228. if (entry_delta != TEST_ESRT_NUM_ENTRIES) {
  229. efi_st_error("ESRT mismatch in new entry count (%d), expected (%d).\n",
  230. entry_delta, TEST_ESRT_NUM_ENTRIES);
  231. return EFI_ST_FAILURE;
  232. }
  233. for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
  234. if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx])) {
  235. efi_st_error("ESRT entry mismatch\n");
  236. return EFI_ST_FAILURE;
  237. }
  238. return EFI_ST_SUCCESS;
  239. }
  240. EFI_UNIT_TEST(esrt) = {
  241. .name = "esrt",
  242. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  243. .setup = setup,
  244. .execute = execute,
  245. .teardown = teardown,
  246. };