os_mem.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-III
  4. * The Real-Time Kernel
  5. *
  6. * Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
  7. *
  8. * SPDX-License-Identifier: APACHE-2.0
  9. *
  10. * This software is subject to an open source license and is distributed by
  11. * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
  12. * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
  13. *
  14. *********************************************************************************************************
  15. */
  16. /*
  17. *********************************************************************************************************
  18. * MEMORY PARTITION MANAGEMENT
  19. *
  20. * File : os_mem.c
  21. * Version : V3.08.02
  22. *********************************************************************************************************
  23. */
  24. #define MICRIUM_SOURCE
  25. #include "os.h"
  26. #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
  27. const CPU_CHAR *os_mem__c = "$Id: $";
  28. #endif
  29. #if (OS_CFG_MEM_EN > 0u)
  30. /*
  31. ************************************************************************************************************************
  32. * CREATE A MEMORY PARTITION
  33. *
  34. * Description : Create a fixed-sized memory partition that will be managed by uC/OS-III.
  35. *
  36. * Arguments : p_mem is a pointer to a memory partition control block which is allocated in user memory space.
  37. *
  38. * p_name is a pointer to an ASCII string to provide a name to the memory partition.
  39. *
  40. * p_addr is the starting address of the memory partition
  41. *
  42. * n_blks is the number of memory blocks to create from the partition.
  43. *
  44. * blk_size is the size (in bytes) of each block in the memory partition.
  45. *
  46. * p_err is a pointer to a variable containing an error message which will be set by this function to
  47. * either:
  48. *
  49. * OS_ERR_NONE If the memory partition has been created correctly
  50. * OS_ERR_ILLEGAL_CREATE_RUN_TIME If you are trying to create the memory partition after you
  51. * called OSSafetyCriticalStart()
  52. * OS_ERR_MEM_CREATE_ISR If you called this function from an ISR
  53. * OS_ERR_MEM_INVALID_BLKS User specified an invalid number of blocks (must be >= 2)
  54. * OS_ERR_MEM_INVALID_P_ADDR If you are specifying an invalid address for the memory
  55. * storage of the partition or, the block does not align on a
  56. * pointer boundary
  57. * OS_ERR_MEM_INVALID_SIZE User specified an invalid block size
  58. * - must be greater than the size of a pointer
  59. * - must be able to hold an integral number of pointers
  60. * OS_ERR_OBJ_CREATED If the memory partition was already created
  61. * Returns : none
  62. *
  63. * Note(s) : none
  64. ************************************************************************************************************************
  65. */
  66. void OSMemCreate (OS_MEM *p_mem,
  67. CPU_CHAR *p_name,
  68. void *p_addr,
  69. OS_MEM_QTY n_blks,
  70. OS_MEM_SIZE blk_size,
  71. OS_ERR *p_err)
  72. {
  73. #if (OS_CFG_ARG_CHK_EN > 0u)
  74. CPU_DATA align_msk;
  75. #endif
  76. OS_MEM_QTY i;
  77. OS_MEM_QTY loops;
  78. CPU_INT08U *p_blk;
  79. void **p_link;
  80. CPU_SR_ALLOC();
  81. #ifdef OS_SAFETY_CRITICAL
  82. if (p_err == (OS_ERR *)0) {
  83. OS_SAFETY_CRITICAL_EXCEPTION();
  84. return;
  85. }
  86. #endif
  87. #ifdef OS_SAFETY_CRITICAL_IEC61508
  88. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  89. *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
  90. return;
  91. }
  92. #endif
  93. #if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
  94. if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
  95. *p_err = OS_ERR_MEM_CREATE_ISR;
  96. return;
  97. }
  98. #endif
  99. #if (OS_CFG_ARG_CHK_EN > 0u)
  100. if (p_addr == (void *)0) { /* Must pass a valid address for the memory part. */
  101. *p_err = OS_ERR_MEM_INVALID_P_ADDR;
  102. return;
  103. }
  104. if (n_blks < 2u) { /* Must have at least 2 blocks per partition */
  105. *p_err = OS_ERR_MEM_INVALID_BLKS;
  106. return;
  107. }
  108. if (blk_size < sizeof(void *)) { /* Must contain space for at least a pointer */
  109. *p_err = OS_ERR_MEM_INVALID_SIZE;
  110. return;
  111. }
  112. align_msk = sizeof(void *) - 1u;
  113. if (align_msk > 0u) {
  114. if (((CPU_ADDR)p_addr & align_msk) != 0u){ /* Must be pointer size aligned */
  115. *p_err = OS_ERR_MEM_INVALID_P_ADDR;
  116. return;
  117. }
  118. if ((blk_size & align_msk) != 0u) { /* Block size must be a multiple address size */
  119. *p_err = OS_ERR_MEM_INVALID_SIZE;
  120. return;
  121. }
  122. }
  123. #endif
  124. p_link = (void **)p_addr; /* Create linked list of free memory blocks */
  125. p_blk = (CPU_INT08U *)p_addr;
  126. loops = n_blks - 1u;
  127. for (i = 0u; i < loops; i++) {
  128. p_blk += blk_size;
  129. *p_link = (void *)p_blk; /* Save pointer to NEXT block in CURRENT block */
  130. p_link = (void **)(void *)p_blk; /* Position to NEXT block */
  131. }
  132. *p_link = (void *)0; /* Last memory block points to NULL */
  133. CPU_CRITICAL_ENTER();
  134. #if (OS_OBJ_TYPE_REQ > 0u)
  135. #if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
  136. if (p_mem->Type == OS_OBJ_TYPE_MEM) {
  137. CPU_CRITICAL_EXIT();
  138. *p_err = OS_ERR_OBJ_CREATED;
  139. return;
  140. }
  141. #endif
  142. p_mem->Type = OS_OBJ_TYPE_MEM; /* Set the type of object */
  143. #endif
  144. #if (OS_CFG_DBG_EN > 0u)
  145. p_mem->NamePtr = p_name; /* Save name of memory partition */
  146. #else
  147. (void)p_name;
  148. #endif
  149. p_mem->AddrPtr = p_addr; /* Store start address of memory partition */
  150. p_mem->FreeListPtr = p_addr; /* Initialize pointer to pool of free blocks */
  151. p_mem->NbrFree = n_blks; /* Store number of free blocks in MCB */
  152. p_mem->NbrMax = n_blks;
  153. p_mem->BlkSize = blk_size; /* Store block size of each memory blocks */
  154. #if (OS_CFG_DBG_EN > 0u)
  155. OS_MemDbgListAdd(p_mem);
  156. OSMemQty++;
  157. #endif
  158. OS_TRACE_MEM_CREATE(p_mem, p_name);
  159. CPU_CRITICAL_EXIT();
  160. *p_err = OS_ERR_NONE;
  161. }
  162. /*
  163. ************************************************************************************************************************
  164. * GET A MEMORY BLOCK
  165. *
  166. * Description : Get a memory block from a partition.
  167. *
  168. * Arguments : p_mem is a pointer to the memory partition control block
  169. *
  170. * p_err is a pointer to a variable containing an error message which will be set by this function to
  171. * either:
  172. *
  173. * OS_ERR_NONE If the memory partition has been created correctly
  174. * OS_ERR_MEM_INVALID_P_MEM If you passed a NULL pointer for 'p_mem'
  175. * OS_ERR_MEM_NO_FREE_BLKS If there are no more free memory blocks to allocate to the caller
  176. * OS_ERR_OBJ_TYPE If 'p_mem' is not pointing at a memory partition
  177. *
  178. * Returns : A pointer to a memory block if no error is detected
  179. * A pointer to NULL if an error is detected
  180. *
  181. * Note(s) : none
  182. ************************************************************************************************************************
  183. */
  184. void *OSMemGet (OS_MEM *p_mem,
  185. OS_ERR *p_err)
  186. {
  187. void *p_blk;
  188. CPU_SR_ALLOC();
  189. #ifdef OS_SAFETY_CRITICAL
  190. if (p_err == (OS_ERR *)0) {
  191. OS_SAFETY_CRITICAL_EXCEPTION();
  192. return ((void *)0);
  193. }
  194. #endif
  195. OS_TRACE_MEM_GET_ENTER(p_mem);
  196. #if (OS_CFG_ARG_CHK_EN > 0u)
  197. if (p_mem == (OS_MEM *)0) { /* Must point to a valid memory partition */
  198. OS_TRACE_MEM_GET_FAILED(p_mem);
  199. OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_INVALID_P_MEM);
  200. *p_err = OS_ERR_MEM_INVALID_P_MEM;
  201. return ((void *)0);
  202. }
  203. #endif
  204. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  205. if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* Make sure the memory block was created */
  206. OS_TRACE_MEM_GET_EXIT(OS_ERR_OBJ_TYPE);
  207. *p_err = OS_ERR_OBJ_TYPE;
  208. return ((void *)0);
  209. }
  210. #endif
  211. CPU_CRITICAL_ENTER();
  212. if (p_mem->NbrFree == 0u) { /* See if there are any free memory blocks */
  213. CPU_CRITICAL_EXIT();
  214. OS_TRACE_MEM_GET_FAILED(p_mem);
  215. OS_TRACE_MEM_GET_EXIT(OS_ERR_MEM_NO_FREE_BLKS);
  216. *p_err = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */
  217. return ((void *)0); /* Return NULL pointer to caller */
  218. }
  219. p_blk = p_mem->FreeListPtr; /* Yes, point to next free memory block */
  220. p_mem->FreeListPtr = *(void **)p_blk; /* Adjust pointer to new free list */
  221. p_mem->NbrFree--; /* One less memory block in this partition */
  222. CPU_CRITICAL_EXIT();
  223. OS_TRACE_MEM_GET(p_mem);
  224. OS_TRACE_MEM_GET_EXIT(OS_ERR_NONE);
  225. *p_err = OS_ERR_NONE; /* No error */
  226. return (p_blk); /* Return memory block to caller */
  227. }
  228. /*
  229. ************************************************************************************************************************
  230. * RELEASE A MEMORY BLOCK
  231. *
  232. * Description : Returns a memory block to a partition.
  233. *
  234. * Arguments : p_mem is a pointer to the memory partition control block
  235. *
  236. * p_blk is a pointer to the memory block being released.
  237. *
  238. * p_err is a pointer to a variable that will contain an error code returned by this function.
  239. *
  240. * OS_ERR_NONE If the memory block was inserted into the partition
  241. * OS_ERR_MEM_FULL If you are returning a memory block to an already FULL memory
  242. * partition (You freed more blocks than you allocated!)
  243. * OS_ERR_MEM_INVALID_P_BLK If you passed a NULL pointer for the block to release.
  244. * OS_ERR_MEM_INVALID_P_MEM If you passed a NULL pointer for 'p_mem'
  245. * OS_ERR_OBJ_TYPE If 'p_mem' is not pointing at a memory partition
  246. *
  247. * Returns : none
  248. *
  249. * Note(s) : none
  250. ************************************************************************************************************************
  251. */
  252. void OSMemPut (OS_MEM *p_mem,
  253. void *p_blk,
  254. OS_ERR *p_err)
  255. {
  256. CPU_SR_ALLOC();
  257. #ifdef OS_SAFETY_CRITICAL
  258. if (p_err == (OS_ERR *)0) {
  259. OS_SAFETY_CRITICAL_EXCEPTION();
  260. return;
  261. }
  262. #endif
  263. OS_TRACE_MEM_PUT_ENTER(p_mem, p_blk);
  264. #if (OS_CFG_ARG_CHK_EN > 0u)
  265. if (p_mem == (OS_MEM *)0) { /* Must point to a valid memory partition */
  266. OS_TRACE_MEM_PUT_FAILED(p_mem);
  267. OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_MEM);
  268. *p_err = OS_ERR_MEM_INVALID_P_MEM;
  269. return;
  270. }
  271. if (p_blk == (void *)0) { /* Must release a valid block */
  272. OS_TRACE_MEM_PUT_FAILED(p_mem);
  273. OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_INVALID_P_BLK);
  274. *p_err = OS_ERR_MEM_INVALID_P_BLK;
  275. return;
  276. }
  277. #endif
  278. #if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
  279. if (p_mem->Type != OS_OBJ_TYPE_MEM) { /* Make sure the memory block was created */
  280. OS_TRACE_MEM_PUT_EXIT(OS_ERR_OBJ_TYPE);
  281. *p_err = OS_ERR_OBJ_TYPE;
  282. return;
  283. }
  284. #endif
  285. CPU_CRITICAL_ENTER();
  286. if (p_mem->NbrFree >= p_mem->NbrMax) { /* Make sure all blocks not already returned */
  287. CPU_CRITICAL_EXIT();
  288. OS_TRACE_MEM_PUT_FAILED(p_mem);
  289. OS_TRACE_MEM_PUT_EXIT(OS_ERR_MEM_FULL);
  290. *p_err = OS_ERR_MEM_FULL;
  291. return;
  292. }
  293. *(void **)p_blk = p_mem->FreeListPtr; /* Insert released block into free block list */
  294. p_mem->FreeListPtr = p_blk;
  295. p_mem->NbrFree++; /* One more memory block in this partition */
  296. CPU_CRITICAL_EXIT();
  297. OS_TRACE_MEM_PUT(p_mem);
  298. OS_TRACE_MEM_PUT_EXIT(OS_ERR_NONE);
  299. *p_err = OS_ERR_NONE; /* Notify caller that memory block was released */
  300. }
  301. /*
  302. ************************************************************************************************************************
  303. * ADD MEMORY PARTITION TO DEBUG LIST
  304. *
  305. * Description : This function is called by OSMemCreate() to add the memory partition to the debug table.
  306. *
  307. * Arguments : p_mem Is a pointer to the memory partition
  308. *
  309. * Returns : none
  310. *
  311. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  312. ************************************************************************************************************************
  313. */
  314. #if (OS_CFG_DBG_EN > 0u)
  315. void OS_MemDbgListAdd (OS_MEM *p_mem)
  316. {
  317. p_mem->DbgPrevPtr = (OS_MEM *)0;
  318. if (OSMemDbgListPtr == (OS_MEM *)0) {
  319. p_mem->DbgNextPtr = (OS_MEM *)0;
  320. } else {
  321. p_mem->DbgNextPtr = OSMemDbgListPtr;
  322. OSMemDbgListPtr->DbgPrevPtr = p_mem;
  323. }
  324. OSMemDbgListPtr = p_mem;
  325. }
  326. #endif
  327. /*
  328. ************************************************************************************************************************
  329. * INITIALIZE MEMORY PARTITION MANAGER
  330. *
  331. * Description : This function is called by uC/OS-III to initialize the memory partition manager. Your
  332. * application MUST NOT call this function.
  333. *
  334. * Arguments : none
  335. *
  336. * Returns : none
  337. *
  338. * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
  339. ************************************************************************************************************************
  340. */
  341. void OS_MemInit (OS_ERR *p_err)
  342. {
  343. #if (OS_CFG_DBG_EN > 0u)
  344. OSMemDbgListPtr = (OS_MEM *)0;
  345. OSMemQty = 0u;
  346. #endif
  347. *p_err = OS_ERR_NONE;
  348. }
  349. #endif