memory_layout_utils.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdint.h>
  7. #include <string.h>
  8. #include "sdkconfig.h"
  9. #include "esp_log.h"
  10. #include "soc/soc_memory_layout.h"
  11. #include "esp_rom_caps.h"
  12. #if ESP_ROM_HAS_LAYOUT_TABLE
  13. #ifdef CONFIG_IDF_TARGET_ESP32C3
  14. #include "esp32c3/rom/rom_layout.h"
  15. #elif CONFIG_IDF_TARGET_ESP32S3
  16. #include "esp32s3/rom/rom_layout.h"
  17. #elif CONFIG_IDF_TARGET_ESP32C2
  18. #include "esp32c2/rom/rom_layout.h"
  19. #elif CONFIG_IDF_TARGET_ESP32C6
  20. #include "esp32c6/rom/rom_layout.h"
  21. #elif CONFIG_IDF_TARGET_ESP32H2
  22. #include "esp32h2/rom/rom_layout.h"
  23. #elif CONFIG_IDF_TARGET_ESP32P4
  24. #include "esp32p4/rom/rom_layout.h"
  25. #endif
  26. #endif // ESP_ROM_HAS_LAYOUT_TABLE
  27. static const char *TAG = "memory_layout";
  28. /* These variables come from the linker script,
  29. delimit the start and end of entries created via
  30. SOC_RESERVE_MEMORY_REGION() macro.
  31. */
  32. extern soc_reserved_region_t soc_reserved_memory_region_start;
  33. extern soc_reserved_region_t soc_reserved_memory_region_end;
  34. static size_t s_get_num_reserved_regions(void)
  35. {
  36. size_t result = ( &soc_reserved_memory_region_end
  37. - &soc_reserved_memory_region_start );
  38. #if ESP_ROM_HAS_LAYOUT_TABLE
  39. return result + 1; // ROM table means one entry needs to be added at runtime
  40. #else
  41. return result;
  42. #endif
  43. }
  44. size_t soc_get_available_memory_region_max_count(void)
  45. {
  46. /* Worst-case: each reserved memory region splits an available
  47. region in two, so the maximum possible number of regions
  48. is the number of regions of memory plus the number of reservations */
  49. return soc_memory_region_count + s_get_num_reserved_regions();
  50. }
  51. static int s_compare_reserved_regions(const void *a, const void *b)
  52. {
  53. const soc_reserved_region_t *r_a = (soc_reserved_region_t *)a;
  54. const soc_reserved_region_t *r_b = (soc_reserved_region_t *)b;
  55. return (int)r_a->start - (int)r_b->start;
  56. }
  57. /* Initialize a mutable array of reserved regions in 'reserved',
  58. then sort it by start address and check for overlapping
  59. reserved regions (illegal).
  60. */
  61. static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t count)
  62. {
  63. #if ESP_ROM_HAS_LAYOUT_TABLE
  64. /* Get the ROM layout to find which part of DRAM is reserved */
  65. const ets_rom_layout_t *layout = ets_rom_layout_p;
  66. reserved[0].start = (intptr_t)layout->dram0_rtos_reserved_start;
  67. #if CONFIG_IDF_TARGET_ESP32P4
  68. //TODO: IDF-7921
  69. reserved[0].end = SOC_DIRAM_ROM_RESERVE_HIGH;
  70. #else
  71. reserved[0].end = SOC_DIRAM_DRAM_HIGH;
  72. #endif
  73. memcpy(reserved + 1, &soc_reserved_memory_region_start, (count - 1) * sizeof(soc_reserved_region_t));
  74. #else
  75. memcpy(reserved, &soc_reserved_memory_region_start, count * sizeof(soc_reserved_region_t));
  76. #endif
  77. /* Sort by starting address */
  78. qsort(reserved, count, sizeof(soc_reserved_region_t), s_compare_reserved_regions);
  79. /* Validity checks */
  80. ESP_EARLY_LOGV(TAG, "reserved range is %p - %p",
  81. &soc_reserved_memory_region_start,
  82. &soc_reserved_memory_region_end);
  83. ESP_EARLY_LOGD(TAG, "Checking %d reserved memory ranges:", count);
  84. for (size_t i = 0; i < count; i++) {
  85. ESP_EARLY_LOGD(TAG, "Reserved memory range 0x%08x - 0x%08x",
  86. reserved[i].start, reserved[i].end);
  87. reserved[i].start = reserved[i].start & ~3; /* expand all reserved areas to word boundaries */
  88. reserved[i].end = (reserved[i].end + 3) & ~3;
  89. assert(reserved[i].start <= reserved[i].end);
  90. if (i < count - 1) {
  91. assert(reserved[i + 1].start > reserved[i].start);
  92. if (reserved[i].end > reserved[i + 1].start) {
  93. ESP_EARLY_LOGE(TAG, "SOC_RESERVE_MEMORY_REGION region range " \
  94. "0x%08x - 0x%08x overlaps with 0x%08x - 0x%08x",
  95. reserved[i].start, reserved[i].end, reserved[i + 1].start,
  96. reserved[i + 1].end);
  97. abort();
  98. }
  99. }
  100. }
  101. }
  102. size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
  103. {
  104. soc_memory_region_t *out_region = regions;
  105. /* make a local copy of the "input" regions so we can modify them */
  106. soc_memory_region_t in_regions[soc_memory_region_count];
  107. memcpy(in_regions, soc_memory_regions, sizeof(in_regions));
  108. soc_memory_region_t *in_region = in_regions;
  109. size_t num_reserved = s_get_num_reserved_regions();
  110. soc_reserved_region_t reserved[num_reserved];
  111. s_prepare_reserved_regions(reserved, num_reserved);
  112. /* Go through the "in" regions (full regions, with no reserved
  113. sections removed from them) one at a time, trim off each reserved
  114. region, and then copy them to an out_region once trimmed
  115. */
  116. ESP_EARLY_LOGD(TAG, "Building list of available memory regions:");
  117. while (in_region != in_regions + soc_memory_region_count) {
  118. soc_memory_region_t in = *in_region;
  119. ESP_EARLY_LOGV(TAG, "Examining memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
  120. intptr_t in_start = in.start;
  121. intptr_t in_end = in_start + in.size;
  122. bool copy_in_to_out = true;
  123. bool move_to_next = true;
  124. for (size_t i = 0; i < num_reserved; i++) {
  125. if (reserved[i].end <= in_start) {
  126. /* reserved region ends before 'in' starts */
  127. continue;
  128. } else if (reserved[i].start >= in_end) {
  129. /* reserved region starts after 'in' ends */
  130. break;
  131. } else if (reserved[i].start <= in_start &&
  132. reserved[i].end >= in_end) { /* reserved covers all of 'in' */
  133. ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x inside of reserved 0x%08x - 0x%08x",
  134. in_start, in_end, reserved[i].start, reserved[i].end);
  135. /* skip 'in' entirely */
  136. copy_in_to_out = false;
  137. break;
  138. } else if (in_start < reserved[i].start &&
  139. in_end > reserved[i].end) { /* reserved contained inside 'in', need to "hole punch" */
  140. ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x contains reserved 0x%08x - 0x%08x",
  141. in_start, in_end, reserved[i].start, reserved[i].end);
  142. assert(in_start < reserved[i].start);
  143. assert(in_end > reserved[i].end);
  144. /* shrink this region to end where the reserved section starts */
  145. in_end = reserved[i].start;
  146. in.size = in_end - in_start;
  147. /* update in_region so the 'next' iteration uses the region
  148. after the reserved section */
  149. in_region->size -= (reserved[i].end - in_region->start);
  150. in_region->start = reserved[i].end;
  151. /* add first region, then re-run while loop with the updated in_region */
  152. move_to_next = false;
  153. break;
  154. } else if (reserved[i].start <= in_start) { /* reserved overlaps start of 'in' */
  155. ESP_EARLY_LOGV(TAG, "Start of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
  156. in_start, in_end, reserved[i].start, reserved[i].end);
  157. in.start = reserved[i].end;
  158. in_start = in.start;
  159. in.size = in_end - in_start;
  160. } else { /* reserved overlaps end of 'in' */
  161. ESP_EARLY_LOGV(TAG, "End of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
  162. in_start, in_end, reserved[i].start, reserved[i].end);
  163. in_end = reserved[i].start;
  164. in.size = in_end - in_start;
  165. }
  166. }
  167. /* ignore regions smaller than 16B */
  168. if (in.size <= 16) {
  169. copy_in_to_out = false;
  170. }
  171. if (copy_in_to_out) {
  172. ESP_EARLY_LOGD(TAG, "Available memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
  173. *out_region++ = in;
  174. }
  175. if (move_to_next) {
  176. in_region++;
  177. }
  178. }
  179. return (out_region - regions); /* return number of regions */
  180. }