efi_selftest_memory.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * efi_selftest_memory
  4. *
  5. * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * This unit test checks the following boottime services:
  8. * AllocatePages, FreePages, GetMemoryMap
  9. *
  10. * The memory type used for the device tree is checked.
  11. */
  12. #include <efi_selftest.h>
  13. #define EFI_ST_NUM_PAGES 8
  14. static const efi_guid_t fdt_guid = EFI_FDT_GUID;
  15. static struct efi_boot_services *boottime;
  16. static u64 fdt_addr;
  17. /**
  18. * setup() - setup unit test
  19. *
  20. * @handle: handle of the loaded image
  21. * @systable: system table
  22. * Return: EFI_ST_SUCCESS for success
  23. */
  24. static int setup(const efi_handle_t handle,
  25. const struct efi_system_table *systable)
  26. {
  27. size_t i;
  28. boottime = systable->boottime;
  29. for (i = 0; i < systable->nr_tables; ++i) {
  30. if (!memcmp(&systable->tables[i].guid, &fdt_guid,
  31. sizeof(efi_guid_t))) {
  32. if (fdt_addr) {
  33. efi_st_error("Duplicate device tree\n");
  34. return EFI_ST_FAILURE;
  35. }
  36. fdt_addr = (uintptr_t)systable->tables[i].table;
  37. }
  38. }
  39. return EFI_ST_SUCCESS;
  40. }
  41. /**
  42. * find_in_memory_map() - check matching memory map entry exists
  43. *
  44. * @memory_map: memory map
  45. * @desc_size: number of memory map entries
  46. * @addr: physical address to find in the map
  47. * @type: expected memory type
  48. * Return: EFI_ST_SUCCESS for success
  49. */
  50. static int find_in_memory_map(efi_uintn_t map_size,
  51. struct efi_mem_desc *memory_map,
  52. efi_uintn_t desc_size,
  53. u64 addr, int memory_type)
  54. {
  55. efi_uintn_t i;
  56. bool found = false;
  57. for (i = 0; map_size; ++i, map_size -= desc_size) {
  58. struct efi_mem_desc *entry = &memory_map[i];
  59. if (entry->physical_start != entry->virtual_start) {
  60. efi_st_error("Physical and virtual addresses do not match\n");
  61. return EFI_ST_FAILURE;
  62. }
  63. if (addr >= entry->physical_start &&
  64. addr < entry->physical_start +
  65. (entry->num_pages << EFI_PAGE_SHIFT)) {
  66. if (found) {
  67. efi_st_error("Duplicate memory map entry\n");
  68. return EFI_ST_FAILURE;
  69. }
  70. found = true;
  71. if (memory_type != entry->type) {
  72. efi_st_error
  73. ("Wrong memory type %d, expected %d\n",
  74. entry->type, memory_type);
  75. return EFI_ST_FAILURE;
  76. }
  77. }
  78. }
  79. if (!found) {
  80. efi_st_error("Missing memory map entry\n");
  81. return EFI_ST_FAILURE;
  82. }
  83. return EFI_ST_SUCCESS;
  84. }
  85. /*
  86. * execute() - execute unit test
  87. *
  88. * Return: EFI_ST_SUCCESS for success
  89. */
  90. static int execute(void)
  91. {
  92. u64 p1;
  93. u64 p2;
  94. efi_uintn_t map_size = 0;
  95. efi_uintn_t map_key;
  96. efi_uintn_t desc_size;
  97. u32 desc_version;
  98. struct efi_mem_desc *memory_map;
  99. efi_status_t ret;
  100. /* Allocate two page ranges with different memory type */
  101. ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
  102. EFI_RUNTIME_SERVICES_CODE,
  103. EFI_ST_NUM_PAGES, &p1);
  104. if (ret != EFI_SUCCESS) {
  105. efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
  106. return EFI_ST_FAILURE;
  107. }
  108. ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
  109. EFI_RUNTIME_SERVICES_DATA,
  110. EFI_ST_NUM_PAGES, &p2);
  111. if (ret != EFI_SUCCESS) {
  112. efi_st_error("AllocatePages did not return EFI_SUCCESS\n");
  113. return EFI_ST_FAILURE;
  114. }
  115. /* Load memory map */
  116. ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
  117. &desc_version);
  118. if (ret != EFI_BUFFER_TOO_SMALL) {
  119. efi_st_error
  120. ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
  121. return EFI_ST_FAILURE;
  122. }
  123. /* Allocate extra space for newly allocated memory */
  124. map_size += sizeof(struct efi_mem_desc);
  125. ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
  126. (void **)&memory_map);
  127. if (ret != EFI_SUCCESS) {
  128. efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
  129. return EFI_ST_FAILURE;
  130. }
  131. ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
  132. &desc_size, &desc_version);
  133. if (ret != EFI_SUCCESS) {
  134. efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
  135. return EFI_ST_FAILURE;
  136. }
  137. /* Check memory map entries */
  138. if (find_in_memory_map(map_size, memory_map, desc_size, p1,
  139. EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS)
  140. return EFI_ST_FAILURE;
  141. if (find_in_memory_map(map_size, memory_map, desc_size, p2,
  142. EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS)
  143. return EFI_ST_FAILURE;
  144. /* Free memory */
  145. ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES);
  146. if (ret != EFI_SUCCESS) {
  147. efi_st_error("FreePages did not return EFI_SUCCESS\n");
  148. return EFI_ST_FAILURE;
  149. }
  150. ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES);
  151. if (ret != EFI_SUCCESS) {
  152. efi_st_error("FreePages did not return EFI_SUCCESS\n");
  153. return EFI_ST_FAILURE;
  154. }
  155. ret = boottime->free_pool(memory_map);
  156. if (ret != EFI_SUCCESS) {
  157. efi_st_error("FreePool did not return EFI_SUCCESS\n");
  158. return EFI_ST_FAILURE;
  159. }
  160. /* Check memory reservation for the device tree */
  161. if (fdt_addr &&
  162. find_in_memory_map(map_size, memory_map, desc_size, fdt_addr,
  163. EFI_ACPI_RECLAIM_MEMORY) != EFI_ST_SUCCESS) {
  164. efi_st_error
  165. ("Device tree not marked as ACPI reclaim memory\n");
  166. return EFI_ST_FAILURE;
  167. }
  168. return EFI_ST_SUCCESS;
  169. }
  170. EFI_UNIT_TEST(memory) = {
  171. .name = "memory",
  172. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  173. .setup = setup,
  174. .execute = execute,
  175. };