memory_layout_utils.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <stdint.h>
  14. #include <string.h>
  15. #include "esp_log.h"
  16. #include "soc/soc_memory_layout.h"
  17. #include "sdkconfig.h"
  18. static const char *TAG = "memory_layout";
  19. /* These variables come from the linker script,
  20. delimit the start and end of entries created via
  21. SOC_RESERVE_MEMORY_REGION() macro.
  22. */
  23. extern soc_reserved_region_t soc_reserved_memory_region_start;
  24. extern soc_reserved_region_t soc_reserved_memory_region_end;
  25. /*
  26. These variables have the start and end of the data and static IRAM
  27. area used by the program. Defined in the linker script.
  28. */
  29. extern int _data_start, _static_data_end, _iram_start, _iram_end;
  30. /* static DRAM & IRAM chunks */
  31. static const size_t EXTRA_RESERVED_REGIONS = 2;
  32. static size_t s_get_num_reserved_regions(void)
  33. {
  34. return ( ( &soc_reserved_memory_region_end
  35. - &soc_reserved_memory_region_start ) +
  36. EXTRA_RESERVED_REGIONS );
  37. }
  38. size_t soc_get_available_memory_region_max_count(void)
  39. {
  40. /* Worst-case: each reserved memory region splits an available
  41. region in two, so the maximum possible number of regions
  42. is the number of regions of memory plus the number of reservations */
  43. return soc_memory_region_count + s_get_num_reserved_regions();
  44. }
  45. static int s_compare_reserved_regions(const void *a, const void *b)
  46. {
  47. const soc_reserved_region_t *r_a = (soc_reserved_region_t *)a;
  48. const soc_reserved_region_t *r_b = (soc_reserved_region_t *)b;
  49. return (int)r_a->start - (int)r_b->start;
  50. }
  51. /* Initialize a mutable array of reserved regions in 'reserved',
  52. then sort it by start address and check for overlapping
  53. reserved regions (illegal).
  54. */
  55. static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t count)
  56. {
  57. memcpy(reserved + EXTRA_RESERVED_REGIONS,
  58. &soc_reserved_memory_region_start,
  59. (count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t));
  60. /* Add the EXTRA_RESERVED_REGIONS at the beginning */
  61. reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */
  62. reserved[0].end = (intptr_t)&_static_data_end;
  63. #if CONFIG_IDF_TARGET_ESP32
  64. //ESP32 has a IRAM-only region 0x4008_0000 - 0x4009_FFFF, protect the used part
  65. reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */
  66. reserved[1].end = (intptr_t)&_iram_end;
  67. #elif CONFIG_IDF_TARGET_ESP32S2BETA
  68. //ESP32S2 has a big D/IRAM region, the part used by code is reserved
  69. //The address of the D/I bus are in the same order, directly shift IRAM address to get reserved DRAM address
  70. const uint32_t i_d_offset = SOC_IRAM_LOW - SOC_DRAM_LOW;
  71. reserved[1].start = (intptr_t)&_iram_start - i_d_offset; /* IRAM used by code */
  72. reserved[1].end = (intptr_t)&_iram_end - i_d_offset;
  73. #else
  74. # error chip not implemented!
  75. #endif
  76. /* Sort by starting address */
  77. qsort(reserved, count, sizeof(soc_reserved_region_t), s_compare_reserved_regions);
  78. /* Validity checks */
  79. ESP_EARLY_LOGV(TAG, "reserved range is %p - %p",
  80. &soc_reserved_memory_region_start,
  81. &soc_reserved_memory_region_end);
  82. ESP_EARLY_LOGD(TAG, "Checking %d reserved memory ranges:", count);
  83. for (size_t i = 0; i < count; i++)
  84. {
  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. }
  129. else if (reserved[i].start >= in_end) {
  130. /* reserved region starts after 'in' ends */
  131. break;
  132. }
  133. else if (reserved[i].start <= in_start &&
  134. reserved[i].end >= in_end) { /* reserved covers all of 'in' */
  135. ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x inside of reserved 0x%08x - 0x%08x",
  136. in_start, in_end, reserved[i].start, reserved[i].end);
  137. /* skip 'in' entirely */
  138. copy_in_to_out = false;
  139. break;
  140. }
  141. else if (in_start < reserved[i].start &&
  142. in_end > reserved[i].end) { /* reserved contained inside 'in', need to "hole punch" */
  143. ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x contains reserved 0x%08x - 0x%08x",
  144. in_start, in_end, reserved[i].start, reserved[i].end);
  145. assert(in_start < reserved[i].start);
  146. assert(in_end > reserved[i].end);
  147. /* shrink this region to end where the reserved section starts */
  148. in_end = reserved[i].start;
  149. in.size = in_end - in_start;
  150. /* update in_region so the 'next' iteration uses the region
  151. after the reserved section */
  152. in_region->size -= (reserved[i].end - in_region->start);
  153. in_region->start = reserved[i].end;
  154. /* add first region, then re-run while loop with the updated in_region */
  155. move_to_next = false;
  156. break;
  157. }
  158. else if (reserved[i].start <= in_start) { /* reserved overlaps start of 'in' */
  159. ESP_EARLY_LOGV(TAG, "Start of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
  160. in_start, in_end, reserved[i].start, reserved[i].end);
  161. in.start = reserved[i].end;
  162. in_start = in.start;
  163. in.size = in_end - in_start;
  164. }
  165. else { /* reserved overlaps end of 'in' */
  166. ESP_EARLY_LOGV(TAG, "End of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
  167. in_start, in_end, reserved[i].start, reserved[i].end);
  168. in_end = reserved[i].start;
  169. in.size = in_end - in_start;
  170. }
  171. }
  172. if (copy_in_to_out) {
  173. ESP_EARLY_LOGD(TAG, "Available memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
  174. *out_region++ = in;
  175. }
  176. if (move_to_next) {
  177. in_region++;
  178. }
  179. }
  180. return (out_region - regions); /* return number of regions */
  181. }