You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2866 line
117 KiB

  1. /*
  2. *********************************************************************************************************
  3. * uC/LIB
  4. * Custom Library Modules
  5. *
  6. * Copyright 2004-2021 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. *
  19. * STANDARD MEMORY OPERATIONS
  20. *
  21. * Filename : lib_mem.c
  22. * Version : V1.39.01
  23. *********************************************************************************************************
  24. * Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software.
  25. *
  26. * (a) ALL standard library functions are implemented in the custom library modules :
  27. *
  28. * (1) \<Custom Library Directory>\lib_*.*
  29. *
  30. * (2) \<Custom Library Directory>\Ports\<cpu>\<compiler>\lib*_a.*
  31. *
  32. * where
  33. * <Custom Library Directory> directory path for custom library software
  34. * <cpu> directory name for specific processor (CPU)
  35. * <compiler> directory name for specific compiler
  36. *
  37. * (b) Product-specific library functions are implemented in individual products.
  38. *********************************************************************************************************
  39. */
  40. /*
  41. *********************************************************************************************************
  42. * INCLUDE FILES
  43. *********************************************************************************************************
  44. */
  45. #define MICRIUM_SOURCE
  46. #define LIB_MEM_MODULE
  47. #include "lib_mem.h"
  48. #include "lib_math.h"
  49. #include "lib_str.h"
  50. /*
  51. *********************************************************************************************************
  52. * LOCAL DEFINES
  53. *********************************************************************************************************
  54. */
  55. /*
  56. *********************************************************************************************************
  57. * LOCAL CONSTANTS
  58. *********************************************************************************************************
  59. */
  60. /*
  61. *********************************************************************************************************
  62. * LOCAL DATA TYPES
  63. *********************************************************************************************************
  64. */
  65. /*
  66. *********************************************************************************************************
  67. * LOCAL TABLES
  68. *********************************************************************************************************
  69. */
  70. /*
  71. *********************************************************************************************************
  72. * LOCAL GLOBAL VARIABLES
  73. *********************************************************************************************************
  74. */
  75. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  76. #ifndef LIB_MEM_CFG_HEAP_BASE_ADDR
  77. CPU_INT08U Mem_Heap[LIB_MEM_CFG_HEAP_SIZE]; /* Mem heap. */
  78. #endif
  79. MEM_SEG Mem_SegHeap; /* Heap mem seg. */
  80. #endif
  81. MEM_SEG *Mem_SegHeadPtr; /* Ptr to head of seg list. */
  82. /*
  83. *********************************************************************************************************
  84. * LOCAL FUNCTION PROTOTYPES
  85. *********************************************************************************************************
  86. */
  87. static void Mem_SegCreateCritical (const CPU_CHAR *p_name,
  88. MEM_SEG *p_seg,
  89. CPU_ADDR seg_base_addr,
  90. CPU_SIZE_T padding_align,
  91. CPU_SIZE_T size);
  92. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  93. static MEM_SEG *Mem_SegOverlapChkCritical( CPU_ADDR seg_base_addr,
  94. CPU_SIZE_T size,
  95. LIB_ERR *p_err);
  96. #endif
  97. static void *Mem_SegAllocInternal (const CPU_CHAR *p_name,
  98. MEM_SEG *p_seg,
  99. CPU_SIZE_T size,
  100. CPU_SIZE_T align,
  101. CPU_SIZE_T padding_align,
  102. CPU_SIZE_T *p_bytes_reqd,
  103. LIB_ERR *p_err);
  104. static void *Mem_SegAllocExtCritical ( MEM_SEG *p_seg,
  105. CPU_SIZE_T size,
  106. CPU_SIZE_T align,
  107. CPU_SIZE_T padding_align,
  108. CPU_SIZE_T *p_bytes_reqd,
  109. LIB_ERR *p_err);
  110. static void Mem_DynPoolCreateInternal(const CPU_CHAR *p_name,
  111. MEM_DYN_POOL *p_pool,
  112. MEM_SEG *p_seg,
  113. CPU_SIZE_T blk_size,
  114. CPU_SIZE_T blk_align,
  115. CPU_SIZE_T blk_padding_align,
  116. CPU_SIZE_T blk_qty_init,
  117. CPU_SIZE_T blk_qty_max,
  118. LIB_ERR *p_err);
  119. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  120. static void Mem_SegAllocTrackCritical(const CPU_CHAR *p_name,
  121. MEM_SEG *p_seg,
  122. CPU_SIZE_T size,
  123. LIB_ERR *p_err);
  124. #endif
  125. #if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \
  126. (LIB_MEM_CFG_HEAP_SIZE > 0u))
  127. static CPU_BOOLEAN Mem_PoolBlkIsValidAddr ( MEM_POOL *p_pool,
  128. void *p_mem);
  129. #endif
  130. /*
  131. *********************************************************************************************************
  132. * LOCAL CONFIGURATION ERRORS
  133. *********************************************************************************************************
  134. */
  135. /*
  136. *********************************************************************************************************
  137. *********************************************************************************************************
  138. * GLOBAL FUNCTIONS
  139. *********************************************************************************************************
  140. *********************************************************************************************************
  141. */
  142. /*
  143. *********************************************************************************************************
  144. * Mem_Init()
  145. *
  146. * Description : (1) Initializes Memory Management Module :
  147. *
  148. * (a) Initialize heap memory pool
  149. * (b) Initialize memory pool table
  150. *
  151. *
  152. * Argument(s) : none.
  153. *
  154. * Return(s) : none.
  155. *
  156. * Caller(s) : Application.
  157. *
  158. * Note(s) : (2) Mem_Init() MUST be called ... :
  159. *
  160. * (a) ONLY ONCE from a product's application; ...
  161. * (b) BEFORE product's application calls any memory library module function(s)
  162. *********************************************************************************************************
  163. */
  164. void Mem_Init (void)
  165. {
  166. /* ------------------ INIT SEG LIST ------------------- */
  167. Mem_SegHeadPtr = DEF_NULL;
  168. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  169. {
  170. LIB_ERR err;
  171. CPU_ADDR heap_base_addr;
  172. /* ------------------ INIT HEAP SEG ------------------- */
  173. #ifdef LIB_MEM_CFG_HEAP_BASE_ADDR
  174. heap_base_addr = LIB_MEM_CFG_HEAP_BASE_ADDR;
  175. #else
  176. heap_base_addr = (CPU_ADDR)&Mem_Heap[0u];
  177. #endif
  178. Mem_SegCreate("Heap",
  179. &Mem_SegHeap, /* Create heap seg. */
  180. heap_base_addr,
  181. LIB_MEM_CFG_HEAP_SIZE,
  182. LIB_MEM_PADDING_ALIGN_NONE,
  183. &err);
  184. if (err != LIB_MEM_ERR_NONE) {
  185. CPU_SW_EXCEPTION(;);
  186. }
  187. }
  188. #endif
  189. }
  190. /*
  191. *********************************************************************************************************
  192. * Mem_Clr()
  193. *
  194. * Description : Clears data buffer (see Note #2).
  195. *
  196. * Argument(s) : pmem Pointer to memory buffer to clear.
  197. *
  198. * size Number of data buffer octets to clear (see Note #1).
  199. *
  200. * Return(s) : none.
  201. *
  202. * Caller(s) : Application.
  203. *
  204. * Note(s) : (1) Null clears allowed (i.e. zero-length clears).
  205. *
  206. * See also 'Mem_Set() Note #1'.
  207. *
  208. * (2) Clear data by setting each data octet to 0.
  209. *********************************************************************************************************
  210. */
  211. void Mem_Clr (void *pmem,
  212. CPU_SIZE_T size)
  213. {
  214. Mem_Set(pmem,
  215. 0u, /* See Note #2. */
  216. size);
  217. }
  218. /*
  219. *********************************************************************************************************
  220. * Mem_Set()
  221. *
  222. * Description : Fills data buffer with specified data octet.
  223. *
  224. * Argument(s) : pmem Pointer to memory buffer to fill with specified data octet.
  225. *
  226. * data_val Data fill octet value.
  227. *
  228. * size Number of data buffer octets to fill (see Note #1).
  229. *
  230. * Return(s) : none.
  231. *
  232. * Caller(s) : Application.
  233. *
  234. * Note(s) : (1) Null sets allowed (i.e. zero-length sets).
  235. *
  236. * (2) For best CPU performance, optimized to fill data buffer using 'CPU_ALIGN'-sized data
  237. * words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on
  238. * word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd
  239. * addresses.
  240. *
  241. * (3) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN'
  242. * address boundary.
  243. *
  244. * Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus
  245. * address values MUST be cast to an appropriately-sized integer value PRIOR to any
  246. * 'mem_align_mod' arithmetic operation.
  247. *********************************************************************************************************
  248. */
  249. void Mem_Set (void *pmem,
  250. CPU_INT08U data_val,
  251. CPU_SIZE_T size)
  252. {
  253. CPU_SIZE_T size_rem;
  254. CPU_ALIGN data_align;
  255. CPU_ALIGN *pmem_align;
  256. CPU_INT08U *pmem_08;
  257. CPU_DATA mem_align_mod;
  258. CPU_DATA i;
  259. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  260. if (size < 1) { /* See Note #1. */
  261. return;
  262. }
  263. if (pmem == (void *)0) {
  264. return;
  265. }
  266. #endif
  267. data_align = 0u;
  268. for (i = 0u; i < sizeof(CPU_ALIGN); i++) { /* Fill each data_align octet with data val. */
  269. data_align <<= DEF_OCTET_NBR_BITS;
  270. data_align |= (CPU_ALIGN)data_val;
  271. }
  272. size_rem = size;
  273. mem_align_mod = (CPU_INT08U)((CPU_ADDR)pmem % sizeof(CPU_ALIGN)); /* See Note #3. */
  274. pmem_08 = (CPU_INT08U *)pmem;
  275. if (mem_align_mod != 0u) { /* If leading octets avail, ... */
  276. i = mem_align_mod;
  277. while ((size_rem > 0) && /* ... start mem buf fill with leading octets ... */
  278. (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */
  279. *pmem_08++ = data_val;
  280. size_rem -= sizeof(CPU_INT08U);
  281. i++;
  282. }
  283. }
  284. pmem_align = (CPU_ALIGN *)pmem_08; /* See Note #2. */
  285. while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem buf aligned on CPU_ALIGN word boundaries, */
  286. *pmem_align++ = data_align; /* ... fill mem buf with CPU_ALIGN-sized data. */
  287. size_rem -= sizeof(CPU_ALIGN);
  288. }
  289. pmem_08 = (CPU_INT08U *)pmem_align;
  290. while (size_rem > 0) { /* Finish mem buf fill with trailing octets. */
  291. *pmem_08++ = data_val;
  292. size_rem -= sizeof(CPU_INT08U);
  293. }
  294. }
  295. /*
  296. *********************************************************************************************************
  297. * Mem_Copy()
  298. *
  299. * Description : Copies data octets from one memory buffer to another memory buffer.
  300. *
  301. * Argument(s) : pdest Pointer to destination memory buffer.
  302. *
  303. * psrc Pointer to source memory buffer.
  304. *
  305. * size Number of octets to copy (see Note #1).
  306. *
  307. * Return(s) : none.
  308. *
  309. * Caller(s) : Application.
  310. *
  311. * Note(s) : (1) Null copies allowed (i.e. zero-length copies).
  312. *
  313. * (2) Memory buffers NOT checked for overlapping.
  314. *
  315. * (a) IEEE Std 1003.1, 2004 Edition, Section 'memcpy() : DESCRIPTION' states that "if
  316. * copying takes place between objects that overlap, the behavior is undefined".
  317. *
  318. * (b) However, data octets from a source memory buffer at a higher address value SHOULD
  319. * successfully copy to a destination memory buffer at a lower address value even
  320. * if any octets of the memory buffers overlap as long as no individual, atomic CPU
  321. * word copy overlaps.
  322. *
  323. * Since Mem_Copy() performs the data octet copy via 'CPU_ALIGN'-sized words &/or
  324. * octets; & since 'CPU_ALIGN'-sized words MUST be accessed on word-aligned addresses
  325. * (see Note #3b), neither 'CPU_ALIGN'-sized words nor octets at unique addresses can
  326. * ever overlap.
  327. *
  328. * Therefore, Mem_Copy() SHOULD be able to successfully copy overlapping memory
  329. * buffers as long as the source memory buffer is at a higher address value than the
  330. * destination memory buffer.
  331. *
  332. * (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data
  333. * words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on
  334. * word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd
  335. * addresses.
  336. *
  337. * (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN'
  338. * address boundary.
  339. *
  340. * Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus
  341. * address values MUST be cast to an appropriately-sized integer value PRIOR to any
  342. * 'mem_align_mod' arithmetic operation.
  343. *********************************************************************************************************
  344. */
  345. #if (LIB_MEM_CFG_OPTIMIZE_ASM_EN != DEF_ENABLED)
  346. void Mem_Copy ( void *pdest,
  347. const void *psrc,
  348. CPU_SIZE_T size)
  349. {
  350. CPU_SIZE_T size_rem;
  351. CPU_SIZE_T mem_gap_octets;
  352. CPU_ALIGN *pmem_align_dest;
  353. const CPU_ALIGN *pmem_align_src;
  354. CPU_INT08U *pmem_08_dest;
  355. const CPU_INT08U *pmem_08_src;
  356. CPU_DATA i;
  357. CPU_DATA mem_align_mod_dest;
  358. CPU_DATA mem_align_mod_src;
  359. CPU_BOOLEAN mem_aligned;
  360. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  361. if (size < 1) { /* See Note #1. */
  362. return;
  363. }
  364. if (pdest == (void *)0) {
  365. return;
  366. }
  367. if (psrc == (void *)0) {
  368. return;
  369. }
  370. #endif
  371. size_rem = size;
  372. pmem_08_dest = ( CPU_INT08U *)pdest;
  373. pmem_08_src = (const CPU_INT08U *)psrc;
  374. mem_gap_octets = (CPU_SIZE_T)(pmem_08_src - pmem_08_dest);
  375. if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */
  376. /* See Note #4. */
  377. mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN));
  378. mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN));
  379. mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO;
  380. if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */
  381. /* ... optimize copy for mem buf alignment. */
  382. if (mem_align_mod_dest != 0u) { /* If leading octets avail, ... */
  383. i = mem_align_mod_dest;
  384. while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */
  385. (i < sizeof(CPU_ALIGN ))) { /* ... until next CPU_ALIGN word boundary. */
  386. *pmem_08_dest++ = *pmem_08_src++;
  387. size_rem -= sizeof(CPU_INT08U);
  388. i++;
  389. }
  390. }
  391. pmem_align_dest = ( CPU_ALIGN *)pmem_08_dest; /* See Note #3. */
  392. pmem_align_src = (const CPU_ALIGN *)pmem_08_src;
  393. while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */
  394. *pmem_align_dest++ = *pmem_align_src++; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */
  395. size_rem -= sizeof(CPU_ALIGN);
  396. }
  397. pmem_08_dest = ( CPU_INT08U *)pmem_align_dest;
  398. pmem_08_src = (const CPU_INT08U *)pmem_align_src;
  399. }
  400. }
  401. while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */
  402. *pmem_08_dest++ = *pmem_08_src++; /* ... copy psrc to pdest by octets. */
  403. size_rem -= sizeof(CPU_INT08U);
  404. }
  405. }
  406. #endif
  407. /*
  408. *********************************************************************************************************
  409. * Mem_Move()
  410. *
  411. * Description : Moves data octets from one memory buffer to another memory buffer, or within the same
  412. * memory buffer. Overlapping is correctly handled for all move operations.
  413. *
  414. * Argument(s) : pdest Pointer to destination memory buffer.
  415. *
  416. * psrc Pointer to source memory buffer.
  417. *
  418. * size Number of octets to move (see Note #1).
  419. *
  420. * Return(s) : none.
  421. *
  422. * Caller(s) : Application.
  423. *
  424. * Note(s) : (1) Null move operations allowed (i.e. zero-length).
  425. *
  426. * (2) Memory buffers checked for overlapping.
  427. *
  428. * (3) For best CPU performance, optimized to copy data buffer using 'CPU_ALIGN'-sized data
  429. * words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on
  430. * word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd
  431. * addresses.
  432. *
  433. * (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN'
  434. * address boundary.
  435. *
  436. * Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus
  437. * address values MUST be cast to an appropriately-sized integer value PRIOR to any
  438. * 'mem_align_mod' arithmetic operation.
  439. *********************************************************************************************************
  440. */
  441. void Mem_Move ( void *pdest,
  442. const void *psrc,
  443. CPU_SIZE_T size)
  444. {
  445. CPU_SIZE_T size_rem;
  446. CPU_SIZE_T mem_gap_octets;
  447. CPU_ALIGN *pmem_align_dest;
  448. const CPU_ALIGN *pmem_align_src;
  449. CPU_INT08U *pmem_08_dest;
  450. const CPU_INT08U *pmem_08_src;
  451. CPU_INT08S i;
  452. CPU_DATA mem_align_mod_dest;
  453. CPU_DATA mem_align_mod_src;
  454. CPU_BOOLEAN mem_aligned;
  455. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  456. if (size < 1) {
  457. return;
  458. }
  459. if (pdest == (void *)0) {
  460. return;
  461. }
  462. if (psrc == (void *)0) {
  463. return;
  464. }
  465. #endif
  466. pmem_08_src = (const CPU_INT08U *)psrc;
  467. pmem_08_dest = ( CPU_INT08U *)pdest;
  468. if (pmem_08_src > pmem_08_dest) {
  469. Mem_Copy(pdest, psrc, size);
  470. return;
  471. }
  472. size_rem = size;
  473. pmem_08_dest = ( CPU_INT08U *)pdest + size - 1;
  474. pmem_08_src = (const CPU_INT08U *)psrc + size - 1;
  475. mem_gap_octets = (CPU_SIZE_T)(pmem_08_dest - pmem_08_src);
  476. if (mem_gap_octets >= sizeof(CPU_ALIGN)) { /* Avoid bufs overlap. */
  477. /* See Note #4. */
  478. mem_align_mod_dest = (CPU_INT08U)((CPU_ADDR)pmem_08_dest % sizeof(CPU_ALIGN));
  479. mem_align_mod_src = (CPU_INT08U)((CPU_ADDR)pmem_08_src % sizeof(CPU_ALIGN));
  480. mem_aligned = (mem_align_mod_dest == mem_align_mod_src) ? DEF_YES : DEF_NO;
  481. if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */
  482. /* ... optimize copy for mem buf alignment. */
  483. if (mem_align_mod_dest != (sizeof(CPU_ALIGN) - 1)) {/* If leading octets avail, ... */
  484. i = (CPU_INT08S)mem_align_mod_dest;
  485. while ((size_rem > 0) && /* ... start mem buf copy with leading octets ... */
  486. (i >= 0)) { /* ... until next CPU_ALIGN word boundary. */
  487. *pmem_08_dest-- = *pmem_08_src--;
  488. size_rem -= sizeof(CPU_INT08U);
  489. i--;
  490. }
  491. }
  492. /* See Note #3. */
  493. pmem_align_dest = ( CPU_ALIGN *)(((CPU_INT08U *)pmem_08_dest - sizeof(CPU_ALIGN)) + 1);
  494. pmem_align_src = (const CPU_ALIGN *)(((CPU_INT08U *)pmem_08_src - sizeof(CPU_ALIGN)) + 1);
  495. while (size_rem >= sizeof(CPU_ALIGN)) { /* While mem bufs aligned on CPU_ALIGN word boundaries, */
  496. *pmem_align_dest-- = *pmem_align_src--; /* ... copy psrc to pdest with CPU_ALIGN-sized words. */
  497. size_rem -= sizeof(CPU_ALIGN);
  498. }
  499. pmem_08_dest = ( CPU_INT08U *)pmem_align_dest + sizeof(CPU_ALIGN) - 1;
  500. pmem_08_src = (const CPU_INT08U *)pmem_align_src + sizeof(CPU_ALIGN) - 1;
  501. }
  502. }
  503. while (size_rem > 0) { /* For unaligned mem bufs or trailing octets, ... */
  504. *pmem_08_dest-- = *pmem_08_src--; /* ... copy psrc to pdest by octets. */
  505. size_rem -= sizeof(CPU_INT08U);
  506. }
  507. }
  508. /*
  509. *********************************************************************************************************
  510. * Mem_Cmp()
  511. *
  512. * Description : Verifies that ALL data octets in two memory buffers are identical in sequence.
  513. *
  514. * Argument(s) : p1_mem Pointer to first memory buffer.
  515. *
  516. * p2_mem Pointer to second memory buffer.
  517. *
  518. * size Number of data buffer octets to compare (see Note #1).
  519. *
  520. * Return(s) : DEF_YES, if 'size' number of data octets are identical in both memory buffers.
  521. *
  522. * DEF_NO, otherwise.
  523. *
  524. * Caller(s) : Application.
  525. *
  526. * Note(s) : (1) Null compares allowed (i.e. zero-length compares); 'DEF_YES' returned to indicate
  527. * identical null compare.
  528. *
  529. * (2) Many memory buffer comparisons vary ONLY in the least significant octets -- e.g.
  530. * network address buffers. Consequently, memory buffer comparison is more efficient
  531. * if the comparison starts from the end of the memory buffers which will abort sooner
  532. * on dissimilar memory buffers that vary only in the least significant octets.
  533. *
  534. * (3) For best CPU performance, optimized to compare data buffers using 'CPU_ALIGN'-sized
  535. * data words. Since many word-aligned processors REQUIRE that multi-octet words be accessed on
  536. * word-aligned addresses, 'CPU_ALIGN'-sized words MUST be accessed on 'CPU_ALIGN'd
  537. * addresses.
  538. *
  539. * (4) Modulo arithmetic is used to determine whether a memory buffer starts on a 'CPU_ALIGN'
  540. * address boundary.
  541. *
  542. * Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values. Thus
  543. * address values MUST be cast to an appropriately-sized integer value PRIOR to any
  544. * 'mem_align_mod' arithmetic operation.
  545. *********************************************************************************************************
  546. */
  547. CPU_BOOLEAN Mem_Cmp (const void *p1_mem,
  548. const void *p2_mem,
  549. CPU_SIZE_T size)
  550. {
  551. CPU_SIZE_T size_rem;
  552. CPU_ALIGN *p1_mem_align;
  553. CPU_ALIGN *p2_mem_align;
  554. const CPU_INT08U *p1_mem_08;
  555. const CPU_INT08U *p2_mem_08;
  556. CPU_DATA i;
  557. CPU_DATA mem_align_mod_1;
  558. CPU_DATA mem_align_mod_2;
  559. CPU_BOOLEAN mem_aligned;
  560. CPU_BOOLEAN mem_cmp;
  561. if (size < 1) { /* See Note #1. */
  562. return (DEF_YES);
  563. }
  564. if (p1_mem == (void *)0) {
  565. return (DEF_NO);
  566. }
  567. if (p2_mem == (void *)0) {
  568. return (DEF_NO);
  569. }
  570. mem_cmp = DEF_YES; /* Assume mem bufs are identical until cmp fails. */
  571. size_rem = size;
  572. /* Start @ end of mem bufs (see Note #2). */
  573. p1_mem_08 = (const CPU_INT08U *)p1_mem + size;
  574. p2_mem_08 = (const CPU_INT08U *)p2_mem + size;
  575. /* See Note #4. */
  576. mem_align_mod_1 = (CPU_INT08U)((CPU_ADDR)p1_mem_08 % sizeof(CPU_ALIGN));
  577. mem_align_mod_2 = (CPU_INT08U)((CPU_ADDR)p2_mem_08 % sizeof(CPU_ALIGN));
  578. mem_aligned = (mem_align_mod_1 == mem_align_mod_2) ? DEF_YES : DEF_NO;
  579. if (mem_aligned == DEF_YES) { /* If mem bufs' alignment offset equal, ... */
  580. /* ... optimize cmp for mem buf alignment. */
  581. if (mem_align_mod_1 != 0u) { /* If trailing octets avail, ... */
  582. i = mem_align_mod_1;
  583. while ((mem_cmp == DEF_YES) && /* ... cmp mem bufs while identical & ... */
  584. (size_rem > 0) && /* ... start mem buf cmp with trailing octets ... */
  585. (i > 0)) { /* ... until next CPU_ALIGN word boundary. */
  586. p1_mem_08--;
  587. p2_mem_08--;
  588. if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */
  589. mem_cmp = DEF_NO;
  590. }
  591. size_rem -= sizeof(CPU_INT08U);
  592. i--;
  593. }
  594. }
  595. if (mem_cmp == DEF_YES) { /* If cmp still identical, cmp aligned mem bufs. */
  596. p1_mem_align = (CPU_ALIGN *)p1_mem_08; /* See Note #3. */
  597. p2_mem_align = (CPU_ALIGN *)p2_mem_08;
  598. while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical & ... */
  599. (size_rem >= sizeof(CPU_ALIGN))) { /* ... mem bufs aligned on CPU_ALIGN word boundaries. */
  600. p1_mem_align--;
  601. p2_mem_align--;
  602. if (*p1_mem_align != *p2_mem_align) { /* If ANY data octet(s) NOT identical, cmp fails. */
  603. mem_cmp = DEF_NO;
  604. }
  605. size_rem -= sizeof(CPU_ALIGN);
  606. }
  607. p1_mem_08 = (CPU_INT08U *)p1_mem_align;
  608. p2_mem_08 = (CPU_INT08U *)p2_mem_align;
  609. }
  610. }
  611. while ((mem_cmp == DEF_YES) && /* Cmp mem bufs while identical ... */
  612. (size_rem > 0)) { /* ... for unaligned mem bufs or trailing octets. */
  613. p1_mem_08--;
  614. p2_mem_08--;
  615. if (*p1_mem_08 != *p2_mem_08) { /* If ANY data octet(s) NOT identical, cmp fails. */
  616. mem_cmp = DEF_NO;
  617. }
  618. size_rem -= sizeof(CPU_INT08U);
  619. }
  620. return (mem_cmp);
  621. }
  622. /*
  623. *********************************************************************************************************
  624. * Mem_HeapAlloc()
  625. *
  626. * Description : Allocates a memory block from the heap memory segment.
  627. *
  628. * Argument(s) : size Size of memory block to allocate (in bytes).
  629. *
  630. * align Alignment of memory block to specific word boundary (in bytes).
  631. *
  632. * p_bytes_reqd Optional pointer to a variable to ... :
  633. *
  634. * (a) Return the number of bytes required to successfully
  635. * allocate the memory block, if any error(s);
  636. * (b) Return 0, otherwise.
  637. *
  638. * p_err Pointer to variable that will receive the return error code from this function :
  639. *
  640. * LIB_MEM_ERR_NONE Operation was successful.
  641. * LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap.
  642. *
  643. * ---------------------RETURNED BY Mem_SegAllocInternal()---------------------
  644. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  645. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  646. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  647. *
  648. * Return(s) : Pointer to memory block, if NO error(s).
  649. *
  650. * Pointer to NULL, otherwise.
  651. *
  652. * Caller(s) : Application.
  653. *
  654. * Note(s) : (1) Pointers to variables that return values MUST be initialized PRIOR to all other
  655. * validation or function handling in case of any error(s).
  656. *
  657. * (2) This function is DEPRECATED and will be removed in a future version of this product.
  658. * Mem_SegAlloc(), Mem_SegAllocExt() or Mem_SegAllocHW() should be used instead.
  659. *********************************************************************************************************
  660. */
  661. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  662. void *Mem_HeapAlloc (CPU_SIZE_T size,
  663. CPU_SIZE_T align,
  664. CPU_SIZE_T *p_bytes_reqd,
  665. LIB_ERR *p_err)
  666. {
  667. void *p_mem;
  668. p_mem = Mem_SegAllocInternal(DEF_NULL,
  669. &Mem_SegHeap,
  670. size,
  671. align,
  672. LIB_MEM_CFG_HEAP_PADDING_ALIGN,
  673. p_bytes_reqd,
  674. p_err);
  675. if (*p_err == LIB_MEM_ERR_SEG_OVF) {
  676. *p_err = LIB_MEM_ERR_HEAP_OVF;
  677. }
  678. return (p_mem);
  679. }
  680. #endif
  681. /*
  682. *********************************************************************************************************
  683. * Mem_HeapGetSizeRem()
  684. *
  685. * Description : Gets remaining heap memory size available to allocate.
  686. *
  687. * Argument(s) : align Desired word boundary alignment (in bytes) to return remaining memory size from.
  688. *
  689. * p_err Pointer to variable that will receive the return error code from this function
  690. *
  691. * LIB_MEM_ERR_NONE Operation was successful.
  692. *
  693. * --------------------RETURNED BY Mem_SegRemSizeGet()--------------------
  694. * LIB_MEM_ERR_NULL_PTR Segment data pointer NULL.
  695. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment.
  696. *
  697. * Return(s) : Remaining heap memory size (in bytes), if NO error(s).
  698. *
  699. * 0, otherwise.
  700. *
  701. * Caller(s) : Application.
  702. *
  703. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  704. * Mem_SegRemSizeGet() should be used instead.
  705. *********************************************************************************************************
  706. */
  707. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  708. CPU_SIZE_T Mem_HeapGetSizeRem (CPU_SIZE_T align,
  709. LIB_ERR *p_err)
  710. {
  711. CPU_SIZE_T rem_size;
  712. rem_size = Mem_SegRemSizeGet(&Mem_SegHeap,
  713. align,
  714. DEF_NULL,
  715. p_err);
  716. if (*p_err != LIB_MEM_ERR_NONE) {
  717. return (0u);
  718. }
  719. return (rem_size);
  720. }
  721. #endif
  722. /*
  723. *********************************************************************************************************
  724. * Mem_SegCreate()
  725. *
  726. * Description : Creates a new memory segment to be used for runtime memory allocation.
  727. *
  728. * Argument(s) : p_name Pointer to segment name.
  729. *
  730. * p_seg Pointer to segment data. Must be allocated by caller.
  731. *
  732. * seg_base_addr Address of segment's first byte.
  733. *
  734. * size Total size of segment, in bytes.
  735. *
  736. * padding_align Padding alignment, in bytes, that will be added to any allocated buffer from
  737. * this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE
  738. * means no padding.
  739. *
  740. * p_err Pointer to variable that will receive the return error code from this function :
  741. *
  742. * LIB_MEM_ERR_NONE Operation was successful.
  743. * LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size specified.
  744. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid padding alignment.
  745. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  746. *
  747. * -------------------RETURNED BY Mem_SegOverlapChkCritical()-------------------
  748. * LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment.
  749. * LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists.
  750. *
  751. * Return(s) : None.
  752. *
  753. * Caller(s) : Application.
  754. *
  755. * Note(s) : (1) New segments are checked for overlap with existing segments. A critical section needs
  756. * to be maintained during the whole list search and add procedure to prevent a reentrant
  757. * call from creating another segment overlapping with the one being added.
  758. *********************************************************************************************************
  759. */
  760. void Mem_SegCreate (const CPU_CHAR *p_name,
  761. MEM_SEG *p_seg,
  762. CPU_ADDR seg_base_addr,
  763. CPU_SIZE_T size,
  764. CPU_SIZE_T padding_align,
  765. LIB_ERR *p_err)
  766. {
  767. CPU_SR_ALLOC();
  768. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  769. if (p_err == DEF_NULL) { /* Chk for null err ptr. */
  770. CPU_SW_EXCEPTION(;);
  771. }
  772. if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */
  773. *p_err = LIB_MEM_ERR_NULL_PTR;
  774. return;
  775. }
  776. if (size < 1u) { /* Chk for invalid sized seg. */
  777. *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE;
  778. return;
  779. }
  780. /* Chk for addr space ovf. */
  781. if (seg_base_addr + (size - 1u) < seg_base_addr) {
  782. *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE;
  783. return;
  784. }
  785. if ((padding_align != LIB_MEM_PADDING_ALIGN_NONE) &&
  786. (MATH_IS_PWR2(padding_align) != DEF_YES)) {
  787. *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN;
  788. return;
  789. }
  790. #endif
  791. CPU_CRITICAL_ENTER();
  792. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \
  793. (LIB_MEM_CFG_HEAP_SIZE > 0u)
  794. (void)Mem_SegOverlapChkCritical(seg_base_addr, /* Chk for overlap. */
  795. size,
  796. p_err);
  797. if (*p_err != LIB_MEM_ERR_NONE) {
  798. CPU_CRITICAL_EXIT();
  799. return;
  800. }
  801. #endif
  802. Mem_SegCreateCritical(p_name, /* Create seg. */
  803. p_seg,
  804. seg_base_addr,
  805. padding_align,
  806. size);
  807. CPU_CRITICAL_EXIT();
  808. *p_err = LIB_MEM_ERR_NONE;
  809. }
  810. /*
  811. *********************************************************************************************************
  812. * Mem_SegClr()
  813. *
  814. * Description : Clears a memory segment.
  815. *
  816. * Argument(s) : p_seg Pointer to segment data. Must be allocated by caller.
  817. *
  818. * p_err Pointer to variable that will receive the return error code from this function :
  819. *
  820. * LIB_MEM_ERR_NONE Operation was successful.
  821. * LIB_MEM_ERR_NULL_PTR Segment data pointer NULL.
  822. *
  823. * Return(s) : None.
  824. *
  825. * Caller(s) : Application.
  826. *
  827. * Note(s) : (1) This function must be used with extreme caution. It must only be called on memory
  828. * segments that are no longer used.
  829. *
  830. * (2) This function is disabled when debug mode is enabled to avoid heap memory leaks.
  831. *********************************************************************************************************
  832. */
  833. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_DISABLED)
  834. void Mem_SegClr (MEM_SEG *p_seg,
  835. LIB_ERR *p_err)
  836. {
  837. CPU_SR_ALLOC();
  838. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  839. if (p_err == DEF_NULL) { /* Chk for null err ptr. */
  840. CPU_SW_EXCEPTION(;);
  841. }
  842. if (p_seg == DEF_NULL) { /* Chk for null seg ptr. */
  843. *p_err = LIB_MEM_ERR_NULL_PTR;
  844. return;
  845. }
  846. #endif
  847. CPU_CRITICAL_ENTER();
  848. p_seg->AddrNext = p_seg->AddrBase;
  849. CPU_CRITICAL_EXIT();
  850. *p_err = LIB_MEM_ERR_NONE;
  851. }
  852. #endif
  853. /*
  854. *********************************************************************************************************
  855. * Mem_SegRemSizeGet()
  856. *
  857. * Description : Gets free space of memory segment.
  858. *
  859. * Argument(s) : p_seg Pointer to segment data.
  860. *
  861. * align Alignment in bytes to assume for calculation of free space.
  862. *
  863. * p_seg_info Pointer to structure that will receive further segment info data (used size,
  864. * total size, base address and next allocation address).
  865. *
  866. * p_err Pointer to variable that will receive the return error code from this function :
  867. *
  868. * LIB_MEM_ERR_NONE Operation was successful.
  869. * LIB_MEM_ERR_NULL_PTR Segment data pointer NULL.
  870. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment.
  871. *
  872. * Return(s) : Memory segment remaining size in bytes, if successful.
  873. * 0, otherwise or if memory segment empty.
  874. *
  875. * Caller(s) : Application,
  876. * Mem_HeapGetSizeRem(),
  877. * Mem_OutputUsage().
  878. *
  879. * Note(s) : None.
  880. *********************************************************************************************************
  881. */
  882. CPU_SIZE_T Mem_SegRemSizeGet (MEM_SEG *p_seg,
  883. CPU_SIZE_T align,
  884. MEM_SEG_INFO *p_seg_info,
  885. LIB_ERR *p_err)
  886. {
  887. CPU_SIZE_T rem_size;
  888. CPU_SIZE_T total_size;
  889. CPU_SIZE_T used_size;
  890. CPU_ADDR next_addr_align;
  891. CPU_SR_ALLOC();
  892. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  893. if (p_err == DEF_NULL) { /* Chk for null err ptr. */
  894. CPU_SW_EXCEPTION(0);
  895. }
  896. if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk for invalid align val. */
  897. *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN;
  898. return (0u);
  899. }
  900. #endif
  901. if (p_seg == DEF_NULL) { /* Dflt to heap in case p_seg is null. */
  902. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  903. p_seg = &Mem_SegHeap;
  904. #else
  905. *p_err = LIB_MEM_ERR_NULL_PTR;
  906. return (0u);
  907. #endif
  908. }
  909. CPU_CRITICAL_ENTER(); /* Calc seg stats. */
  910. next_addr_align = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, align);
  911. CPU_CRITICAL_EXIT();
  912. total_size = (p_seg->AddrEnd - p_seg->AddrBase) + 1u;
  913. used_size = p_seg->AddrNext - p_seg->AddrBase;
  914. if (next_addr_align > p_seg->AddrEnd){
  915. next_addr_align = 0u;
  916. rem_size = 0u;
  917. } else {
  918. rem_size = total_size - (next_addr_align - p_seg->AddrBase);
  919. }
  920. if (p_seg_info != DEF_NULL) {
  921. p_seg_info->TotalSize = total_size;
  922. p_seg_info->UsedSize = used_size;
  923. p_seg_info->AddrBase = p_seg->AddrBase;
  924. p_seg_info->AddrNextAlloc = next_addr_align;
  925. }
  926. *p_err = LIB_MEM_ERR_NONE;
  927. return (rem_size);
  928. }
  929. /*
  930. *********************************************************************************************************
  931. * Mem_SegAlloc()
  932. *
  933. * Description : Allocates memory from specified segment. Returned memory block will be aligned on a CPU
  934. * word boundary.
  935. *
  936. * Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL.
  937. *
  938. * p_seg Pointer to segment from which to allocate memory. Will be allocated from
  939. * general-purpose heap if null.
  940. *
  941. * size Size of memory block to allocate, in bytes.
  942. *
  943. * p_err Pointer to variable that will receive the return error code from this function :
  944. *
  945. * LIB_MEM_ERR_NONE Operation was successful.
  946. *
  947. * ------------------RETURNED BY Mem_SegAllocInternal()-------------------
  948. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  949. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  950. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  951. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  952. *
  953. * Return(s) : Pointer to allocated memory block, if successful.
  954. *
  955. * DEF_NULL, otherwise.
  956. *
  957. * Caller(s) : Application.
  958. *
  959. * Note(s) : (1) The memory block returned by this function will be aligned on a word boundary. In
  960. * order to specify a specific alignment value, use either Mem_SegAllocExt() or
  961. * Mem_SegAllocHW().
  962. *********************************************************************************************************
  963. */
  964. void *Mem_SegAlloc (const CPU_CHAR *p_name,
  965. MEM_SEG *p_seg,
  966. CPU_SIZE_T size,
  967. LIB_ERR *p_err)
  968. {
  969. void *p_blk;
  970. if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */
  971. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  972. p_seg = &Mem_SegHeap;
  973. #else
  974. *p_err = LIB_MEM_ERR_NULL_PTR;
  975. return (DEF_NULL);
  976. #endif
  977. }
  978. p_blk = Mem_SegAllocInternal(p_name,
  979. p_seg,
  980. size,
  981. sizeof(CPU_ALIGN),
  982. LIB_MEM_PADDING_ALIGN_NONE,
  983. DEF_NULL,
  984. p_err);
  985. return (p_blk);
  986. }
  987. /*
  988. *********************************************************************************************************
  989. * Mem_SegAllocExt()
  990. *
  991. * Description : Allocates memory from specified memory segment.
  992. *
  993. * Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL.
  994. *
  995. * p_seg Pointer to segment from which to allocate memory. Will be allocated from
  996. * general-purpose heap if null.
  997. *
  998. * size Size of memory block to allocate, in bytes.
  999. *
  1000. * align Required alignment of memory block, in bytes. MUST be a power of 2.
  1001. *
  1002. * p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for
  1003. * the allocation to succeed. Set to DEF_NULL to skip calculation.
  1004. *
  1005. * p_err Pointer to variable that will receive the return error code from this function :
  1006. *
  1007. * LIB_MEM_ERR_NONE Operation was successful.
  1008. *
  1009. * ------------------RETURNED BY Mem_SegAllocInternal()-------------------
  1010. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1011. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1012. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1013. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1014. *
  1015. * Return(s) : Pointer to allocated memory block, if successful.
  1016. *
  1017. * DEF_NULL, otherwise.
  1018. *
  1019. * Caller(s) : Application.
  1020. *
  1021. * Note(s) : none.
  1022. *********************************************************************************************************
  1023. */
  1024. void *Mem_SegAllocExt (const CPU_CHAR *p_name,
  1025. MEM_SEG *p_seg,
  1026. CPU_SIZE_T size,
  1027. CPU_SIZE_T align,
  1028. CPU_SIZE_T *p_bytes_reqd,
  1029. LIB_ERR *p_err)
  1030. {
  1031. void *p_blk;
  1032. if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */
  1033. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1034. p_seg = &Mem_SegHeap;
  1035. #else
  1036. *p_err = LIB_MEM_ERR_NULL_PTR;
  1037. return (DEF_NULL);
  1038. #endif
  1039. }
  1040. p_blk = Mem_SegAllocInternal(p_name,
  1041. p_seg,
  1042. size,
  1043. align,
  1044. LIB_MEM_PADDING_ALIGN_NONE,
  1045. p_bytes_reqd,
  1046. p_err);
  1047. return (p_blk);
  1048. }
  1049. /*
  1050. *********************************************************************************************************
  1051. * Mem_SegAllocHW()
  1052. *
  1053. * Description : Allocates memory from specified segment. The returned buffer will be padded in function
  1054. * of memory segment's properties.
  1055. *
  1056. * Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL.
  1057. *
  1058. * p_seg Pointer to segment from which to allocate memory. Will be allocated from
  1059. * general-purpose heap if null.
  1060. *
  1061. * size Size of memory block to allocate, in bytes.
  1062. *
  1063. * align Required alignment of memory block, in bytes. MUST be a power of 2.
  1064. *
  1065. * p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for
  1066. * the allocation to succeed. Set to DEF_NULL to skip calculation.
  1067. *
  1068. * p_err Pointer to variable that will receive the return error code from this function :
  1069. *
  1070. * LIB_MEM_ERR_NONE Operation was successful.
  1071. *
  1072. * ------------------RETURNED BY Mem_SegAllocInternal()-------------------
  1073. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1074. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1075. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1076. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1077. *
  1078. * Return(s) : Pointer to allocated memory block, if successful.
  1079. *
  1080. * DEF_NULL, otherwise.
  1081. *
  1082. * Caller(s) : Application.
  1083. *
  1084. * Note(s) : none.
  1085. *********************************************************************************************************
  1086. */
  1087. void *Mem_SegAllocHW (const CPU_CHAR *p_name,
  1088. MEM_SEG *p_seg,
  1089. CPU_SIZE_T size,
  1090. CPU_SIZE_T align,
  1091. CPU_SIZE_T *p_bytes_reqd,
  1092. LIB_ERR *p_err)
  1093. {
  1094. void *p_blk;
  1095. if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */
  1096. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1097. p_seg = &Mem_SegHeap;
  1098. #else
  1099. *p_err = LIB_MEM_ERR_NULL_PTR;
  1100. return (DEF_NULL);
  1101. #endif
  1102. }
  1103. p_blk = Mem_SegAllocInternal(p_name,
  1104. p_seg,
  1105. size,
  1106. align,
  1107. p_seg->PaddingAlign,
  1108. p_bytes_reqd,
  1109. p_err);
  1110. return (p_blk);
  1111. }
  1112. /*
  1113. *********************************************************************************************************
  1114. * Mem_PoolCreate()
  1115. *
  1116. * Description : (1) Creates a memory pool :
  1117. *
  1118. * (a) Create memory pool from heap or dedicated memory
  1119. * (b) Allocate memory pool memory blocks
  1120. * (c) Configure memory pool
  1121. *
  1122. *
  1123. * Argument(s) : p_pool Pointer to a memory pool structure to create (see Note #1).
  1124. *
  1125. * p_mem_base Memory pool segment base address :
  1126. *
  1127. * (a) Null address Memory pool allocated from general-purpose heap.
  1128. * (b) Non-null address Memory pool allocated from dedicated memory
  1129. * specified by its base address.
  1130. *
  1131. * mem_size Size of memory pool segment (in bytes).
  1132. *
  1133. * blk_nbr Number of memory pool blocks to create.
  1134. *
  1135. * blk_size Size of memory pool blocks to create (in bytes).
  1136. *
  1137. * blk_align Alignment of memory pool blocks to specific word boundary (in bytes).
  1138. *
  1139. * p_bytes_reqd Optional pointer to a variable to ... :
  1140. *
  1141. * (a) Return the number of bytes required to successfully
  1142. * allocate the memory pool, if any error(s);
  1143. * (b) Return 0, otherwise.
  1144. *
  1145. * p_err Pointer to variable that will receive the return error code from this function :
  1146. *
  1147. * LIB_MEM_ERR_NONE Operation was successful.
  1148. * LIB_MEM_ERR_NULL_PTR Pointer to memory pool is null.
  1149. * LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid block alignment requested.
  1150. * LIB_MEM_ERR_INVALID_BLK_NBR Invalid number of blocks specified.
  1151. * LIB_MEM_ERR_INVALID_BLK_SIZE Invalid block size specified.
  1152. * LIB_MEM_ERR_INVALID_SEG_SIZE Invalid segment size.
  1153. * LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap.
  1154. * LIB_MEM_ERR_ADDR_OVF Memory allocation exceeds address space.
  1155. *
  1156. * ---------------RETURNED BY Mem_SegOverlapChkCritical()----------------
  1157. * LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists.
  1158. * LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment.
  1159. *
  1160. * -----------------RETURNED BY Mem_SegAllocExtCritical()-----------------
  1161. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1162. *
  1163. * ------------------RETURNED BY Mem_SegAllocInternal()-------------------
  1164. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1165. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1166. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1167. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1168. *
  1169. * -----------------------RETURNED BY Mem_PoolClr()-----------------------
  1170. * LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer.
  1171. *
  1172. * Return(s) : none.
  1173. *
  1174. * Caller(s) : Application.
  1175. *
  1176. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  1177. * Mem_DynPoolCreate() or Mem_DynPoolCreateHW() should be used instead.
  1178. *********************************************************************************************************
  1179. */
  1180. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1181. void Mem_PoolCreate (MEM_POOL *p_pool,
  1182. void *p_mem_base,
  1183. CPU_SIZE_T mem_size,
  1184. MEM_POOL_BLK_QTY blk_nbr,
  1185. CPU_SIZE_T blk_size,
  1186. CPU_SIZE_T blk_align,
  1187. CPU_SIZE_T *p_bytes_reqd,
  1188. LIB_ERR *p_err)
  1189. {
  1190. MEM_SEG *p_seg;
  1191. void *p_pool_mem;
  1192. CPU_SIZE_T pool_size;
  1193. CPU_SIZE_T tbl_size;
  1194. CPU_SIZE_T blk_size_align;
  1195. CPU_ADDR pool_addr_end;
  1196. MEM_POOL_BLK_QTY blk_ix;
  1197. CPU_INT08U *p_blk;
  1198. CPU_SR_ALLOC();
  1199. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* --------------- VALIDATE RTN ERR PTR --------------- */
  1200. if (p_err == DEF_NULL) {
  1201. CPU_SW_EXCEPTION(;);
  1202. }
  1203. /* ------------- VALIDATE MEM POOL CREATE ------------- */
  1204. if (p_pool == DEF_NULL) {
  1205. *p_err = LIB_MEM_ERR_NULL_PTR;
  1206. return;
  1207. }
  1208. if (p_mem_base != DEF_NULL) {
  1209. if (mem_size < 1u) {
  1210. *p_err = LIB_MEM_ERR_INVALID_SEG_SIZE;
  1211. return;
  1212. }
  1213. }
  1214. if (blk_nbr < 1u) {
  1215. *p_err = LIB_MEM_ERR_INVALID_BLK_NBR;
  1216. return;
  1217. }
  1218. if (blk_size < 1u) {
  1219. *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE;
  1220. return;
  1221. }
  1222. if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk that req alignment is a pwr of 2. */
  1223. *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN;
  1224. return;
  1225. }
  1226. #endif
  1227. Mem_PoolClr(p_pool, p_err); /* Init mem pool. */
  1228. if (*p_err != LIB_MEM_ERR_NONE) {
  1229. return;
  1230. }
  1231. /* -------- DETERMINE AND/OR ALLOC SEG TO USE --------- */
  1232. if (p_mem_base == DEF_NULL) { /* Use heap seg. */
  1233. p_seg = &Mem_SegHeap;
  1234. } else { /* Use other seg. */
  1235. CPU_CRITICAL_ENTER();
  1236. p_seg = Mem_SegOverlapChkCritical((CPU_ADDR)p_mem_base,
  1237. mem_size,
  1238. p_err);
  1239. switch (*p_err) {
  1240. case LIB_MEM_ERR_INVALID_SEG_EXISTS: /* Seg already exists. */
  1241. break;
  1242. case LIB_MEM_ERR_NONE: /* Seg must be created. */
  1243. p_seg = (MEM_SEG *)Mem_SegAllocExtCritical(&Mem_SegHeap,
  1244. sizeof(MEM_SEG),
  1245. sizeof(CPU_ALIGN),
  1246. LIB_MEM_PADDING_ALIGN_NONE,
  1247. p_bytes_reqd,
  1248. p_err);
  1249. if (*p_err != LIB_MEM_ERR_NONE) {
  1250. CPU_CRITICAL_EXIT();
  1251. return;
  1252. }
  1253. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */
  1254. Mem_SegAllocTrackCritical("Unknown segment data",
  1255. &Mem_SegHeap,
  1256. sizeof(MEM_SEG),
  1257. p_err);
  1258. if (*p_err != LIB_MEM_ERR_NONE) {
  1259. CPU_CRITICAL_EXIT();
  1260. return;
  1261. }
  1262. #endif
  1263. Mem_SegCreateCritical( DEF_NULL,
  1264. p_seg,
  1265. (CPU_ADDR)p_mem_base,
  1266. LIB_MEM_PADDING_ALIGN_NONE,
  1267. mem_size);
  1268. break;
  1269. case LIB_MEM_ERR_INVALID_SEG_OVERLAP:
  1270. default:
  1271. CPU_CRITICAL_EXIT();
  1272. return; /* Prevent 'break NOT reachable' compiler warning. */
  1273. }
  1274. CPU_CRITICAL_EXIT();
  1275. }
  1276. /* ---------------- ALLOC MEM FOR POOL ---------------- */
  1277. /* Calc blk size with align. */
  1278. blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align);
  1279. pool_size = blk_size_align * blk_nbr; /* Calc required size for pool. */
  1280. tbl_size = blk_nbr * sizeof(void *); /* Calc required size for free block table. */
  1281. /* Detect integer overflows in the size calculations. */
  1282. if ((blk_size_align > (DEF_INT_CPU_U_MAX_VAL / blk_nbr )) ||
  1283. (blk_nbr > (DEF_INT_CPU_U_MAX_VAL / sizeof(void *)))) {
  1284. *p_err = LIB_MEM_ERR_ADDR_OVF;
  1285. return;
  1286. }
  1287. /* Alloc mem for pool. */
  1288. p_pool_mem = (void *)Mem_SegAllocInternal("Unnamed static pool",
  1289. p_seg,
  1290. pool_size,
  1291. blk_align,
  1292. LIB_MEM_PADDING_ALIGN_NONE,
  1293. p_bytes_reqd,
  1294. p_err);
  1295. if (*p_err != LIB_MEM_ERR_NONE) {
  1296. return;
  1297. }
  1298. /* ------------ ALLOC MEM FOR FREE BLK TBL ------------ */
  1299. p_pool->BlkFreeTbl = (void **)Mem_SegAllocInternal("Unnamed static pool free blk tbl",
  1300. &Mem_SegHeap,
  1301. tbl_size,
  1302. sizeof(CPU_ALIGN),
  1303. LIB_MEM_PADDING_ALIGN_NONE,
  1304. p_bytes_reqd,
  1305. p_err);
  1306. if (*p_err != LIB_MEM_ERR_NONE) {
  1307. return;
  1308. }
  1309. /* ------------------ INIT BLK LIST ------------------- */
  1310. p_blk = (CPU_INT08U *)p_pool_mem;
  1311. for (blk_ix = 0; blk_ix < blk_nbr; blk_ix++) {
  1312. p_pool->BlkFreeTbl[blk_ix] = p_blk;
  1313. p_blk += blk_size_align;
  1314. }
  1315. /* ------------------ INIT POOL DATA ------------------ */
  1316. pool_addr_end = (CPU_ADDR)p_pool_mem + (pool_size - 1u);
  1317. p_pool->PoolAddrStart = p_pool_mem;
  1318. p_pool->PoolAddrEnd = (void *)pool_addr_end;
  1319. p_pool->BlkNbr = blk_nbr;
  1320. p_pool->BlkSize = blk_size_align;
  1321. p_pool->BlkFreeTblIx = blk_nbr;
  1322. }
  1323. #endif
  1324. /*
  1325. *********************************************************************************************************
  1326. * Mem_PoolClr()
  1327. *
  1328. * Description : Clears a memory pool (see Note #1).
  1329. *
  1330. * Argument(s) : p_pool Pointer to a memory pool structure to clear (see Note #2).
  1331. *
  1332. * p_err Pointer to variable that will receive the return error code from this function :
  1333. *
  1334. * LIB_MEM_ERR_NONE Operation was successful.
  1335. * LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer.
  1336. *
  1337. * Return(s) : none.
  1338. *
  1339. * Caller(s) : Application,
  1340. * Mem_PoolCreate().
  1341. *
  1342. * Note(s) : (1) (a) Mem_PoolClr() ONLY clears a memory pool structure's variables & should ONLY be
  1343. * called to initialize a memory pool structure prior to calling Mem_PoolCreate().
  1344. *
  1345. * (b) Mem_PoolClr() does NOT deallocate memory from the memory pool or deallocate the
  1346. * memory pool itself & MUST NOT be called after calling Mem_PoolCreate() since
  1347. * this will likely corrupt the memory pool management.
  1348. *
  1349. * (2) Assumes 'p_pool' points to a valid memory pool (if non-NULL).
  1350. *
  1351. * (3) This function is DEPRECATED and will be removed in a future version of this product.
  1352. *********************************************************************************************************
  1353. */
  1354. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1355. void Mem_PoolClr (MEM_POOL *p_pool,
  1356. LIB_ERR *p_err)
  1357. {
  1358. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE RTN ERR PTR --------------- */
  1359. if (p_err == DEF_NULL) {
  1360. CPU_SW_EXCEPTION(;);
  1361. }
  1362. /* -------------- VALIDATE MEM POOL PTR --------------- */
  1363. if (p_pool == DEF_NULL) {
  1364. *p_err = LIB_MEM_ERR_NULL_PTR;
  1365. return;
  1366. }
  1367. #endif
  1368. p_pool->PoolAddrStart = DEF_NULL;
  1369. p_pool->PoolAddrEnd = DEF_NULL;
  1370. p_pool->BlkSize = 0u;
  1371. p_pool->BlkNbr = 0u;
  1372. p_pool->BlkFreeTbl = DEF_NULL;
  1373. p_pool->BlkFreeTblIx = 0u;
  1374. *p_err = LIB_MEM_ERR_NONE;
  1375. }
  1376. #endif
  1377. /*
  1378. *********************************************************************************************************
  1379. * Mem_PoolBlkGet()
  1380. *
  1381. * Description : Gets a memory block from memory pool.
  1382. *
  1383. * Argument(s) : p_pool Pointer to memory pool to get memory block from.
  1384. *
  1385. * size Size of requested memory (in bytes).
  1386. *
  1387. * p_err Pointer to variable that will receive the return error code from this function :
  1388. *
  1389. * LIB_MEM_ERR_NONE Operation was successful.
  1390. * LIB_MEM_ERR_INVALID_BLK_SIZE Invalid memory pool block size requested.
  1391. * LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer.
  1392. * LIB_MEM_ERR_POOL_EMPTY NO memory blocks available in memory pool.
  1393. *
  1394. * Return(s) : Pointer to memory block, if NO error(s).
  1395. *
  1396. * Pointer to NULL, otherwise.
  1397. *
  1398. * Caller(s) : Application.
  1399. *
  1400. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  1401. * Mem_DynPoolBlkGet() should be used instead.
  1402. *********************************************************************************************************
  1403. */
  1404. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1405. void *Mem_PoolBlkGet (MEM_POOL *p_pool,
  1406. CPU_SIZE_T size,
  1407. LIB_ERR *p_err)
  1408. {
  1409. CPU_INT08U *p_blk;
  1410. CPU_SR_ALLOC();
  1411. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL GET --------------- */
  1412. if (p_err == DEF_NULL) { /* Validate err ptr. */
  1413. CPU_SW_EXCEPTION(DEF_NULL);
  1414. }
  1415. if (p_pool == DEF_NULL) { /* Validate pool ptr. */
  1416. *p_err = LIB_MEM_ERR_NULL_PTR;
  1417. return (DEF_NULL);
  1418. }
  1419. if (size < 1u) { /* Validate req'd size as non-NULL. */
  1420. *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE;
  1421. return (DEF_NULL);
  1422. }
  1423. if (size > p_pool->BlkSize) { /* Validate req'd size <= mem pool blk size. */
  1424. *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE;
  1425. return (DEF_NULL);
  1426. }
  1427. #else
  1428. (void)size; /* Prevent possible 'variable unused' warning. */
  1429. #endif
  1430. /* -------------- GET MEM BLK FROM POOL --------------- */
  1431. p_blk = DEF_NULL;
  1432. CPU_CRITICAL_ENTER();
  1433. if (p_pool->BlkFreeTblIx > 0u) {
  1434. p_pool->BlkFreeTblIx -= 1u;
  1435. p_blk = (CPU_INT08U *)p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx];
  1436. p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = DEF_NULL;
  1437. }
  1438. CPU_CRITICAL_EXIT();
  1439. if (p_blk == DEF_NULL) {
  1440. *p_err = LIB_MEM_ERR_POOL_EMPTY;
  1441. } else {
  1442. *p_err = LIB_MEM_ERR_NONE;
  1443. }
  1444. return (p_blk);
  1445. }
  1446. #endif
  1447. /*
  1448. *********************************************************************************************************
  1449. * Mem_PoolBlkFree()
  1450. *
  1451. * Description : Free a memory block to memory pool.
  1452. *
  1453. * Argument(s) : p_pool Pointer to memory pool to free memory block.
  1454. *
  1455. * p_blk Pointer to memory block address to free.
  1456. *
  1457. * p_err Pointer to variable that will receive the return error code from this function :
  1458. *
  1459. * LIB_MEM_ERR_NONE Operation was successful.
  1460. * LIB_MEM_ERR_NULL_PTR Argument 'p_pool'/'p_blk' passed
  1461. * a NULL pointer.
  1462. * LIB_MEM_ERR_INVALID_BLK_ADDR Invalid memory block address.
  1463. * LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL Memory block address already
  1464. * in memory pool.
  1465. * LIB_MEM_ERR_POOL_FULL Pool is full.
  1466. *
  1467. * Return(s) : none.
  1468. *
  1469. * Caller(s) : Application.
  1470. *
  1471. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  1472. * Mem_DynPoolBlkFree() should be used instead.
  1473. *********************************************************************************************************
  1474. */
  1475. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1476. void Mem_PoolBlkFree (MEM_POOL *p_pool,
  1477. void *p_blk,
  1478. LIB_ERR *p_err)
  1479. {
  1480. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1481. CPU_SIZE_T tbl_ix;
  1482. CPU_BOOLEAN addr_valid;
  1483. #endif
  1484. CPU_SR_ALLOC();
  1485. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* -------------- VALIDATE MEM POOL FREE -------------- */
  1486. if (p_err == DEF_NULL) {
  1487. CPU_SW_EXCEPTION(;);
  1488. }
  1489. if (p_pool == DEF_NULL) { /* Validate mem ptrs. */
  1490. *p_err = LIB_MEM_ERR_NULL_PTR;
  1491. return;
  1492. }
  1493. if (p_blk == DEF_NULL) {
  1494. *p_err = LIB_MEM_ERR_NULL_PTR;
  1495. return;
  1496. }
  1497. addr_valid = Mem_PoolBlkIsValidAddr(p_pool, p_blk); /* Validate mem blk as valid pool blk addr. */
  1498. if (addr_valid != DEF_OK) {
  1499. *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR;
  1500. return;
  1501. }
  1502. CPU_CRITICAL_ENTER(); /* Make sure blk isn't already in free list. */
  1503. for (tbl_ix = 0u; tbl_ix < p_pool->BlkNbr; tbl_ix++) {
  1504. if (p_pool->BlkFreeTbl[tbl_ix] == p_blk) {
  1505. CPU_CRITICAL_EXIT();
  1506. *p_err = LIB_MEM_ERR_INVALID_BLK_ADDR_IN_POOL;
  1507. return;
  1508. }
  1509. }
  1510. #else /* Double-free possibility if not in critical section. */
  1511. CPU_CRITICAL_ENTER();
  1512. #endif
  1513. /* --------------- FREE MEM BLK TO POOL --------------- */
  1514. if (p_pool->BlkFreeTblIx >= p_pool->BlkNbr) {
  1515. CPU_CRITICAL_EXIT();
  1516. *p_err = LIB_MEM_ERR_POOL_FULL;
  1517. return;
  1518. }
  1519. p_pool->BlkFreeTbl[p_pool->BlkFreeTblIx] = p_blk;
  1520. p_pool->BlkFreeTblIx += 1u;
  1521. CPU_CRITICAL_EXIT();
  1522. *p_err = LIB_MEM_ERR_NONE;
  1523. }
  1524. #endif
  1525. /*
  1526. *********************************************************************************************************
  1527. * Mem_PoolBlkGetNbrAvail()
  1528. *
  1529. * Description : Get memory pool's remaining number of blocks available to allocate.
  1530. *
  1531. * Argument(s) : p_pool Pointer to a memory pool structure.
  1532. *
  1533. * p_err Pointer to variable that will receive the return error code from this function :
  1534. *
  1535. * LIB_MEM_ERR_NONE Operation was successful.
  1536. * LIB_MEM_ERR_NULL_PTR Argument 'p_pool' passed a NULL pointer.
  1537. *
  1538. * Return(s) : Remaining memory pool blocks, if NO error(s).
  1539. *
  1540. * 0, otherwise.
  1541. *
  1542. * Caller(s) : Application.
  1543. *
  1544. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  1545. * Mem_DynPoolBlkNbrAvailGet() should be used instead.
  1546. *********************************************************************************************************
  1547. */
  1548. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1549. MEM_POOL_BLK_QTY Mem_PoolBlkGetNbrAvail (MEM_POOL *p_pool,
  1550. LIB_ERR *p_err)
  1551. {
  1552. CPU_SIZE_T nbr_avail;
  1553. CPU_SR_ALLOC();
  1554. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1555. /* --------------- VALIDATE RTN ERR PTR --------------- */
  1556. if (p_err == DEF_NULL) {
  1557. CPU_SW_EXCEPTION(0u);
  1558. }
  1559. /* ---------------- VALIDATE MEM POOL ----------------- */
  1560. if (p_pool == DEF_NULL) { /* Validate mem ptr. */
  1561. *p_err = LIB_MEM_ERR_NULL_PTR;
  1562. return (0u);
  1563. }
  1564. #endif
  1565. CPU_CRITICAL_ENTER();
  1566. nbr_avail = p_pool->BlkFreeTblIx;
  1567. CPU_CRITICAL_EXIT();
  1568. *p_err = LIB_MEM_ERR_NONE;
  1569. return (nbr_avail);
  1570. }
  1571. #endif
  1572. /*
  1573. *********************************************************************************************************
  1574. * Mem_DynPoolCreate()
  1575. *
  1576. * Description : Creates a dynamic memory pool.
  1577. *
  1578. * Argument(s) : p_name Pointer to pool name.
  1579. *
  1580. * p_pool Pointer to pool data.
  1581. *
  1582. * p_seg Pointer to segment from which to allocate memory. Will be allocated from
  1583. * general-purpose heap if null.
  1584. *
  1585. * blk_size Size of memory block to allocate from pool, in bytes. See Note #1.
  1586. *
  1587. * blk_align Required alignment of memory block, in bytes. MUST be a power of 2.
  1588. *
  1589. * blk_qty_init Initial number of elements to be allocated in pool.
  1590. *
  1591. * blk_qty_max Maximum number of elements that can be allocated from this pool. Set to
  1592. * LIB_MEM_BLK_QTY_UNLIMITED if no limit.
  1593. *
  1594. * p_err Pointer to variable that will receive the return error code from this function :
  1595. *
  1596. * LIB_MEM_ERR_NONE Operation was successful.
  1597. *
  1598. * --------------------RETURNED BY Mem_DynPoolCreateInternal()-------------------
  1599. * LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment.
  1600. * LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size.
  1601. * LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max.
  1602. * LIB_MEM_ERR_NULL_PTR Pool data pointer NULL.
  1603. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1604. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1605. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1606. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1607. * LIB_MEM_ERR_ADDR_OVF Memory allocation exceeds address space.
  1608. *
  1609. * Return(s) : None.
  1610. *
  1611. * Caller(s) : Application.
  1612. *
  1613. * Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free
  1614. * block is stored in the block itself (only when free/unused).
  1615. *********************************************************************************************************
  1616. */
  1617. void Mem_DynPoolCreate (const CPU_CHAR *p_name,
  1618. MEM_DYN_POOL *p_pool,
  1619. MEM_SEG *p_seg,
  1620. CPU_SIZE_T blk_size,
  1621. CPU_SIZE_T blk_align,
  1622. CPU_SIZE_T blk_qty_init,
  1623. CPU_SIZE_T blk_qty_max,
  1624. LIB_ERR *p_err)
  1625. {
  1626. if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */
  1627. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1628. p_seg = &Mem_SegHeap;
  1629. #else
  1630. *p_err = LIB_MEM_ERR_NULL_PTR;
  1631. return;
  1632. #endif
  1633. }
  1634. Mem_DynPoolCreateInternal(p_name,
  1635. p_pool,
  1636. p_seg,
  1637. blk_size,
  1638. blk_align,
  1639. LIB_MEM_PADDING_ALIGN_NONE,
  1640. blk_qty_init,
  1641. blk_qty_max,
  1642. p_err);
  1643. }
  1644. /*
  1645. *********************************************************************************************************
  1646. * Mem_DynPoolCreateHW()
  1647. *
  1648. * Description : Creates a dynamic memory pool. Memory blocks will be padded according to memory segment's
  1649. * properties.
  1650. *
  1651. * Argument(s) : p_name Pointer to pool name.
  1652. *
  1653. * p_pool Pointer to pool data.
  1654. *
  1655. * p_seg Pointer to segment from which to allocate memory. Will allocate from
  1656. * general-purpose heap if null.
  1657. *
  1658. * blk_size Size of memory block to allocate from pool, in bytes. See Note #1.
  1659. *
  1660. * blk_align Required alignment of memory block, in bytes. MUST be a power of 2.
  1661. *
  1662. * blk_qty_init Initial number of elements to be allocated in pool.
  1663. *
  1664. * blk_qty_max Maximum number of elements that can be allocated from this pool. Set to
  1665. * LIB_MEM_BLK_QTY_UNLIMITED if no limit.
  1666. *
  1667. * p_err Pointer to variable that will receive the return error code from this function :
  1668. *
  1669. * LIB_MEM_ERR_NONE Operation was successful.
  1670. *
  1671. * -------------------RETURNED BY Mem_DynPoolCreateInternal()-------------------
  1672. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1673. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1674. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1675. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1676. * LIB_MEM_ERR_ADDR_OVF Memory allocation exceeds address space.
  1677. *
  1678. * Return(s) : None.
  1679. *
  1680. * Caller(s) : Application.
  1681. *
  1682. * Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free
  1683. * block is stored in the block itself (only when free/unused).
  1684. *********************************************************************************************************
  1685. */
  1686. void Mem_DynPoolCreateHW (const CPU_CHAR *p_name,
  1687. MEM_DYN_POOL *p_pool,
  1688. MEM_SEG *p_seg,
  1689. CPU_SIZE_T blk_size,
  1690. CPU_SIZE_T blk_align,
  1691. CPU_SIZE_T blk_qty_init,
  1692. CPU_SIZE_T blk_qty_max,
  1693. LIB_ERR *p_err)
  1694. {
  1695. if (p_seg == DEF_NULL) { /* Alloc from heap if p_seg is null. */
  1696. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  1697. p_seg = &Mem_SegHeap;
  1698. #else
  1699. *p_err = LIB_MEM_ERR_NULL_PTR;
  1700. return;
  1701. #endif
  1702. }
  1703. Mem_DynPoolCreateInternal(p_name,
  1704. p_pool,
  1705. p_seg,
  1706. blk_size,
  1707. blk_align,
  1708. p_seg->PaddingAlign,
  1709. blk_qty_init,
  1710. blk_qty_max,
  1711. p_err);
  1712. }
  1713. /*
  1714. *********************************************************************************************************
  1715. * Mem_DynPoolBlkGet()
  1716. *
  1717. * Description : Gets a memory block from specified pool, growing it if needed.
  1718. *
  1719. * Argument(s) : p_pool Pointer to pool data.
  1720. *
  1721. * p_err Pointer to variable that will receive the return error code from this function :
  1722. *
  1723. * LIB_MEM_ERR_NONE Operation was successful.
  1724. * LIB_MEM_ERR_NULL_PTR Pool data pointer NULL.
  1725. * LIB_MEM_ERR_POOL_EMPTY Pools is empty.
  1726. *
  1727. * ----------------------RETURNED BY Mem_SegAllocInternal()-----------------------
  1728. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  1729. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  1730. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  1731. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  1732. *
  1733. * Return(s) : Pointer to memory block, if successful.
  1734. *
  1735. * DEF_NULL, otherwise.
  1736. *
  1737. * Caller(s) : Application.
  1738. *
  1739. * Note(s) : none.
  1740. *********************************************************************************************************
  1741. */
  1742. void *Mem_DynPoolBlkGet (MEM_DYN_POOL *p_pool,
  1743. LIB_ERR *p_err)
  1744. {
  1745. void *p_blk;
  1746. const CPU_CHAR *p_pool_name;
  1747. CPU_SR_ALLOC();
  1748. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1749. if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */
  1750. CPU_SW_EXCEPTION(DEF_NULL);
  1751. }
  1752. if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */
  1753. *p_err = LIB_MEM_ERR_NULL_PTR;
  1754. return (DEF_NULL);
  1755. }
  1756. #endif
  1757. /* Ensure pool is not empty if qty is limited. */
  1758. if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) {
  1759. CPU_CRITICAL_ENTER();
  1760. if (p_pool->BlkAllocCnt >= p_pool->BlkQtyMax) {
  1761. CPU_CRITICAL_EXIT();
  1762. *p_err = LIB_MEM_ERR_POOL_EMPTY;
  1763. return (DEF_NULL);
  1764. }
  1765. p_pool->BlkAllocCnt++;
  1766. CPU_CRITICAL_EXIT();
  1767. }
  1768. /* --------------- ALLOC FROM FREE LIST --------------- */
  1769. CPU_CRITICAL_ENTER();
  1770. if (p_pool->BlkFreePtr != DEF_NULL) {
  1771. p_blk = p_pool->BlkFreePtr;
  1772. p_pool->BlkFreePtr = *((void **)p_blk);
  1773. CPU_CRITICAL_EXIT();
  1774. *p_err = LIB_MEM_ERR_NONE;
  1775. return (p_blk);
  1776. }
  1777. CPU_CRITICAL_EXIT();
  1778. /* ------------------ ALLOC NEW BLK ------------------- */
  1779. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  1780. p_pool_name = p_pool->NamePtr;
  1781. #else
  1782. p_pool_name = DEF_NULL;
  1783. #endif
  1784. p_blk = Mem_SegAllocInternal(p_pool_name,
  1785. p_pool->PoolSegPtr,
  1786. p_pool->BlkSize,
  1787. p_pool->BlkAlign,
  1788. p_pool->BlkPaddingAlign,
  1789. DEF_NULL,
  1790. p_err);
  1791. if (*p_err != LIB_MEM_ERR_NONE) {
  1792. if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) {
  1793. p_pool->BlkAllocCnt--;
  1794. }
  1795. return (DEF_NULL);
  1796. }
  1797. return (p_blk);
  1798. }
  1799. /*
  1800. *********************************************************************************************************
  1801. * Mem_DynPoolBlkFree()
  1802. *
  1803. * Description : Frees memory block, making it available for future use.
  1804. *
  1805. * Argument(s) : p_pool Pointer to pool data.
  1806. *
  1807. * p_blk Pointer to first byte of memory block.
  1808. *
  1809. * p_err Pointer to variable that will receive the return error code from this function :
  1810. *
  1811. * LIB_MEM_ERR_NONE Operation was successful.
  1812. * LIB_MEM_ERR_NULL_PTR 'p_pool' or 'p_blk' pointer passed is NULL.
  1813. * LIB_MEM_ERR_POOL_FULL Pool is full.
  1814. *
  1815. * Return(s) : none.
  1816. *
  1817. * Caller(s) : Application.
  1818. *
  1819. * Note(s) : none.
  1820. *********************************************************************************************************
  1821. */
  1822. void Mem_DynPoolBlkFree (MEM_DYN_POOL *p_pool,
  1823. void *p_blk,
  1824. LIB_ERR *p_err)
  1825. {
  1826. CPU_SR_ALLOC();
  1827. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1828. if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */
  1829. CPU_SW_EXCEPTION(;);
  1830. }
  1831. if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */
  1832. *p_err = LIB_MEM_ERR_NULL_PTR;
  1833. return;
  1834. }
  1835. if (p_blk == DEF_NULL) {
  1836. *p_err = LIB_MEM_ERR_NULL_PTR;
  1837. return;
  1838. }
  1839. #endif
  1840. if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) { /* Ensure pool is not full. */
  1841. CPU_CRITICAL_ENTER();
  1842. if (p_pool->BlkAllocCnt == 0u) {
  1843. CPU_CRITICAL_EXIT();
  1844. *p_err = LIB_MEM_ERR_POOL_FULL;
  1845. return;
  1846. }
  1847. p_pool->BlkAllocCnt--;
  1848. CPU_CRITICAL_EXIT();
  1849. }
  1850. CPU_CRITICAL_ENTER();
  1851. *((void **)p_blk) = p_pool->BlkFreePtr;
  1852. p_pool->BlkFreePtr = p_blk;
  1853. CPU_CRITICAL_EXIT();
  1854. *p_err = LIB_MEM_ERR_NONE;
  1855. }
  1856. /*
  1857. *********************************************************************************************************
  1858. * Mem_DynPoolBlkNbrAvailGet()
  1859. *
  1860. * Description : Gets number of available blocks in dynamic memory pool. This call will fail with a
  1861. * dynamic memory pool for which no limit was set at creation.
  1862. *
  1863. * Argument(s) : p_pool Pointer to pool data.
  1864. *
  1865. * p_err Pointer to variable that will receive the return error code from this function :
  1866. *
  1867. * LIB_MEM_ERR_NONE Operation was successful.
  1868. * LIB_MEM_ERR_NULL_PTR 'p_pool' pointer passed is NULL.
  1869. * LIB_MEM_ERR_POOL_UNLIMITED Pool has no specified limit.
  1870. *
  1871. * Return(s) : Number of blocks available in dynamic memory pool, if successful.
  1872. *
  1873. * 0, if pool is empty or if an error occurred.
  1874. *
  1875. * Caller(s) : Application.
  1876. *
  1877. * Note(s) : None.
  1878. *********************************************************************************************************
  1879. */
  1880. CPU_SIZE_T Mem_DynPoolBlkNbrAvailGet (MEM_DYN_POOL *p_pool,
  1881. LIB_ERR *p_err)
  1882. {
  1883. CPU_SIZE_T blk_nbr_avail;
  1884. CPU_SR_ALLOC();
  1885. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1886. if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */
  1887. CPU_SW_EXCEPTION(0);
  1888. }
  1889. if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */
  1890. *p_err = LIB_MEM_ERR_NULL_PTR;
  1891. return (0u);
  1892. }
  1893. #endif
  1894. if (p_pool->BlkQtyMax != LIB_MEM_BLK_QTY_UNLIMITED) {
  1895. CPU_CRITICAL_ENTER();
  1896. blk_nbr_avail = p_pool->BlkQtyMax - p_pool->BlkAllocCnt;
  1897. CPU_CRITICAL_EXIT();
  1898. *p_err = LIB_MEM_ERR_NONE;
  1899. } else {
  1900. blk_nbr_avail = 0u;
  1901. *p_err = LIB_MEM_ERR_POOL_UNLIMITED;
  1902. }
  1903. return (blk_nbr_avail);
  1904. }
  1905. /*
  1906. *********************************************************************************************************
  1907. * Mem_OutputUsage()
  1908. *
  1909. * Description : Outputs memory usage report through 'out_fnct'.
  1910. *
  1911. * Argument(s) : out_fnct Pointer to output function.
  1912. *
  1913. * print_details DEF_YES, if the size of each allocation should be printed.
  1914. * DEF_NO, otherwise.
  1915. *
  1916. * p_err Pointer to variable that will receive the return error code from this function :
  1917. *
  1918. * LIB_MEM_ERR_NONE Operation was successful.
  1919. * LIB_MEM_ERR_NULL_PTR 'out_fnct' pointer passed is NULL.
  1920. *
  1921. * ---------------------RETURNED BY Mem_SegRemSizeGet()--------------------
  1922. * LIB_MEM_ERR_NULL_PTR Segment data pointer NULL.
  1923. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory alignment.
  1924. *
  1925. * Return(s) : None.
  1926. *
  1927. * Caller(s) : Application.
  1928. *
  1929. * Note(s) : none.
  1930. *********************************************************************************************************
  1931. */
  1932. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  1933. void Mem_OutputUsage(void (*out_fnct) (CPU_CHAR *),
  1934. LIB_ERR *p_err)
  1935. {
  1936. CPU_CHAR str[DEF_INT_32U_NBR_DIG_MAX];
  1937. MEM_SEG *p_seg;
  1938. CPU_SR_ALLOC();
  1939. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  1940. if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */
  1941. CPU_SW_EXCEPTION(;);
  1942. }
  1943. if (out_fnct == DEF_NULL) { /* Chk for NULL out fnct ptr. */
  1944. *p_err = LIB_MEM_ERR_NULL_PTR;
  1945. return;
  1946. }
  1947. #endif
  1948. out_fnct((CPU_CHAR *)"---------------- Memory allocation info ----------------\r\n");
  1949. out_fnct((CPU_CHAR *)"| Type | Size | Free size | Name\r\n");
  1950. out_fnct((CPU_CHAR *)"|---------|------------|------------|-------------------\r\n");
  1951. CPU_CRITICAL_ENTER();
  1952. p_seg = Mem_SegHeadPtr;
  1953. while (p_seg != DEF_NULL) {
  1954. CPU_SIZE_T rem_size;
  1955. MEM_SEG_INFO seg_info;
  1956. MEM_ALLOC_INFO *p_alloc;
  1957. rem_size = Mem_SegRemSizeGet(p_seg, 1u, &seg_info, p_err);
  1958. if (*p_err != LIB_MEM_ERR_NONE) {
  1959. return;
  1960. }
  1961. out_fnct((CPU_CHAR *)"| Section | ");
  1962. (void)Str_FmtNbr_Int32U(seg_info.TotalSize,
  1963. 10u,
  1964. DEF_NBR_BASE_DEC,
  1965. ' ',
  1966. DEF_NO,
  1967. DEF_YES,
  1968. &str[0u]);
  1969. out_fnct(str);
  1970. out_fnct((CPU_CHAR *)" | ");
  1971. (void)Str_FmtNbr_Int32U(rem_size,
  1972. 10u,
  1973. DEF_NBR_BASE_DEC,
  1974. ' ',
  1975. DEF_NO,
  1976. DEF_YES,
  1977. &str[0u]);
  1978. out_fnct(str);
  1979. out_fnct((CPU_CHAR *)" | ");
  1980. out_fnct((p_seg->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_seg->NamePtr : (CPU_CHAR *)"Unknown");
  1981. out_fnct((CPU_CHAR *)"\r\n");
  1982. p_alloc = p_seg->AllocInfoHeadPtr;
  1983. while (p_alloc != DEF_NULL) {
  1984. out_fnct((CPU_CHAR *)"| -> Obj | ");
  1985. (void)Str_FmtNbr_Int32U(p_alloc->Size,
  1986. 10u,
  1987. DEF_NBR_BASE_DEC,
  1988. ' ',
  1989. DEF_NO,
  1990. DEF_YES,
  1991. &str[0u]);
  1992. out_fnct(str);
  1993. out_fnct((CPU_CHAR *)" | | ");
  1994. out_fnct((p_alloc->NamePtr != DEF_NULL) ? (CPU_CHAR *)p_alloc->NamePtr : (CPU_CHAR *)"Unknown");
  1995. out_fnct((CPU_CHAR *)"\r\n");
  1996. p_alloc = p_alloc->NextPtr;
  1997. }
  1998. p_seg = p_seg->NextPtr;
  1999. }
  2000. CPU_CRITICAL_EXIT();
  2001. *p_err = LIB_MEM_ERR_NONE;
  2002. }
  2003. #endif
  2004. /*
  2005. *********************************************************************************************************
  2006. *********************************************************************************************************
  2007. * LOCAL FUNCTIONS
  2008. *********************************************************************************************************
  2009. *********************************************************************************************************
  2010. */
  2011. /*
  2012. *********************************************************************************************************
  2013. * Mem_SegCreateCritical()
  2014. *
  2015. * Description : Creates a new memory segment to be used for runtime memory allocation or dynamic pools.
  2016. *
  2017. * Argument(s) : p_name Pointer to segment name.
  2018. *
  2019. * p_seg Pointer to segment data. Must be allocated by caller.
  2020. * ----- Argument validated by caller.
  2021. *
  2022. * seg_base_addr Segment's first byte address.
  2023. *
  2024. * padding_align Padding alignment, in bytes, that will be added to any allocated buffer
  2025. * from this memory segment. MUST be a power of 2.
  2026. * LIB_MEM_PADDING_ALIGN_NONE means no padding.
  2027. * ------------- Argument validated by caller.
  2028. *
  2029. * size Total size of segment, in bytes.
  2030. * ---- Argument validated by caller.
  2031. *
  2032. * Return(s) : Pointer to segment data, if successful.
  2033. *
  2034. * DEF_NULL, otherwise.
  2035. *
  2036. * Caller(s) : Mem_PoolCreate(),
  2037. * Mem_SegCreate().
  2038. *
  2039. * Note(s) : (1) This function MUST be called within a CRITICAL_SECTION.
  2040. *********************************************************************************************************
  2041. */
  2042. static void Mem_SegCreateCritical(const CPU_CHAR *p_name,
  2043. MEM_SEG *p_seg,
  2044. CPU_ADDR seg_base_addr,
  2045. CPU_SIZE_T padding_align,
  2046. CPU_SIZE_T size)
  2047. {
  2048. p_seg->AddrBase = seg_base_addr;
  2049. p_seg->AddrEnd = (seg_base_addr + (size - 1u));
  2050. p_seg->AddrNext = seg_base_addr;
  2051. p_seg->NextPtr = Mem_SegHeadPtr;
  2052. p_seg->PaddingAlign = padding_align;
  2053. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  2054. p_seg->NamePtr = p_name;
  2055. p_seg->AllocInfoHeadPtr = DEF_NULL;
  2056. #else
  2057. (void)p_name;
  2058. #endif
  2059. Mem_SegHeadPtr = p_seg;
  2060. }
  2061. /*
  2062. *********************************************************************************************************
  2063. * Mem_SegOverlapChkCritical()
  2064. *
  2065. * Description : Checks if existing memory segment exists or overlaps with specified memory area.
  2066. *
  2067. * Argument(s) : seg_base_addr Address of first byte of memory area.
  2068. *
  2069. * size Size of memory area, in bytes.
  2070. *
  2071. * p_err Pointer to variable that will receive the return error code from this function :
  2072. *
  2073. * LIB_MEM_ERR_INVALID_SEG_OVERLAP Segment overlaps another existing segment.
  2074. * LIB_MEM_ERR_INVALID_SEG_EXISTS Segment already exists.
  2075. *
  2076. * Return(s) : Pointer to memory segment that overlaps.
  2077. *
  2078. * DEF_NULL, otherwise.
  2079. *
  2080. * Caller(s) : Mem_PoolCreate(),
  2081. * Mem_SegCreate().
  2082. *
  2083. * Note(s) : (1) This function MUST be called within a CRITICAL_SECTION.
  2084. *********************************************************************************************************
  2085. */
  2086. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  2087. static MEM_SEG *Mem_SegOverlapChkCritical (CPU_ADDR seg_base_addr,
  2088. CPU_SIZE_T size,
  2089. LIB_ERR *p_err)
  2090. {
  2091. MEM_SEG *p_seg_chk;
  2092. CPU_ADDR seg_new_end;
  2093. CPU_ADDR seg_chk_start;
  2094. CPU_ADDR seg_chk_end;
  2095. seg_new_end = seg_base_addr + (size - 1u);
  2096. p_seg_chk = Mem_SegHeadPtr;
  2097. while (p_seg_chk != DEF_NULL) {
  2098. seg_chk_start = (CPU_ADDR)p_seg_chk->AddrBase;
  2099. seg_chk_end = (CPU_ADDR)p_seg_chk->AddrEnd;
  2100. if ((seg_base_addr == seg_chk_start) && (seg_new_end == seg_chk_end)) {
  2101. *p_err = LIB_MEM_ERR_INVALID_SEG_EXISTS;
  2102. return (p_seg_chk);
  2103. } else if (((seg_base_addr >= seg_chk_start) && (seg_base_addr <= seg_chk_end)) ||
  2104. ((seg_base_addr <= seg_chk_start) && (seg_new_end >= seg_chk_start))) {
  2105. *p_err = LIB_MEM_ERR_INVALID_SEG_OVERLAP;
  2106. return (p_seg_chk);
  2107. } else {
  2108. /* Empty Else Statement */
  2109. }
  2110. p_seg_chk = p_seg_chk->NextPtr;
  2111. }
  2112. *p_err = LIB_MEM_ERR_NONE;
  2113. return (DEF_NULL);
  2114. }
  2115. #endif
  2116. /*
  2117. *********************************************************************************************************
  2118. * Mem_SegAllocInternal()
  2119. *
  2120. * Description : Allocates memory from specified segment.
  2121. *
  2122. * Argument(s) : p_name Pointer to allocated object name. Used for allocations tracking. May be DEF_NULL.
  2123. *
  2124. * p_seg Pointer to segment from which to allocate memory.
  2125. * ----- Argument validated by caller.
  2126. *
  2127. * size Size of memory block to allocate, in bytes.
  2128. *
  2129. * align Required alignment of memory block, in bytes. MUST be a power of 2.
  2130. *
  2131. * padding_align Padding alignment, in bytes, that will be added to any allocated buffer from
  2132. * this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE
  2133. * means no padding.
  2134. *
  2135. * p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for
  2136. * the allocation to succeed. Set to DEF_NULL to skip calculation.
  2137. *
  2138. * p_err Pointer to variable that will receive the return error code from this function :
  2139. *
  2140. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  2141. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  2142. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  2143. *
  2144. * ------------------RETURNED BY Mem_SegAllocExtCritical()------------------
  2145. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  2146. *
  2147. * Return(s) : Pointer to allocated memory block, if successful.
  2148. *
  2149. * DEF_NULL, otherwise.
  2150. *
  2151. * Caller(s) : Mem_DynPoolBlkGet(),
  2152. * Mem_DynPoolCreateInternal(),
  2153. * Mem_HeapAlloc(),
  2154. * Mem_PoolCreate(),
  2155. * Mem_SegAlloc(),
  2156. * Mem_SegAllocExt(),
  2157. * Mem_SegAllocHW().
  2158. *
  2159. * Note(s) : none.
  2160. *********************************************************************************************************
  2161. */
  2162. static void *Mem_SegAllocInternal (const CPU_CHAR *p_name,
  2163. MEM_SEG *p_seg,
  2164. CPU_SIZE_T size,
  2165. CPU_SIZE_T align,
  2166. CPU_SIZE_T padding_align,
  2167. CPU_SIZE_T *p_bytes_reqd,
  2168. LIB_ERR *p_err)
  2169. {
  2170. void *p_blk;
  2171. CPU_SR_ALLOC();
  2172. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  2173. if (p_err == DEF_NULL) { /* Chk for null err ptr. */
  2174. CPU_SW_EXCEPTION(DEF_NULL);
  2175. }
  2176. if (size < 1u) { /* Chk for invalid sized mem req. */
  2177. *p_err = LIB_MEM_ERR_INVALID_MEM_SIZE;
  2178. return (DEF_NULL);
  2179. }
  2180. if (MATH_IS_PWR2(align) != DEF_YES) { /* Chk that align is a pwr of 2. */
  2181. *p_err = LIB_MEM_ERR_INVALID_MEM_ALIGN;
  2182. return (DEF_NULL);
  2183. }
  2184. #endif
  2185. CPU_CRITICAL_ENTER();
  2186. p_blk = Mem_SegAllocExtCritical(p_seg,
  2187. size,
  2188. align,
  2189. padding_align,
  2190. p_bytes_reqd,
  2191. p_err);
  2192. if (*p_err != LIB_MEM_ERR_NONE) {
  2193. CPU_CRITICAL_EXIT();
  2194. return (DEF_NULL);
  2195. }
  2196. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED) /* Track alloc if req'd. */
  2197. Mem_SegAllocTrackCritical(p_name,
  2198. p_seg,
  2199. size,
  2200. p_err);
  2201. if (*p_err != LIB_MEM_ERR_NONE) {
  2202. CPU_CRITICAL_EXIT();
  2203. return (DEF_NULL);
  2204. }
  2205. #else
  2206. (void)p_name;
  2207. #endif
  2208. CPU_CRITICAL_EXIT();
  2209. return (p_blk);
  2210. }
  2211. /*
  2212. *********************************************************************************************************
  2213. * Mem_SegAllocExtCritical()
  2214. *
  2215. * Description : Allocates memory from specified segment.
  2216. *
  2217. * Argument(s) : p_seg Pointer to segment from which to allocate memory.
  2218. *
  2219. * size Size of memory block to allocate, in bytes.
  2220. *
  2221. * align Required alignment of memory block, in bytes. MUST be a power of 2.
  2222. *
  2223. * padding_align Padding alignment, in bytes, that will be added to any allocated buffer from
  2224. * this memory segment. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE
  2225. * means no padding.
  2226. *
  2227. * p_bytes_reqd Pointer to variable that will receive the number of free bytes missing for
  2228. * the allocation to succeed. Set to DEF_NULL to skip calculation.
  2229. *
  2230. * p_err Pointer to variable that will receive the return error code from this function :
  2231. *
  2232. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  2233. *
  2234. * Return(s) : Pointer to allocated memory block, if successful.
  2235. *
  2236. * DEF_NULL, otherwise.
  2237. *
  2238. * Caller(s) : Mem_PoolCreate(),
  2239. * Mem_SegAllocInternal(),
  2240. * Mem_SegAllocTrackCritical().
  2241. *
  2242. * Note(s) : (1) This function MUST be called within a CRITICAL_SECTION.
  2243. *********************************************************************************************************
  2244. */
  2245. static void *Mem_SegAllocExtCritical (MEM_SEG *p_seg,
  2246. CPU_SIZE_T size,
  2247. CPU_SIZE_T align,
  2248. CPU_SIZE_T padding_align,
  2249. CPU_SIZE_T *p_bytes_reqd,
  2250. LIB_ERR *p_err)
  2251. {
  2252. CPU_ADDR blk_addr;
  2253. CPU_ADDR addr_next;
  2254. CPU_SIZE_T size_rem_seg;
  2255. CPU_SIZE_T size_tot_blk;
  2256. CPU_SIZE_T blk_align = DEF_MAX(align, padding_align);
  2257. blk_addr = MATH_ROUND_INC_UP_PWR2(p_seg->AddrNext, /* Compute align'ed blk addr. */
  2258. blk_align);
  2259. addr_next = MATH_ROUND_INC_UP_PWR2(blk_addr + size, /* Compute addr of next alloc. */
  2260. padding_align);
  2261. size_rem_seg = (p_seg->AddrEnd - p_seg->AddrNext) + 1u;
  2262. size_tot_blk = addr_next - p_seg->AddrNext; /* Compute tot blk size including align and padding. */
  2263. if (size_rem_seg < size_tot_blk) { /* If seg doesn't have enough space ... */
  2264. if (p_bytes_reqd != DEF_NULL) { /* ... calc nbr of req'd bytes. */
  2265. *p_bytes_reqd = size_tot_blk - size_rem_seg;
  2266. }
  2267. *p_err = LIB_MEM_ERR_SEG_OVF;
  2268. return (DEF_NULL);
  2269. }
  2270. p_seg->AddrNext = addr_next;
  2271. *p_err = LIB_MEM_ERR_NONE;
  2272. return ((void *)blk_addr);
  2273. }
  2274. /*
  2275. *********************************************************************************************************
  2276. * Mem_SegAllocTrackCritical()
  2277. *
  2278. * Description : Tracks segment allocation, adding the 'size' of the allocation under the 'p_name' entry.
  2279. *
  2280. * Argument(s) : p_name Pointer to the name of the object. This string is not copied and its memory should
  2281. * remain accessible at all times.
  2282. *
  2283. * p_seg Pointer to segment data.
  2284. *
  2285. * size Allocation size, in bytes.
  2286. *
  2287. * p_err Pointer to variable that will receive the return error code from this function :
  2288. *
  2289. * LIB_MEM_ERR_HEAP_EMPTY No more memory available on heap
  2290. *
  2291. * --------------RETURNED BY Mem_SegAllocExtCritical()---------------
  2292. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  2293. *
  2294. * Return(s) : none.
  2295. *
  2296. * Caller(s) : Mem_PoolCreate(),
  2297. * Mem_SegAllocInternal().
  2298. *
  2299. * Note(s) : none.
  2300. *********************************************************************************************************
  2301. */
  2302. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  2303. static void Mem_SegAllocTrackCritical (const CPU_CHAR *p_name,
  2304. MEM_SEG *p_seg,
  2305. CPU_SIZE_T size,
  2306. LIB_ERR *p_err)
  2307. {
  2308. MEM_ALLOC_INFO *p_alloc;
  2309. /* ------- UPDATE ALLOC INFO LIST, IF POSSIBLE -------- */
  2310. p_alloc = p_seg->AllocInfoHeadPtr;
  2311. while (p_alloc != DEF_NULL) {
  2312. if (p_alloc->NamePtr == p_name) {
  2313. p_alloc->Size += size;
  2314. *p_err = LIB_MEM_ERR_NONE;
  2315. return;
  2316. }
  2317. p_alloc = p_alloc->NextPtr;
  2318. }
  2319. /* --------- ADD NEW ALLOC INFO ENTRY IN LIST --------- */
  2320. p_alloc = (MEM_ALLOC_INFO *)Mem_SegAllocExtCritical(&Mem_SegHeap, /* Alloc new alloc info struct on heap. */
  2321. sizeof(MEM_ALLOC_INFO),
  2322. sizeof(CPU_ALIGN),
  2323. LIB_MEM_PADDING_ALIGN_NONE,
  2324. DEF_NULL,
  2325. p_err);
  2326. if (*p_err != LIB_MEM_ERR_NONE) {
  2327. return;
  2328. }
  2329. p_alloc->NamePtr = p_name; /* Populate alloc info. */
  2330. p_alloc->Size = size;
  2331. p_alloc->NextPtr = p_seg->AllocInfoHeadPtr; /* Prepend new item in list. */
  2332. p_seg->AllocInfoHeadPtr = p_alloc;
  2333. }
  2334. #endif
  2335. /*
  2336. *********************************************************************************************************
  2337. * Mem_DynPoolCreateInternal()
  2338. *
  2339. * Description : Creates a dynamic memory pool.
  2340. *
  2341. * Argument(s) : p_name Pointer to pool name.
  2342. *
  2343. * p_pool Pointer to pool data.
  2344. *
  2345. * p_seg Pointer to segment from which to allocate memory.
  2346. *
  2347. * blk_size Size of memory block to allocate from pool, in bytes. See Note #1.
  2348. *
  2349. * blk_align Required alignment of memory block, in bytes. MUST be a power of 2.
  2350. *
  2351. * blk_padding_align Block's padding alignment, in bytes, that will be added at the end
  2352. * of block's buffer. MUST be a power of 2. LIB_MEM_PADDING_ALIGN_NONE
  2353. * means no padding.
  2354. *
  2355. * blk_qty_init Initial number of elements to be allocated in pool.
  2356. *
  2357. * blk_qty_max Maximum number of elements that can be allocated from this pool. Set to
  2358. * LIB_MEM_BLK_QTY_UNLIMITED if no limit.
  2359. *
  2360. * p_err Pointer to variable that will receive the return error code from this function :
  2361. *
  2362. * LIB_MEM_ERR_INVALID_BLK_ALIGN Invalid requested block alignment.
  2363. * LIB_MEM_ERR_INVALID_BLK_SIZE Invalid requested block size.
  2364. * LIB_MEM_ERR_INVALID_BLK_NBR Invalid requested block quantity max.
  2365. * LIB_MEM_ERR_NULL_PTR Pool data pointer NULL.
  2366. * LIB_MEM_ERR_ADDR_OVF Memory allocation exceeds address space.
  2367. *
  2368. * ------------------RETURNED BY Mem_SegAllocInternal()-------------------
  2369. * LIB_MEM_ERR_INVALID_MEM_ALIGN Invalid memory block alignment requested.
  2370. * LIB_MEM_ERR_INVALID_MEM_SIZE Invalid memory block size specified.
  2371. * LIB_MEM_ERR_NULL_PTR Error or segment data pointer NULL.
  2372. * LIB_MEM_ERR_SEG_OVF Allocation would overflow memory segment.
  2373. *
  2374. * Return(s) : None.
  2375. *
  2376. * Caller(s) : Mem_DynPoolCreate(),
  2377. * Mem_DynPoolCreateHW().
  2378. *
  2379. * Note(s) : (1) 'blk_size' must be big enough to fit a pointer since the pointer to the next free
  2380. * block is stored in the block itself (only when free/unused).
  2381. *********************************************************************************************************
  2382. */
  2383. static void Mem_DynPoolCreateInternal (const CPU_CHAR *p_name,
  2384. MEM_DYN_POOL *p_pool,
  2385. MEM_SEG *p_seg,
  2386. CPU_SIZE_T blk_size,
  2387. CPU_SIZE_T blk_align,
  2388. CPU_SIZE_T blk_padding_align,
  2389. CPU_SIZE_T blk_qty_init,
  2390. CPU_SIZE_T blk_qty_max,
  2391. LIB_ERR *p_err)
  2392. {
  2393. CPU_INT08U *p_blks = DEF_NULL;
  2394. CPU_SIZE_T seg_size;
  2395. CPU_SIZE_T blk_size_align;
  2396. CPU_SIZE_T blk_align_worst = DEF_MAX(blk_align, blk_padding_align);
  2397. #if (LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
  2398. if (p_err == DEF_NULL) { /* Chk for NULL err ptr. */
  2399. CPU_SW_EXCEPTION(;);
  2400. }
  2401. if (p_pool == DEF_NULL) { /* Chk for NULL pool data ptr. */
  2402. *p_err = LIB_MEM_ERR_NULL_PTR;
  2403. return;
  2404. }
  2405. if (blk_size < 1u) { /* Chk for inv blk size. */
  2406. *p_err = LIB_MEM_ERR_INVALID_BLK_SIZE;
  2407. return;
  2408. }
  2409. if ((blk_qty_max != LIB_MEM_BLK_QTY_UNLIMITED) && /* Chk for invalid blk qty. */
  2410. (blk_qty_init > blk_qty_max)) {
  2411. *p_err = LIB_MEM_ERR_INVALID_BLK_NBR;
  2412. return;
  2413. }
  2414. if (MATH_IS_PWR2(blk_align) != DEF_YES) { /* Chk for illegal align spec. */
  2415. *p_err = LIB_MEM_ERR_INVALID_BLK_ALIGN;
  2416. return;
  2417. }
  2418. #endif
  2419. /* Calc blk size with align. */
  2420. if (blk_size < sizeof(void *)) { /* If size if smaller than ptr ... */
  2421. /* ... inc size to ptr size. */
  2422. blk_size_align = MATH_ROUND_INC_UP_PWR2(sizeof(void *), blk_align_worst);
  2423. } else {
  2424. blk_size_align = MATH_ROUND_INC_UP_PWR2(blk_size, blk_align_worst);
  2425. }
  2426. if (blk_qty_init != 0u) { /* Alloc init blks. */
  2427. CPU_SIZE_T i;
  2428. seg_size = blk_size_align * blk_qty_init; /* Calc required size for pool. */
  2429. /* Detect integer overflow in the seg_size calculation. */
  2430. if (blk_size_align > (DEF_INT_CPU_U_MAX_VAL / blk_qty_init)) {
  2431. *p_err = LIB_MEM_ERR_ADDR_OVF;
  2432. return;
  2433. }
  2434. p_blks = (CPU_INT08U *)Mem_SegAllocInternal(p_name,
  2435. p_seg,
  2436. seg_size,
  2437. DEF_MAX(blk_align, sizeof(void *)),
  2438. LIB_MEM_PADDING_ALIGN_NONE,
  2439. DEF_NULL,
  2440. p_err);
  2441. if (*p_err != LIB_MEM_ERR_NONE) {
  2442. return;
  2443. }
  2444. /* ----------------- CREATE POOL DATA ----------------- */
  2445. /* Init free list. */
  2446. p_pool->BlkFreePtr = (void *)p_blks;
  2447. for (i = 0u; i < blk_qty_init - 1u; i++) {
  2448. *((void **)p_blks) = p_blks + blk_size_align;
  2449. p_blks += blk_size_align;
  2450. }
  2451. *((void **)p_blks) = DEF_NULL;
  2452. } else {
  2453. p_pool->BlkFreePtr = DEF_NULL;
  2454. }
  2455. #if (LIB_MEM_CFG_HEAP_SIZE > 0u)
  2456. p_pool->PoolSegPtr = ((p_seg != DEF_NULL) ? p_seg : &Mem_SegHeap);
  2457. #else
  2458. p_pool->PoolSegPtr = p_seg;
  2459. #endif
  2460. p_pool->BlkSize = blk_size;
  2461. p_pool->BlkAlign = blk_align_worst;
  2462. p_pool->BlkPaddingAlign = blk_padding_align;
  2463. p_pool->BlkQtyMax = blk_qty_max;
  2464. p_pool->BlkAllocCnt = 0u;
  2465. #if (LIB_MEM_CFG_DBG_INFO_EN == DEF_ENABLED)
  2466. p_pool->NamePtr = p_name;
  2467. #endif
  2468. *p_err = LIB_MEM_ERR_NONE;
  2469. }
  2470. /*
  2471. *********************************************************************************************************
  2472. * Mem_PoolBlkIsValidAddr()
  2473. *
  2474. * Description : Calculates if a given memory block address is valid for the memory pool.
  2475. *
  2476. * Argument(s) : p_pool Pointer to memory pool structure to validate memory block address.
  2477. * ------ Argument validated by caller.
  2478. *
  2479. * p_mem Pointer to memory block address to validate.
  2480. * ----- Argument validated by caller.
  2481. *
  2482. * Return(s) : DEF_YES, if valid memory pool block address.
  2483. *
  2484. * DEF_NO, otherwise.
  2485. *
  2486. * Caller(s) : Mem_PoolBlkFree().
  2487. *
  2488. * Note(s) : (1) This function is DEPRECATED and will be removed in a future version of this product.
  2489. *********************************************************************************************************
  2490. */
  2491. #if ((LIB_MEM_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) && \
  2492. (LIB_MEM_CFG_HEAP_SIZE > 0u))
  2493. static CPU_BOOLEAN Mem_PoolBlkIsValidAddr (MEM_POOL *p_pool,
  2494. void *p_mem)
  2495. {
  2496. CPU_ADDR pool_offset;
  2497. if ((p_mem < p_pool->PoolAddrStart) ||
  2498. (p_mem > p_pool->PoolAddrEnd)) {
  2499. return (DEF_FALSE);
  2500. }
  2501. pool_offset = (CPU_ADDR)p_mem - (CPU_ADDR)p_pool->PoolAddrStart;
  2502. if (pool_offset % p_pool->BlkSize != 0u) {
  2503. return (DEF_FALSE);
  2504. } else {
  2505. return (DEF_TRUE);
  2506. }
  2507. }
  2508. #endif