os_mem.c 19 KB

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