memory_layout_utils.c 7.9 KB

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