malloc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright (C) Siddharth Bharat Purohit 2017
  3. * This file is free software: you can redistribute it and/or modify it
  4. * under the terms of the GNU General Public License as published by the
  5. * Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This file is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. /*
  17. wrappers for allocation functions
  18. Relies on linker wrap options
  19. Note that not all functions that have been wrapped are implemented
  20. here. The others are wrapped to ensure the function is not used
  21. without an implementation. If we need them then we can implement as
  22. needed.
  23. */
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <hal.h>
  27. #include <ch.h>
  28. #include <stdarg.h>
  29. #include "stm32_util.h"
  30. #define MEM_REGION_FLAG_DMA_OK 1
  31. #define MEM_REGION_FLAG_FAST 2
  32. #define MEM_REGION_FLAG_SDCARD 4
  33. static const struct memory_region {
  34. void *address;
  35. uint32_t size;
  36. uint32_t flags;
  37. } memory_regions[] = { HAL_MEMORY_REGIONS };
  38. // the first memory region is already setup as the ChibiOS
  39. // default heap, so we will index from 1 in the allocators
  40. #define NUM_MEMORY_REGIONS (sizeof(memory_regions)/sizeof(memory_regions[0]))
  41. #if CH_CFG_USE_HEAP == TRUE
  42. static memory_heap_t heaps[NUM_MEMORY_REGIONS];
  43. #define MIN_ALIGNMENT 8
  44. #if defined(STM32H7)
  45. #define DMA_ALIGNMENT 32
  46. #else
  47. #define DMA_ALIGNMENT 8
  48. #endif
  49. // size of memory reserved for dma-capable alloc
  50. #ifndef DMA_RESERVE_SIZE
  51. #define DMA_RESERVE_SIZE 4096
  52. #endif
  53. #if DMA_RESERVE_SIZE != 0
  54. static memory_heap_t dma_reserve_heap;
  55. #endif
  56. /*
  57. initialise memory handling
  58. */
  59. void malloc_init(void)
  60. {
  61. uint8_t i;
  62. for (i=1; i<NUM_MEMORY_REGIONS; i++) {
  63. chHeapObjectInit(&heaps[i], memory_regions[i].address, memory_regions[i].size);
  64. }
  65. #if DMA_RESERVE_SIZE != 0
  66. /*
  67. create a DMA reserve heap, to ensure we keep some memory for DMA
  68. safe memory allocations
  69. */
  70. void *dma_reserve = malloc_dma(DMA_RESERVE_SIZE);
  71. osalDbgAssert(dma_reserve != NULL, "DMA reserve");
  72. chHeapObjectInit(&dma_reserve_heap, dma_reserve, DMA_RESERVE_SIZE);
  73. #endif
  74. }
  75. static void *malloc_flags(size_t size, uint32_t flags)
  76. {
  77. if (size == 0) {
  78. return NULL;
  79. }
  80. const uint8_t dma_flags = (MEM_REGION_FLAG_DMA_OK | MEM_REGION_FLAG_SDCARD);
  81. const uint8_t alignment = (flags&dma_flags?DMA_ALIGNMENT:MIN_ALIGNMENT);
  82. void *p = NULL;
  83. uint8_t i;
  84. if (flags & dma_flags) {
  85. // allocate multiple of DMA alignment
  86. size = (size + (DMA_ALIGNMENT-1)) & ~(DMA_ALIGNMENT-1);
  87. }
  88. // if no flags are set or this is a DMA request and default heap
  89. // is DMA safe then start with default heap
  90. if (flags == 0 || (flags == MEM_REGION_FLAG_DMA_OK &&
  91. (memory_regions[0].flags & MEM_REGION_FLAG_DMA_OK))) {
  92. p = chHeapAllocAligned(NULL, size, alignment);
  93. if (p) {
  94. goto found;
  95. }
  96. }
  97. // try with matching flags
  98. for (i=1; i<NUM_MEMORY_REGIONS; i++) {
  99. if ((flags & MEM_REGION_FLAG_DMA_OK) &&
  100. !(memory_regions[i].flags & MEM_REGION_FLAG_DMA_OK)) {
  101. continue;
  102. }
  103. if ((flags & MEM_REGION_FLAG_SDCARD) &&
  104. !(memory_regions[i].flags & MEM_REGION_FLAG_SDCARD)) {
  105. continue;
  106. }
  107. if ((flags & MEM_REGION_FLAG_FAST) &&
  108. !(memory_regions[i].flags & MEM_REGION_FLAG_FAST)) {
  109. continue;
  110. }
  111. p = chHeapAllocAligned(&heaps[i], size, alignment);
  112. if (p) {
  113. goto found;
  114. }
  115. }
  116. // if this is a not a DMA request then we can fall back to any heap
  117. if (!(flags & dma_flags)) {
  118. for (i=1; i<NUM_MEMORY_REGIONS; i++) {
  119. p = chHeapAllocAligned(&heaps[i], size, alignment);
  120. if (p) {
  121. goto found;
  122. }
  123. }
  124. // try default heap
  125. p = chHeapAllocAligned(NULL, size, alignment);
  126. if (p) {
  127. goto found;
  128. }
  129. }
  130. #if DMA_RESERVE_SIZE != 0
  131. // fall back to DMA reserve
  132. p = chHeapAllocAligned(&dma_reserve_heap, size, alignment);
  133. if (p) {
  134. memset(p, 0, size);
  135. return p;
  136. }
  137. #endif
  138. // failed
  139. return NULL;
  140. found:
  141. memset(p, 0, size);
  142. return p;
  143. }
  144. /*
  145. allocate normal memory
  146. */
  147. void *malloc(size_t size)
  148. {
  149. return malloc_flags(size, 0);
  150. }
  151. /*
  152. allocate DMA-safe memory
  153. */
  154. void *malloc_dma(size_t size)
  155. {
  156. return malloc_flags(size, MEM_REGION_FLAG_DMA_OK);
  157. }
  158. /*
  159. allocate DMA-safe memory for microSD transfers. This is only
  160. different on H7 where SDMMC IDMA can't use SRAM4
  161. */
  162. void *malloc_sdcard_dma(size_t size)
  163. {
  164. #if defined(STM32H7)
  165. return malloc_flags(size, MEM_REGION_FLAG_SDCARD);
  166. #else
  167. return malloc_flags(size, MEM_REGION_FLAG_DMA_OK);
  168. #endif
  169. }
  170. /*
  171. allocate fast memory
  172. */
  173. void *malloc_fastmem(size_t size)
  174. {
  175. return malloc_flags(size, MEM_REGION_FLAG_FAST);
  176. }
  177. void *calloc(size_t nmemb, size_t size)
  178. {
  179. return malloc(nmemb * size);
  180. }
  181. void free(void *ptr)
  182. {
  183. if(ptr != NULL) {
  184. chHeapFree(ptr);
  185. }
  186. }
  187. /*
  188. return total available memory in bytes
  189. */
  190. size_t mem_available(void)
  191. {
  192. size_t totalp = 0;
  193. uint8_t i;
  194. // get memory available on main heap
  195. chHeapStatus(NULL, &totalp, NULL);
  196. // we also need to add in memory that is not yet allocated to the heap
  197. totalp += chCoreGetStatusX();
  198. // now our own heaps
  199. for (i=1; i<NUM_MEMORY_REGIONS; i++) {
  200. size_t available = 0;
  201. chHeapStatus(&heaps[i], &available, NULL);
  202. totalp += available;
  203. }
  204. #if DMA_RESERVE_SIZE != 0
  205. // and reserve DMA heap
  206. size_t available = 0;
  207. chHeapStatus(&dma_reserve_heap, &available, NULL);
  208. totalp += available;
  209. #endif
  210. return totalp;
  211. }
  212. /*
  213. allocate a thread on any available heap
  214. */
  215. thread_t *thread_create_alloc(size_t size,
  216. const char *name, tprio_t prio,
  217. tfunc_t pf, void *arg)
  218. {
  219. thread_t *ret;
  220. // first try default heap
  221. ret = chThdCreateFromHeap(NULL, size, name, prio, pf, arg);
  222. if (ret != NULL) {
  223. return ret;
  224. }
  225. // now try other heaps
  226. uint8_t i;
  227. for (i=1; i<NUM_MEMORY_REGIONS; i++) {
  228. ret = chThdCreateFromHeap(&heaps[i], size, name, prio, pf, arg);
  229. if (ret != NULL) {
  230. return ret;
  231. }
  232. }
  233. return NULL;
  234. }
  235. #endif // CH_CFG_USE_HEAP
  236. /*
  237. flush all memory. Used in chSysHalt()
  238. */
  239. void memory_flush_all(void)
  240. {
  241. uint8_t i;
  242. for (i=0; i<NUM_MEMORY_REGIONS; i++) {
  243. stm32_cacheBufferFlush(memory_regions[i].address, memory_regions[i].size);
  244. }
  245. }