os_mem.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * MEMORY MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2013, Micrium, Weston, FL
  8. * All Rights Reserved
  9. *
  10. * File : OS_MEM.C
  11. * By : Jean J. Labrosse
  12. * Version : V2.92.11
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. * uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.
  17. * If you plan on using uC/OS-II in a commercial product you need to contact Micrium to properly license
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience
  19. * uC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #define MICRIUM_SOURCE
  24. #ifndef OS_MASTER_FILE
  25. #include <ucos_ii.h>
  26. #endif
  27. #if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
  28. /*
  29. *********************************************************************************************************
  30. * CREATE A MEMORY PARTITION
  31. *
  32. * Description : Create a fixed-sized memory partition that will be managed by uC/OS-II.
  33. *
  34. * Arguments : addr is the starting address of the memory partition
  35. *
  36. * nblks is the number of memory blocks to create from the partition.
  37. *
  38. * blksize is the size (in bytes) of each block in the memory partition.
  39. *
  40. * perr is a pointer to a variable containing an error message which will be set by
  41. * this function to either:
  42. *
  43. * OS_ERR_NONE if the memory partition has been created correctly.
  44. * OS_ERR_MEM_INVALID_ADDR if you are specifying an invalid address for the memory
  45. * storage of the partition or, the block does not align
  46. * on a pointer boundary
  47. * OS_ERR_MEM_INVALID_PART no free partitions available
  48. * OS_ERR_MEM_INVALID_BLKS user specified an invalid number of blocks (must be >= 2)
  49. * OS_ERR_MEM_INVALID_SIZE user specified an invalid block size
  50. * - must be greater than the size of a pointer
  51. * - must be able to hold an integral number of pointers
  52. * Returns : != (OS_MEM *)0 is the partition was created
  53. * == (OS_MEM *)0 if the partition was not created because of invalid arguments or, no
  54. * free partition is available.
  55. *********************************************************************************************************
  56. */
  57. OS_MEM *OSMemCreate (void *addr,
  58. INT32U nblks,
  59. INT32U blksize,
  60. INT8U *perr)
  61. {
  62. OS_MEM *pmem;
  63. INT8U *pblk;
  64. void **plink;
  65. INT32U loops;
  66. INT32U i;
  67. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  68. OS_CPU_SR cpu_sr = 0u;
  69. #endif
  70. #ifdef OS_SAFETY_CRITICAL
  71. if (perr == (INT8U *)0) {
  72. OS_SAFETY_CRITICAL_EXCEPTION();
  73. return ((OS_MEM *)0);
  74. }
  75. #endif
  76. #ifdef OS_SAFETY_CRITICAL_IEC61508
  77. if (OSSafetyCriticalStartFlag == OS_TRUE) {
  78. OS_SAFETY_CRITICAL_EXCEPTION();
  79. return ((OS_MEM *)0);
  80. }
  81. #endif
  82. #if OS_ARG_CHK_EN > 0u
  83. if (addr == (void *)0) { /* Must pass a valid address for the memory part.*/
  84. *perr = OS_ERR_MEM_INVALID_ADDR;
  85. return ((OS_MEM *)0);
  86. }
  87. if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){ /* Must be pointer size aligned */
  88. *perr = OS_ERR_MEM_INVALID_ADDR;
  89. return ((OS_MEM *)0);
  90. }
  91. if (nblks < 2u) { /* Must have at least 2 blocks per partition */
  92. *perr = OS_ERR_MEM_INVALID_BLKS;
  93. return ((OS_MEM *)0);
  94. }
  95. if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */
  96. *perr = OS_ERR_MEM_INVALID_SIZE;
  97. return ((OS_MEM *)0);
  98. }
  99. #endif
  100. OS_ENTER_CRITICAL();
  101. pmem = OSMemFreeList; /* Get next free memory partition */
  102. if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */
  103. OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
  104. }
  105. OS_EXIT_CRITICAL();
  106. if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */
  107. *perr = OS_ERR_MEM_INVALID_PART;
  108. return ((OS_MEM *)0);
  109. }
  110. plink = (void **)addr; /* Create linked list of free memory blocks */
  111. pblk = (INT8U *)addr;
  112. loops = nblks - 1u;
  113. for (i = 0u; i < loops; i++) {
  114. pblk += blksize; /* Point to the FOLLOWING block */
  115. *plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */
  116. plink = (void **)pblk; /* Position to NEXT block */
  117. }
  118. *plink = (void *)0; /* Last memory block points to NULL */
  119. pmem->OSMemAddr = addr; /* Store start address of memory partition */
  120. pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */
  121. pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */
  122. pmem->OSMemNBlks = nblks;
  123. pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */
  124. *perr = OS_ERR_NONE;
  125. return (pmem);
  126. }
  127. /*$PAGE*/
  128. /*
  129. *********************************************************************************************************
  130. * GET A MEMORY BLOCK
  131. *
  132. * Description : Get a memory block from a partition
  133. *
  134. * Arguments : pmem is a pointer to the memory partition control block
  135. *
  136. * perr is a pointer to a variable containing an error message which will be set by this
  137. * function to either:
  138. *
  139. * OS_ERR_NONE if the memory partition has been created correctly.
  140. * OS_ERR_MEM_NO_FREE_BLKS if there are no more free memory blocks to allocate to caller
  141. * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  142. *
  143. * Returns : A pointer to a memory block if no error is detected
  144. * A pointer to NULL if an error is detected
  145. *********************************************************************************************************
  146. */
  147. void *OSMemGet (OS_MEM *pmem,
  148. INT8U *perr)
  149. {
  150. void *pblk;
  151. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  152. OS_CPU_SR cpu_sr = 0u;
  153. #endif
  154. #ifdef OS_SAFETY_CRITICAL
  155. if (perr == (INT8U *)0) {
  156. OS_SAFETY_CRITICAL_EXCEPTION();
  157. return ((void *)0);
  158. }
  159. #endif
  160. #if OS_ARG_CHK_EN > 0u
  161. if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
  162. *perr = OS_ERR_MEM_INVALID_PMEM;
  163. return ((void *)0);
  164. }
  165. #endif
  166. OS_ENTER_CRITICAL();
  167. if (pmem->OSMemNFree > 0u) { /* See if there are any free memory blocks */
  168. pblk = pmem->OSMemFreeList; /* Yes, point to next free memory block */
  169. pmem->OSMemFreeList = *(void **)pblk; /* Adjust pointer to new free list */
  170. pmem->OSMemNFree--; /* One less memory block in this partition */
  171. OS_EXIT_CRITICAL();
  172. *perr = OS_ERR_NONE; /* No error */
  173. return (pblk); /* Return memory block to caller */
  174. }
  175. OS_EXIT_CRITICAL();
  176. *perr = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */
  177. return ((void *)0); /* Return NULL pointer to caller */
  178. }
  179. /*$PAGE*/
  180. /*
  181. *********************************************************************************************************
  182. * GET THE NAME OF A MEMORY PARTITION
  183. *
  184. * Description: This function is used to obtain the name assigned to a memory partition.
  185. *
  186. * Arguments : pmem is a pointer to the memory partition
  187. *
  188. * pname is a pointer to a pointer to an ASCII string that will receive the name of the memory partition.
  189. *
  190. * perr is a pointer to an error code that can contain one of the following values:
  191. *
  192. * OS_ERR_NONE if the name was copied to 'pname'
  193. * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  194. * OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname'
  195. * OS_ERR_NAME_GET_ISR You called this function from an ISR
  196. *
  197. * Returns : The length of the string or 0 if 'pmem' is a NULL pointer.
  198. *********************************************************************************************************
  199. */
  200. #if OS_MEM_NAME_EN > 0u
  201. INT8U OSMemNameGet (OS_MEM *pmem,
  202. INT8U **pname,
  203. INT8U *perr)
  204. {
  205. INT8U len;
  206. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  207. OS_CPU_SR cpu_sr = 0u;
  208. #endif
  209. #ifdef OS_SAFETY_CRITICAL
  210. if (perr == (INT8U *)0) {
  211. OS_SAFETY_CRITICAL_EXCEPTION();
  212. return (0u);
  213. }
  214. #endif
  215. #if OS_ARG_CHK_EN > 0u
  216. if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */
  217. *perr = OS_ERR_MEM_INVALID_PMEM;
  218. return (0u);
  219. }
  220. if (pname == (INT8U **)0) { /* Is 'pname' a NULL pointer? */
  221. *perr = OS_ERR_PNAME_NULL;
  222. return (0u);
  223. }
  224. #endif
  225. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  226. *perr = OS_ERR_NAME_GET_ISR;
  227. return (0u);
  228. }
  229. OS_ENTER_CRITICAL();
  230. *pname = pmem->OSMemName;
  231. len = OS_StrLen(*pname);
  232. OS_EXIT_CRITICAL();
  233. *perr = OS_ERR_NONE;
  234. return (len);
  235. }
  236. #endif
  237. /*$PAGE*/
  238. /*
  239. *********************************************************************************************************
  240. * ASSIGN A NAME TO A MEMORY PARTITION
  241. *
  242. * Description: This function assigns a name to a memory partition.
  243. *
  244. * Arguments : pmem is a pointer to the memory partition
  245. *
  246. * pname is a pointer to an ASCII string that contains the name of the memory partition.
  247. *
  248. * perr is a pointer to an error code that can contain one of the following values:
  249. *
  250. * OS_ERR_NONE if the name was copied to 'pname'
  251. * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  252. * OS_ERR_PNAME_NULL You passed a NULL pointer for 'pname'
  253. * OS_ERR_MEM_NAME_TOO_LONG if the name doesn't fit in the storage area
  254. * OS_ERR_NAME_SET_ISR if you called this function from an ISR
  255. *
  256. * Returns : None
  257. *********************************************************************************************************
  258. */
  259. #if OS_MEM_NAME_EN > 0u
  260. void OSMemNameSet (OS_MEM *pmem,
  261. INT8U *pname,
  262. INT8U *perr)
  263. {
  264. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  265. OS_CPU_SR cpu_sr = 0u;
  266. #endif
  267. #ifdef OS_SAFETY_CRITICAL
  268. if (perr == (INT8U *)0) {
  269. OS_SAFETY_CRITICAL_EXCEPTION();
  270. return;
  271. }
  272. #endif
  273. #if OS_ARG_CHK_EN > 0u
  274. if (pmem == (OS_MEM *)0) { /* Is 'pmem' a NULL pointer? */
  275. *perr = OS_ERR_MEM_INVALID_PMEM;
  276. return;
  277. }
  278. if (pname == (INT8U *)0) { /* Is 'pname' a NULL pointer? */
  279. *perr = OS_ERR_PNAME_NULL;
  280. return;
  281. }
  282. #endif
  283. if (OSIntNesting > 0u) { /* See if trying to call from an ISR */
  284. *perr = OS_ERR_NAME_SET_ISR;
  285. return;
  286. }
  287. OS_ENTER_CRITICAL();
  288. pmem->OSMemName = pname;
  289. OS_EXIT_CRITICAL();
  290. *perr = OS_ERR_NONE;
  291. }
  292. #endif
  293. /*$PAGE*/
  294. /*
  295. *********************************************************************************************************
  296. * RELEASE A MEMORY BLOCK
  297. *
  298. * Description : Returns a memory block to a partition
  299. *
  300. * Arguments : pmem is a pointer to the memory partition control block
  301. *
  302. * pblk is a pointer to the memory block being released.
  303. *
  304. * Returns : OS_ERR_NONE if the memory block was inserted into the partition
  305. * OS_ERR_MEM_FULL if you are returning a memory block to an already FULL memory
  306. * partition (You freed more blocks than you allocated!)
  307. * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  308. * OS_ERR_MEM_INVALID_PBLK if you passed a NULL pointer for the block to release.
  309. *********************************************************************************************************
  310. */
  311. INT8U OSMemPut (OS_MEM *pmem,
  312. void *pblk)
  313. {
  314. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  315. OS_CPU_SR cpu_sr = 0u;
  316. #endif
  317. #if OS_ARG_CHK_EN > 0u
  318. if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
  319. return (OS_ERR_MEM_INVALID_PMEM);
  320. }
  321. if (pblk == (void *)0) { /* Must release a valid block */
  322. return (OS_ERR_MEM_INVALID_PBLK);
  323. }
  324. #endif
  325. OS_ENTER_CRITICAL();
  326. if (pmem->OSMemNFree >= pmem->OSMemNBlks) { /* Make sure all blocks not already returned */
  327. OS_EXIT_CRITICAL();
  328. return (OS_ERR_MEM_FULL);
  329. }
  330. *(void **)pblk = pmem->OSMemFreeList; /* Insert released block into free block list */
  331. pmem->OSMemFreeList = pblk;
  332. pmem->OSMemNFree++; /* One more memory block in this partition */
  333. OS_EXIT_CRITICAL();
  334. return (OS_ERR_NONE); /* Notify caller that memory block was released */
  335. }
  336. /*$PAGE*/
  337. /*
  338. *********************************************************************************************************
  339. * QUERY MEMORY PARTITION
  340. *
  341. * Description : This function is used to determine the number of free memory blocks and the number of
  342. * used memory blocks from a memory partition.
  343. *
  344. * Arguments : pmem is a pointer to the memory partition control block
  345. *
  346. * p_mem_data is a pointer to a structure that will contain information about the memory
  347. * partition.
  348. *
  349. * Returns : OS_ERR_NONE if no errors were found.
  350. * OS_ERR_MEM_INVALID_PMEM if you passed a NULL pointer for 'pmem'
  351. * OS_ERR_MEM_INVALID_PDATA if you passed a NULL pointer to the data recipient.
  352. *********************************************************************************************************
  353. */
  354. #if OS_MEM_QUERY_EN > 0u
  355. INT8U OSMemQuery (OS_MEM *pmem,
  356. OS_MEM_DATA *p_mem_data)
  357. {
  358. #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
  359. OS_CPU_SR cpu_sr = 0u;
  360. #endif
  361. #if OS_ARG_CHK_EN > 0u
  362. if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */
  363. return (OS_ERR_MEM_INVALID_PMEM);
  364. }
  365. if (p_mem_data == (OS_MEM_DATA *)0) { /* Must release a valid storage area for the data */
  366. return (OS_ERR_MEM_INVALID_PDATA);
  367. }
  368. #endif
  369. OS_ENTER_CRITICAL();
  370. p_mem_data->OSAddr = pmem->OSMemAddr;
  371. p_mem_data->OSFreeList = pmem->OSMemFreeList;
  372. p_mem_data->OSBlkSize = pmem->OSMemBlkSize;
  373. p_mem_data->OSNBlks = pmem->OSMemNBlks;
  374. p_mem_data->OSNFree = pmem->OSMemNFree;
  375. OS_EXIT_CRITICAL();
  376. p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree;
  377. return (OS_ERR_NONE);
  378. }
  379. #endif /* OS_MEM_QUERY_EN */
  380. /*$PAGE*/
  381. /*
  382. *********************************************************************************************************
  383. * INITIALIZE MEMORY PARTITION MANAGER
  384. *
  385. * Description : This function is called by uC/OS-II to initialize the memory partition manager. Your
  386. * application MUST NOT call this function.
  387. *
  388. * Arguments : none
  389. *
  390. * Returns : none
  391. *
  392. * Note(s) : This function is INTERNAL to uC/OS-II and your application should not call it.
  393. *********************************************************************************************************
  394. */
  395. void OS_MemInit (void)
  396. {
  397. #if OS_MAX_MEM_PART == 1u
  398. OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */
  399. OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list */
  400. #if OS_MEM_NAME_EN > 0u
  401. OSMemFreeList->OSMemName = (INT8U *)"?"; /* Unknown name */
  402. #endif
  403. #endif
  404. #if OS_MAX_MEM_PART >= 2u
  405. OS_MEM *pmem;
  406. INT16U i;
  407. OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */
  408. for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) { /* Init. list of free memory partitions */
  409. pmem = &OSMemTbl[i]; /* Point to memory control block (MCB) */
  410. pmem->OSMemFreeList = (void *)&OSMemTbl[i + 1u]; /* Chain list of free partitions */
  411. #if OS_MEM_NAME_EN > 0u
  412. pmem->OSMemName = (INT8U *)(void *)"?";
  413. #endif
  414. }
  415. pmem = &OSMemTbl[i];
  416. pmem->OSMemFreeList = (void *)0; /* Initialize last node */
  417. #if OS_MEM_NAME_EN > 0u
  418. pmem->OSMemName = (INT8U *)(void *)"?";
  419. #endif
  420. OSMemFreeList = &OSMemTbl[0]; /* Point to beginning of free list */
  421. #endif
  422. }
  423. #endif /* OS_MEM_EN */