heap_alloc_caps.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Copyright 2015-2016 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 <rom/ets_sys.h>
  14. #include <freertos/heap_regions.h>
  15. #include "esp_heap_alloc_caps.h"
  16. #include "spiram.h"
  17. #include "esp_log.h"
  18. #include <stdbool.h>
  19. static const char* TAG = "heap_alloc_caps";
  20. /*
  21. This file, combined with a region allocator that supports tags, solves the problem that the ESP32 has RAM that's
  22. slightly heterogeneous. Some RAM can be byte-accessed, some allows only 32-bit accesses, some can execute memory,
  23. some can be remapped by the MMU to only be accessed by a certain PID etc. In order to allow the most flexible
  24. memory allocation possible, this code makes it possible to request memory that has certain capabilities. The
  25. code will then use its knowledge of how the memory is configured along with a priority scheme to allocate that
  26. memory in the most sane way possible. This should optimize the amount of RAM accessible to the code without
  27. hardwiring addresses.
  28. */
  29. //Amount of priority slots for the tag descriptors.
  30. #define NO_PRIOS 3
  31. typedef struct {
  32. const char *name;
  33. uint32_t prio[NO_PRIOS];
  34. bool aliasedIram;
  35. } tag_desc_t;
  36. /*
  37. Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table.
  38. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request.
  39. Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker)
  40. WARNING: The current code assumes the ROM stacks are located in tag 1; no allocation from this tag can be done until
  41. the FreeRTOS scheduler has started.
  42. */
  43. static const tag_desc_t tag_desc[]={
  44. { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, false}, //Tag 0: Plain ole D-port RAM
  45. { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, true}, //Tag 1: Plain ole D-port RAM which has an alias on the I-port
  46. { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, false}, //Tag 2: IRAM
  47. { "PID2IRAM", { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //Tag 3-8: PID 2-7 IRAM
  48. { "PID3IRAM", { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //
  49. { "PID4IRAM", { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //
  50. { "PID5IRAM", { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //
  51. { "PID6IRAM", { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //
  52. { "PID7IRAM", { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //
  53. { "PID2DRAM", { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //Tag 9-14: PID 2-7 DRAM
  54. { "PID3DRAM", { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //
  55. { "PID4DRAM", { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //
  56. { "PID5DRAM", { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //
  57. { "PID6DRAM", { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //
  58. { "PID7DRAM", { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //
  59. { "SPISRAM", { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false}, //Tag 15: SPI SRAM data
  60. { "", { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID }, false} //End
  61. };
  62. /*
  63. Region descriptors. These describe all regions of memory available, and tag them according to the
  64. capabilities the hardware has. This array is not marked constant; the initialization code may want to
  65. change the tags of some regions because eg BT is detected, applications are loaded etc.
  66. The priorities here roughly work like this:
  67. - For a normal malloc (MALLOC_CAP_8BIT), give away the DRAM-only memory first, then pass off any dual-use IRAM regions,
  68. finally eat into the application memory.
  69. - For a malloc where 32-bit-aligned-only access is okay, first allocate IRAM, then DRAM, finally application IRAM.
  70. - Application mallocs (PIDx) will allocate IRAM first, if possible, then DRAM.
  71. - Most other malloc caps only fit in one region anyway.
  72. These region descriptors are very ESP32 specific, because they describe the memory pools available there.
  73. Because of requirements in the coalescing code as well as the heap allocator itself, this list should always
  74. be sorted from low to high start address.
  75. This array is *NOT* const because it gets modified depending on what pools are/aren't available.
  76. */
  77. static HeapRegionTagged_t regions[]={
  78. { (uint8_t *)0x3F800000, 0x20000, 15, 0}, //SPI SRAM, if available
  79. { (uint8_t *)0x3FFAE000, 0x2000, 0, 0}, //pool 16 <- used for rom code
  80. { (uint8_t *)0x3FFB0000, 0x8000, 0, 0}, //pool 15 <- if BT is enabled, used as BT HW shared memory
  81. { (uint8_t *)0x3FFB8000, 0x8000, 0, 0}, //pool 14 <- if BT is enabled, used data memory for BT ROM functions.
  82. { (uint8_t *)0x3FFC0000, 0x2000, 0, 0}, //pool 10-13, mmu page 0
  83. { (uint8_t *)0x3FFC2000, 0x2000, 0, 0}, //pool 10-13, mmu page 1
  84. { (uint8_t *)0x3FFC4000, 0x2000, 0, 0}, //pool 10-13, mmu page 2
  85. { (uint8_t *)0x3FFC6000, 0x2000, 0, 0}, //pool 10-13, mmu page 3
  86. { (uint8_t *)0x3FFC8000, 0x2000, 0, 0}, //pool 10-13, mmu page 4
  87. { (uint8_t *)0x3FFCA000, 0x2000, 0, 0}, //pool 10-13, mmu page 5
  88. { (uint8_t *)0x3FFCC000, 0x2000, 0, 0}, //pool 10-13, mmu page 6
  89. { (uint8_t *)0x3FFCE000, 0x2000, 0, 0}, //pool 10-13, mmu page 7
  90. { (uint8_t *)0x3FFD0000, 0x2000, 0, 0}, //pool 10-13, mmu page 8
  91. { (uint8_t *)0x3FFD2000, 0x2000, 0, 0}, //pool 10-13, mmu page 9
  92. { (uint8_t *)0x3FFD4000, 0x2000, 0, 0}, //pool 10-13, mmu page 10
  93. { (uint8_t *)0x3FFD6000, 0x2000, 0, 0}, //pool 10-13, mmu page 11
  94. { (uint8_t *)0x3FFD8000, 0x2000, 0, 0}, //pool 10-13, mmu page 12
  95. { (uint8_t *)0x3FFDA000, 0x2000, 0, 0}, //pool 10-13, mmu page 13
  96. { (uint8_t *)0x3FFDC000, 0x2000, 0, 0}, //pool 10-13, mmu page 14
  97. { (uint8_t *)0x3FFDE000, 0x2000, 0, 0}, //pool 10-13, mmu page 15
  98. { (uint8_t *)0x3FFE0000, 0x4000, 1, 0x400BC000}, //pool 9 blk 1
  99. { (uint8_t *)0x3FFE4000, 0x4000, 1, 0x400B8000}, //pool 9 blk 0
  100. { (uint8_t *)0x3FFE8000, 0x8000, 1, 0x400B0000}, //pool 8 <- can be remapped to ROM, used for MAC dump
  101. { (uint8_t *)0x3FFF0000, 0x8000, 1, 0x400A8000}, //pool 7 <- can be used for MAC dump
  102. { (uint8_t *)0x3FFF8000, 0x4000, 1, 0x400A4000}, //pool 6 blk 1 <- can be used as trace memory
  103. { (uint8_t *)0x3FFFC000, 0x4000, 1, 0x400A0000}, //pool 6 blk 0 <- can be used as trace memory
  104. { (uint8_t *)0x40070000, 0x8000, 2, 0}, //pool 0
  105. { (uint8_t *)0x40078000, 0x8000, 2, 0}, //pool 1
  106. { (uint8_t *)0x40080000, 0x2000, 2, 0}, //pool 2-5, mmu page 0
  107. { (uint8_t *)0x40082000, 0x2000, 2, 0}, //pool 2-5, mmu page 1
  108. { (uint8_t *)0x40084000, 0x2000, 2, 0}, //pool 2-5, mmu page 2
  109. { (uint8_t *)0x40086000, 0x2000, 2, 0}, //pool 2-5, mmu page 3
  110. { (uint8_t *)0x40088000, 0x2000, 2, 0}, //pool 2-5, mmu page 4
  111. { (uint8_t *)0x4008A000, 0x2000, 2, 0}, //pool 2-5, mmu page 5
  112. { (uint8_t *)0x4008C000, 0x2000, 2, 0}, //pool 2-5, mmu page 6
  113. { (uint8_t *)0x4008E000, 0x2000, 2, 0}, //pool 2-5, mmu page 7
  114. { (uint8_t *)0x40090000, 0x2000, 2, 0}, //pool 2-5, mmu page 8
  115. { (uint8_t *)0x40092000, 0x2000, 2, 0}, //pool 2-5, mmu page 9
  116. { (uint8_t *)0x40094000, 0x2000, 2, 0}, //pool 2-5, mmu page 10
  117. { (uint8_t *)0x40096000, 0x2000, 2, 0}, //pool 2-5, mmu page 11
  118. { (uint8_t *)0x40098000, 0x2000, 2, 0}, //pool 2-5, mmu page 12
  119. { (uint8_t *)0x4009A000, 0x2000, 2, 0}, //pool 2-5, mmu page 13
  120. { (uint8_t *)0x4009C000, 0x2000, 2, 0}, //pool 2-5, mmu page 14
  121. { (uint8_t *)0x4009E000, 0x2000, 2, 0}, //pool 2-5, mmu page 15
  122. { NULL, 0, 0, 0} //end
  123. };
  124. /* For the startup code, the stacks live in memory tagged by this tag. Hence, we only enable allocating from this tag
  125. once FreeRTOS has started up completely. */
  126. #define NONOS_STACK_TAG 1
  127. static bool nonos_stack_in_use=true;
  128. void heap_alloc_enable_nonos_stack_tag()
  129. {
  130. nonos_stack_in_use=false;
  131. }
  132. //Modify regions array to disable the given range of memory.
  133. static void disable_mem_region(void *from, void *to) {
  134. int i;
  135. //Align from and to on word boundaries
  136. from=(void*)((uint32_t)from&~3);
  137. to=(void*)(((uint32_t)to+3)&~3);
  138. for (i=0; regions[i].xSizeInBytes!=0; i++) {
  139. void *regStart=regions[i].pucStartAddress;
  140. void *regEnd=regions[i].pucStartAddress+regions[i].xSizeInBytes;
  141. if (regStart>=from && regEnd<=to) {
  142. //Entire region falls in the range. Disable entirely.
  143. regions[i].xTag=-1;
  144. } else if (regStart>=from && regEnd>to && regStart<to) {
  145. //Start of the region falls in the range. Modify address/len.
  146. int overlap=(uint8_t *)to-(uint8_t *)regStart;
  147. regions[i].pucStartAddress+=overlap;
  148. regions[i].xSizeInBytes-=overlap;
  149. if (regions[i].xExecAddr) regions[i].xExecAddr+=overlap;
  150. } else if (regStart<from && regEnd>from && regEnd<=to) {
  151. //End of the region falls in the range. Modify length.
  152. regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from;
  153. } else if (regStart<from && regEnd>to) {
  154. //Range punches a hole in the region! We do not support this.
  155. ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
  156. regions[i].xTag=-1; //Just disable memory region. That'll teach them!
  157. }
  158. }
  159. }
  160. /*
  161. Warning: These variables are assumed to have the start and end of the data and iram
  162. area used statically by the program, respectively. These variables are defined in the ld
  163. file.
  164. */
  165. extern int _data_start, _heap_start, _init_start, _iram_text_end;
  166. /*
  167. Initialize the heap allocator. We pass it a bunch of region descriptors, but we need to modify those first to accommodate for
  168. the data as loaded by the bootloader.
  169. ToDo: The regions are different when stuff like trace memory, BT, ... is used. Modify the regions struct on the fly for this.
  170. Same with loading of apps. Same with using SPI RAM.
  171. */
  172. void heap_alloc_caps_init() {
  173. int i;
  174. //Compile-time assert to see if we don't have more tags than is set in heap_regions.h
  175. _Static_assert((sizeof(tag_desc)/sizeof(tag_desc[0]))-1 <= HEAPREGIONS_MAX_TAGCOUNT, "More than HEAPREGIONS_MAX_TAGCOUNT tags defined!");
  176. //Disable the bits of memory where this code is loaded.
  177. disable_mem_region(&_data_start, &_heap_start); //DRAM used by bss/data static variables
  178. disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code
  179. disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region
  180. disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region
  181. /* Warning: The ROM stack is located in the 0x3ffe0000 area. We do not specifically disable that area here because
  182. after the scheduler has started, the ROM stack is not used anymore by anything. We handle it instead by not allowing
  183. any mallocs from tag 1 (the IRAM/DRAM region) until the scheduler has started.
  184. The 0x3ffe0000 region also contains static RAM for various ROM functions. The following lines
  185. reserve the regions for UART and ETSC, so these functions are usable. Libraries like xtos, which are
  186. not usable in FreeRTOS anyway, are commented out in the linker script so they cannot be used; we
  187. do not disable their memory regions here and they will be used as general purpose heap memory.
  188. Enabling the heap allocator for this region but disabling allocation here until FreeRTOS is started up
  189. is a somewhat risky action in theory, because on initializing the allocator, vPortDefineHeapRegionsTagged
  190. will go and write linked list entries at the start and end of all regions. For the ESP32, these linked
  191. list entries happen to end up in a region that is not touched by the stack; they can be placed safely there.*/
  192. disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe0440); //Reserve ROM PRO data region
  193. disable_mem_region((void*)0x3ffe4000, (void*)0x3ffe4350); //Reserve ROM APP data region
  194. #if CONFIG_BT_ENABLED
  195. #if CONFIG_BT_DRAM_RELEASE
  196. disable_mem_region((void*)0x3ffb0000, (void*)0x3ffb3000); //Reserve BT data region
  197. disable_mem_region((void*)0x3ffb8000, (void*)0x3ffbbb28); //Reserve BT data region
  198. disable_mem_region((void*)0x3ffbdb28, (void*)0x3ffc0000); //Reserve BT data region
  199. #else
  200. disable_mem_region((void*)0x3ffb0000, (void*)0x3ffc0000); //Reserve BT hardware shared memory & BT data region
  201. #endif
  202. disable_mem_region((void*)0x3ffae000, (void*)0x3ffaff10); //Reserve ROM data region, inc region needed for BT ROM routines
  203. #else
  204. disable_mem_region((void*)0x3ffae000, (void*)0x3ffae2a0); //Reserve ROM data region
  205. #endif
  206. #if CONFIG_MEMMAP_TRACEMEM
  207. #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
  208. disable_mem_region((void*)0x3fff8000, (void*)0x40000000); //Reserve trace mem region
  209. #else
  210. disable_mem_region((void*)0x3fff8000, (void*)0x3fffc000); //Reserve trace mem region
  211. #endif
  212. #endif
  213. #if 0
  214. enable_spi_sram();
  215. #else
  216. disable_mem_region((void*)0x3f800000, (void*)0x3f820000); //SPI SRAM not installed
  217. #endif
  218. //The heap allocator will treat every region given to it as separate. In order to get bigger ranges of contiguous memory,
  219. //it's useful to coalesce adjacent regions that have the same tag.
  220. for (i=1; regions[i].xSizeInBytes!=0; i++) {
  221. if (regions[i].pucStartAddress == (regions[i-1].pucStartAddress + regions[i-1].xSizeInBytes) &&
  222. regions[i].xTag == regions[i-1].xTag ) {
  223. regions[i-1].xTag=-1;
  224. regions[i].pucStartAddress=regions[i-1].pucStartAddress;
  225. regions[i].xSizeInBytes+=regions[i-1].xSizeInBytes;
  226. }
  227. }
  228. ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:");
  229. for (i=0; regions[i].xSizeInBytes!=0; i++) {
  230. if (regions[i].xTag != -1) {
  231. ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s",
  232. (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xSizeInBytes/1024, tag_desc[regions[i].xTag].name);
  233. }
  234. }
  235. //Initialize the malloc implementation.
  236. vPortDefineHeapRegionsTagged( regions );
  237. }
  238. //First and last words of the D/IRAM region, for both the DRAM address as well as the IRAM alias.
  239. #define DIRAM_IRAM_START 0x400A0000
  240. #define DIRAM_IRAM_END 0x400BFFFC
  241. #define DIRAM_DRAM_START 0x3FFE0000
  242. #define DIRAM_DRAM_END 0x3FFFFFFC
  243. /*
  244. This takes a memory chunk in a region that can be addressed as both DRAM as well as IRAM. It will convert it to
  245. IRAM in such a way that it can be later freed. It assumes both the address as wel as the length to be word-aligned.
  246. It returns a region that's 1 word smaller than the region given because it stores the original Dram address there.
  247. In theory, we can also make this work by prepending a struct that looks similar to the block link struct used by the
  248. heap allocator itself, which will allow inspection tools relying on any block returned from any sort of malloc to
  249. have such a block in front of it, work. We may do this later, if/when there is demand for it. For now, a simple
  250. pointer is used.
  251. */
  252. static void *dram_alloc_to_iram_addr(void *addr, size_t len)
  253. {
  254. uint32_t dstart=(int)addr; //First word
  255. uint32_t dend=((int)addr)+len-4; //Last word
  256. configASSERT(dstart>=DIRAM_DRAM_START);
  257. configASSERT(dend<=DIRAM_DRAM_END);
  258. configASSERT((dstart&3)==0);
  259. configASSERT((dend&3)==0);
  260. uint32_t istart=DIRAM_IRAM_START+(DIRAM_DRAM_END-dend);
  261. uint32_t *iptr=(uint32_t*)istart;
  262. *iptr=dstart;
  263. return (void*)(iptr+1);
  264. }
  265. /*
  266. Standard malloc() implementation. Will return standard no-frills byte-accessible data memory.
  267. */
  268. void *pvPortMalloc( size_t xWantedSize )
  269. {
  270. return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT );
  271. }
  272. /*
  273. Standard free() implementation. Will pass memory on to the allocator unless it's an IRAM address where the
  274. actual meory is allocated in DRAM, it will convert to the DRAM address then.
  275. */
  276. void vPortFree( void *pv )
  277. {
  278. if (((int)pv>=DIRAM_IRAM_START) && ((int)pv<=DIRAM_IRAM_END)) {
  279. //Memory allocated here is actually allocated in the DRAM alias region and
  280. //cannot be de-allocated as usual. dram_alloc_to_iram_addr stores a pointer to
  281. //the equivalent DRAM address, though; free that.
  282. uint32_t* dramAddrPtr=(uint32_t*)pv;
  283. return vPortFreeTagged((void*)dramAddrPtr[-1]);
  284. }
  285. return vPortFreeTagged(pv);
  286. }
  287. /*
  288. Routine to allocate a bit of memory with certain capabilities. caps is a bitfield of MALLOC_CAP_* bits.
  289. */
  290. void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps )
  291. {
  292. int prio;
  293. int tag, j;
  294. void *ret=NULL;
  295. uint32_t remCaps;
  296. if (caps & MALLOC_CAP_EXEC) {
  297. //MALLOC_CAP_EXEC forces an alloc from IRAM. There is a region which has both this
  298. //as well as the following caps, but the following caps are not possible for IRAM.
  299. //Thus, the combination is impossible and we return NULL directly, even although our tag_desc
  300. //table would indicate there is a tag for this.
  301. if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) {
  302. return NULL;
  303. }
  304. //If any, EXEC memory should be 32-bit aligned, so round up to the next multiple of 4.
  305. xWantedSize=(xWantedSize+3)&(~3);
  306. }
  307. for (prio=0; prio<NO_PRIOS; prio++) {
  308. //Iterate over tag descriptors for this priority
  309. for (tag=0; tag_desc[tag].prio[prio]!=MALLOC_CAP_INVALID; tag++) {
  310. if (nonos_stack_in_use && tag == NONOS_STACK_TAG) {
  311. //Non-os stack lives here and is still in use. Don't alloc here.
  312. continue;
  313. }
  314. if ((tag_desc[tag].prio[prio]&caps)!=0) {
  315. //Tag has at least one of the caps requested. If caps has other bits set that this prio
  316. //doesn't cover, see if they're available in other prios.
  317. remCaps=caps&(~tag_desc[tag].prio[prio]); //Remaining caps to be fulfilled
  318. j=prio+1;
  319. while (remCaps!=0 && j<NO_PRIOS) {
  320. remCaps=remCaps&(~tag_desc[tag].prio[j]);
  321. j++;
  322. }
  323. if (remCaps==0) {
  324. //This tag can satisfy all the requested capabilities. See if we can grab some memory using it.
  325. if ((caps & MALLOC_CAP_EXEC) && tag_desc[tag].aliasedIram) {
  326. //This is special, insofar that what we're going to get back is probably a DRAM address. If so,
  327. //we need to 'invert' it (lowest address in DRAM == highest address in IRAM and vice-versa) and
  328. //add a pointer to the DRAM equivalent before the address we're going to return.
  329. ret=pvPortMallocTagged(xWantedSize+4, tag);
  330. if (ret!=NULL) return dram_alloc_to_iram_addr(ret, xWantedSize+4);
  331. } else {
  332. //Just try to alloc, nothing special.
  333. ret=pvPortMallocTagged(xWantedSize, tag);
  334. if (ret!=NULL) return ret;
  335. }
  336. }
  337. }
  338. }
  339. }
  340. //Nothing usable found.
  341. return NULL;
  342. }
  343. size_t xPortGetFreeHeapSizeCaps( uint32_t caps )
  344. {
  345. int prio;
  346. int tag;
  347. size_t ret=0;
  348. for (prio=0; prio<NO_PRIOS; prio++) {
  349. //Iterate over tag descriptors for this priority
  350. for (tag=0; tag_desc[tag].prio[prio]!=MALLOC_CAP_INVALID; tag++) {
  351. if ((tag_desc[tag].prio[prio]&caps)!=0) {
  352. ret+=xPortGetFreeHeapSizeTagged(tag);
  353. }
  354. }
  355. }
  356. return ret;
  357. }
  358. size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps )
  359. {
  360. int prio;
  361. int tag;
  362. size_t ret=0;
  363. for (prio=0; prio<NO_PRIOS; prio++) {
  364. //Iterate over tag descriptors for this priority
  365. for (tag=0; tag_desc[tag].prio[prio]!=MALLOC_CAP_INVALID; tag++) {
  366. if ((tag_desc[tag].prio[prio]&caps)!=0) {
  367. ret+=xPortGetMinimumEverFreeHeapSizeTagged(tag);
  368. }
  369. }
  370. }
  371. return ret;
  372. }
  373. size_t xPortGetFreeHeapSize( void )
  374. {
  375. return xPortGetFreeHeapSizeCaps( MALLOC_CAP_8BIT );
  376. }
  377. size_t xPortGetMinimumEverFreeHeapSize( void )
  378. {
  379. return xPortGetMinimumEverFreeHeapSizeCaps( MALLOC_CAP_8BIT );
  380. }