NXP / fsl_phy_mcr20a

Fork of fsl_phy_mcr20a by Freescale

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MemManager.c Source File

MemManager.c

Go to the documentation of this file.
00001 /*!
00002 * Copyright (c) 2015, Freescale Semiconductor, Inc.
00003 * All rights reserved.
00004 *
00005 * \file MemManager.c
00006 * This is the source file for the Memory Manager.
00007 *
00008 * Redistribution and use in source and binary forms, with or without modification,
00009 * are permitted provided that the following conditions are met:
00010 *
00011 * o Redistributions of source code must retain the above copyright notice, this list
00012 *   of conditions and the following disclaimer.
00013 *
00014 * o Redistributions in binary form must reproduce the above copyright notice, this
00015 *   list of conditions and the following disclaimer in the documentation and/or
00016 *   other materials provided with the distribution.
00017 *
00018 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
00019 *   contributors may be used to endorse or promote products derived from this
00020 *   software without specific prior written permission.
00021 *
00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00023 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00024 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00025 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00026 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00029 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00030 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 */
00033 
00034 
00035 /*! *********************************************************************************
00036 *************************************************************************************
00037 * Include
00038 *************************************************************************************
00039 ********************************************************************************** */
00040 #include "EmbeddedTypes.h "
00041 #include "mbedAbstraction.h"
00042 #include "fsl_os_abstraction.h"
00043 #ifdef MEM_DEBUG
00044 #include "Panic.h"
00045 #endif
00046 #include "MemManager.h "
00047 
00048 
00049 /*! *********************************************************************************
00050 *************************************************************************************
00051 * Private memory declarations
00052 *************************************************************************************
00053 ********************************************************************************** */
00054 
00055 #define _block_size_  {
00056 #define _number_of_blocks_  ,
00057 #define _eol_  },
00058            
00059 poolInfo_t poolInfo[] =
00060 {
00061   PoolsDetails_c
00062   {0, 0} /*termination tag*/
00063 };
00064 
00065 #undef _block_size_
00066 #undef _number_of_blocks_
00067 #undef _eol_
00068 
00069 #define _block_size_ (sizeof(listHeader_t)+
00070 #define _number_of_blocks_ ) *
00071 #define _eol_  +
00072 
00073 #define heapSize_c (PoolsDetails_c 0)
00074 
00075 // Heap
00076 uint8_t memHeap[heapSize_c];
00077 const uint32_t heapSize = heapSize_c;
00078 
00079 #undef _block_size_
00080 #undef _number_of_blocks_
00081 #undef _eol_
00082 
00083 #define _block_size_ 0 *
00084 #define _number_of_blocks_ + 0 *
00085 #define _eol_  + 1 +
00086 
00087 #define poolCount (PoolsDetails_c 0)
00088 
00089 // Memory pool info and anchors.
00090 pools_t memPools[poolCount];
00091 
00092 #undef _block_size_
00093 #undef _number_of_blocks_
00094 #undef _eol_
00095 
00096 #ifdef MEM_TRACKING
00097 
00098 #define _block_size_ 0*
00099 #define _number_of_blocks_ +
00100 #define _eol_  +
00101 
00102 #define mTotalNoOfMsgs_d (PoolsDetails_c 0)
00103 static const uint16_t mTotalNoOfMsgs_c = mTotalNoOfMsgs_d;
00104 blockTracking_t memTrack[mTotalNoOfMsgs_d];
00105 
00106 #undef _block_size_
00107 #undef _number_of_blocks_
00108 #undef _eol_
00109 
00110 #endif /*MEM_TRACKING*/
00111 
00112 // Free messages counter. Not used by module.
00113 uint16_t gFreeMessagesCount;
00114 
00115 /*! *********************************************************************************
00116 *************************************************************************************
00117 * Public functions
00118 *************************************************************************************
00119 ********************************************************************************** */
00120 
00121 /*! *********************************************************************************
00122 * \brief   This function initializes the message module private variables. 
00123 *          Must be called at boot time, or if device is reset.
00124 *
00125 * \param[in] none
00126 *
00127 * \return MEM_SUCCESS_c if initialization is successful. (It's always successful).
00128 *
00129 ********************************************************************************** */
00130 memStatus_t  MEM_Init()
00131 {
00132   poolInfo_t *pPoolInfo = poolInfo; // IN: Memory layout information
00133   pools_t *pPools = memPools;// OUT: Will be initialized with requested memory pools.
00134   uint8_t *pHeap = memHeap;// IN: Memory heap.
00135   uint8_t poolN;
00136 #ifdef MEM_TRACKING
00137   uint16_t memTrackIndex = 0;  
00138 #endif /*MEM_TRACKING*/
00139 
00140   gFreeMessagesCount = 0;
00141   
00142   for(;;) 
00143   {  
00144     poolN = pPoolInfo->poolSize;
00145     ListInit((listHandle_t)&pPools->anchor, poolN);
00146 #ifdef MEM_STATISTICS
00147     pPools->poolStatistics.numBlocks = 0;
00148     pPools->poolStatistics.allocatedBlocks = 0;
00149     pPools->poolStatistics.allocatedBlocksPeak = 0;
00150     pPools->poolStatistics.allocationFailures = 0;
00151     pPools->poolStatistics.freeFailures = 0;
00152 #ifdef MEM_TRACKING
00153     pPools->poolStatistics.poolFragmentWaste = 0;
00154     pPools->poolStatistics.poolFragmentWastePeak = 0;
00155 #endif /*MEM_TRACKING*/
00156 #endif /*MEM_STATISTICS*/
00157 
00158     while(poolN) 
00159     {
00160       // Add block to list of free memory.
00161       ListAddTail((listHandle_t)&pPools->anchor, (listElementHandle_t)&((listHeader_t *)pHeap)->link);
00162       ((listHeader_t *)pHeap)->pParentPool = pPools;
00163 #ifdef MEM_STATISTICS
00164       pPools->poolStatistics.numBlocks++;
00165 #endif /*MEM_STATISTICS*/
00166 
00167       gFreeMessagesCount++;
00168 #ifdef MEM_TRACKING
00169       memTrack[memTrackIndex].blockAddr = (void *)(pHeap + sizeof(listHeader_t));
00170       memTrack[memTrackIndex].blockSize = pPoolInfo->blockSize;
00171       memTrack[memTrackIndex].fragmentWaste = 0;
00172       memTrack[memTrackIndex].allocAddr = NULL;
00173       memTrack[memTrackIndex].allocCounter = 0;
00174       memTrack[memTrackIndex].allocStatus = MEM_TRACKING_FREE_c;
00175       memTrack[memTrackIndex].freeAddr = NULL;
00176       memTrack[memTrackIndex].freeCounter = 0;
00177       memTrackIndex++;
00178 #endif /*MEM_TRACKING*/
00179   
00180         // Add block size (without list header)
00181       pHeap += pPoolInfo->blockSize + sizeof(listHeader_t);
00182       poolN--;
00183     }
00184 
00185     pPools->blockSize = pPoolInfo->blockSize;
00186     pPools->nextBlockSize = (pPoolInfo+1)->blockSize;
00187     if(pPools->nextBlockSize == 0)
00188     {
00189       break;
00190     }
00191     
00192     pPools++;
00193     pPoolInfo++;
00194   }
00195   return MEM_SUCCESS_c;
00196 }
00197 
00198 /*! *********************************************************************************
00199 * \brief    This function returns the number of available blocks greater or 
00200 *           equal to the given size.
00201 *
00202 * \param[in] size - Size of blocks to check for availability.
00203 *
00204 * \return Number of available blocks greater or equal to the given size.
00205 *
00206 * \pre Memory manager must be previously initialized.
00207 *
00208 ********************************************************************************** */
00209 uint32_t MEM_GetAvailableBlocks
00210   (
00211   uint32_t size
00212   )
00213 {
00214   pools_t *pPools = memPools;
00215   uint32_t pTotalCount = 0;
00216   
00217   for(;;)
00218   {
00219     if(size <= pPools->blockSize)
00220     {
00221       pTotalCount += ListGetSize((listHandle_t)&pPools->anchor);
00222     }
00223     
00224     if(pPools->nextBlockSize == 0)
00225     {
00226       break;
00227     }
00228     
00229     pPools++;
00230   }
00231   
00232   return  pTotalCount;
00233 }
00234 
00235 /*! *********************************************************************************
00236 * \brief     Allocate a block from the memory pools. The function uses the 
00237 *            numBytes argument to look up a pool with adequate block sizes.
00238 * \param[in] numBytes - Size of buffer to allocate.
00239 *
00240 * \return Pointer to the allocated buffer, NULL if failed.
00241 *
00242 * \pre Memory manager must be previously initialized.
00243 *
00244 ********************************************************************************** */
00245 void* MEM_BufferAlloc
00246   (
00247   uint32_t numBytes // IN: Minimum number of bytes to allocate
00248   )
00249 {
00250 #ifdef MEM_TRACKING
00251 
00252   /* Save the Link Register */
00253   volatile uint32_t savedLR;
00254 //  __asm("str  r14, [SP]");
00255   __asm("push {r2}  ");
00256   __asm("push {LR} ");
00257   __asm("pop  {r2} ");
00258   __asm("str  r2, [SP, #4]");
00259   __asm("pop {r2}");
00260 
00261 #endif /*MEM_TRACKING*/
00262   
00263   pools_t *pPools = memPools;
00264   listHeader_t *pBlock;
00265   
00266 #ifdef MEM_TRACKING
00267   uint16_t requestedSize = numBytes;
00268 #endif /*MEM_TRACKING*/
00269 
00270   OSA_EnterCritical(kCriticalDisableInt);
00271 
00272   while(numBytes)
00273   {
00274     if(numBytes <= pPools->blockSize)
00275     {
00276       pBlock = (listHeader_t *)ListRemoveHead((listHandle_t)&pPools->anchor);
00277       
00278       if(NULL != pBlock)
00279       {
00280         pBlock++;
00281         gFreeMessagesCount--;
00282         
00283 #ifdef MEM_STATISTICS
00284         pPools->poolStatistics.allocatedBlocks++;
00285         if ( pPools->poolStatistics.allocatedBlocks > pPools->poolStatistics.allocatedBlocksPeak )
00286         {
00287           pPools->poolStatistics.allocatedBlocksPeak = pPools->poolStatistics.allocatedBlocks;
00288         }
00289         MEM_ASSERT(pPools->poolStatistics.allocatedBlocks <= pPools->poolStatistics.numBlocks);
00290 #endif /*MEM_STATISTICS*/
00291         
00292 #ifdef MEM_TRACKING
00293         MEM_Track(pBlock, MEM_TRACKING_ALLOC_c, savedLR, requestedSize);
00294 #endif /*MEM_TRACKING*/
00295         OSA_ExitCritical(kCriticalDisableInt);
00296         return pBlock;
00297       }
00298       else
00299       {
00300         if(numBytes > pPools->nextBlockSize) break;
00301         // No more blocks of that size, try next size.
00302         numBytes = pPools->nextBlockSize;   
00303       }
00304     }
00305       // Try next pool
00306     if(pPools->nextBlockSize)
00307       pPools++;
00308     else
00309       break;
00310   }
00311 #ifdef MEM_STATISTICS
00312   pPools->poolStatistics.allocationFailures++;
00313 #endif /*MEM_STATISTICS*/ 
00314 
00315 #ifdef MEM_DEBUG
00316   panic( 0, (uint32_t)MEM_BufferAlloc, 0, 0);
00317 #endif
00318 
00319   OSA_ExitCritical(kCriticalDisableInt);
00320   return NULL;
00321 }
00322 
00323 /*! *********************************************************************************
00324 * \brief     Deallocate a memory block by putting it in the corresponding pool 
00325 *            of free blocks. 
00326 *
00327 * \param[in] buffer - Pointer to buffer to deallocate.
00328 *
00329 * \return MEM_SUCCESS_c if deallocation was successful, MEM_FREE_ERROR_c if not.
00330 *
00331 * \pre Memory manager must be previously initialized.
00332 *
00333 * \remarks Never deallocate the same buffer twice.
00334 *
00335 ********************************************************************************** */
00336 memStatus_t  MEM_BufferFree
00337   (
00338   void* buffer // IN: Block of memory to free
00339   )
00340 {
00341 #ifdef MEM_TRACKING
00342 
00343   /* Save the Link Register */
00344   volatile uint32_t savedLR;
00345 //  __asm("str  r14, [SP]");
00346   __asm("push {r1}  ");
00347   __asm("push {LR} ");
00348   __asm("pop  {r1} ");
00349   __asm("str  r1, [SP, #4]");
00350   __asm("pop {r1}");
00351 #endif /*MEM_TRACKING*/
00352 
00353   if(buffer == NULL) 
00354   {
00355     return MEM_FREE_ERROR_c;
00356   }
00357 
00358   OSA_EnterCritical(kCriticalDisableInt);
00359   
00360   listHeader_t *pHeader = (listHeader_t *)buffer-1;
00361   pools_t *pParentPool = (pools_t *)pHeader->pParentPool;
00362 
00363   pools_t *pool = memPools;
00364   for(;;)
00365   {
00366     if (pParentPool == pool)
00367       break;
00368     if(pool->nextBlockSize == 0)
00369     {
00370       /* The parent pool was not found! This means that the memory buffer is corrupt or 
00371         that the MEM_BufferFree() function was called with an invalid parameter */
00372 #ifdef MEM_STATISTICS
00373       pParentPool->poolStatistics.freeFailures++;
00374 #endif /*MEM_STATISTICS*/
00375       OSA_ExitCritical(kCriticalDisableInt);
00376       return MEM_FREE_ERROR_c;
00377     }
00378     pool++;
00379   }
00380 
00381   if( pHeader->link.list != NULL )
00382   {
00383       /* The memory buffer appears to be enqueued in a linked list. 
00384          This list may be the free memory buffers pool, or another list. */
00385 #ifdef MEM_STATISTICS
00386       pParentPool->poolStatistics.freeFailures++;
00387 #endif /*MEM_STATISTICS*/
00388       OSA_ExitCritical(kCriticalDisableInt);
00389       return MEM_FREE_ERROR_c;
00390   }
00391 
00392   gFreeMessagesCount++;
00393 
00394   ListAddTail((listHandle_t)&pParentPool->anchor, (listElementHandle_t)&pHeader->link);
00395 
00396 #ifdef MEM_STATISTICS
00397   MEM_ASSERT(pParentPool->poolStatistics.allocatedBlocks > 0);
00398   pParentPool->poolStatistics.allocatedBlocks--;
00399 #endif /*MEM_STATISTICS*/
00400 
00401 #ifdef MEM_TRACKING
00402   MEM_Track(buffer, MEM_TRACKING_FREE_c, savedLR, 0);
00403 #endif /*MEM_TRACKING*/   
00404   OSA_ExitCritical(kCriticalDisableInt);
00405   return MEM_SUCCESS_c; 
00406 }
00407 
00408 /*! *********************************************************************************
00409 * \brief     Determines the size of a memory block
00410 *
00411 * \param[in] buffer - Pointer to buffer.
00412 *
00413 * \return size of memory block
00414 *
00415 * \pre Memory manager must be previously initialized.
00416 *
00417 ********************************************************************************** */
00418 uint16_t MEM_BufferGetSize
00419 (
00420 void* buffer // IN: Block of memory to free
00421 )
00422 {
00423     if( buffer )
00424     {
00425         return ((pools_t *)((listHeader_t *)buffer-1)->pParentPool)->blockSize;
00426     }
00427     
00428     return 0;
00429 }
00430 
00431 /*! *********************************************************************************
00432 *************************************************************************************
00433 * Private functions
00434 *************************************************************************************
00435 ********************************************************************************** */
00436 /*! *********************************************************************************
00437 * \brief     This function updates the tracking array element corresponding to the given 
00438 *            block.
00439 *
00440 * \param[in] block - Pointer to the block.
00441 * \param[in] alloc - Indicates whether an allocation or free operation was performed
00442 * \param[in] address - Address where MEM_BufferAlloc or MEM_BufferFree was called 
00443 * \param[in] requestedSize - Indicates the requested buffer size  passed to MEM_BufferAlloc.
00444 *                            Has no use if a free operation was performed.
00445 *
00446 * \return Returns TRUE if correct allocation or dealocation was performed, FALSE if a
00447 *         buffer was allocated or freed twice.
00448 *
00449 ********************************************************************************** */
00450 #ifdef MEM_TRACKING
00451 uint8_t MEM_Track(listHeader_t *block, memTrackingStatus_t alloc, uint32_t address, uint16_t requestedSize)        
00452 {
00453   uint16_t i;
00454   blockTracking_t *pTrack = NULL;
00455 #ifdef MEM_STATISTICS
00456   poolStat_t  * poolStatistics = (poolStat_t  *)&((pools_t *)( (listElementHandle_t)(block-1)->pParentPool ))->poolStatistics;
00457 #endif
00458 
00459   for( i=0; i<mTotalNoOfMsgs_c; i++ )
00460   {
00461       if( block == memTrack[i].blockAddr )
00462       {
00463           pTrack = &memTrack[i];
00464           break;
00465       }
00466   }
00467 
00468   if( !pTrack || pTrack->allocStatus == alloc)
00469   {
00470 #ifdef MEM_DEBUG
00471       panic( 0, (uint32_t)MEM_Track, 0, 0);
00472 #endif
00473       return FALSE;
00474   }
00475 
00476   pTrack->allocStatus = alloc; 
00477 
00478   if(alloc == MEM_TRACKING_ALLOC_c)                                          
00479   {
00480     pTrack->fragmentWaste = pTrack->blockSize - requestedSize;
00481     pTrack->allocCounter++;                     
00482     pTrack->allocAddr = (void *)address;
00483 #ifdef MEM_STATISTICS
00484     
00485     poolStatistics->poolFragmentWaste += pTrack->fragmentWaste;
00486     if(poolStatistics->poolFragmentWaste > poolStatistics->poolFragmentWastePeak)
00487       poolStatistics->poolFragmentWastePeak = poolStatistics->poolFragmentWaste;
00488 #endif /*MEM_STATISTICS*/
00489   }
00490   else
00491   {
00492 #ifdef MEM_STATISTICS
00493     poolStatistics->poolFragmentWaste -= pTrack->fragmentWaste;
00494 #endif /*MEM_STATISTICS*/
00495     pTrack->fragmentWaste = 0;
00496     pTrack->freeCounter++;
00497     pTrack->freeAddr = (void *)address;
00498   }
00499 
00500   return TRUE;
00501 }
00502 
00503 /*! *********************************************************************************
00504 * \brief     This function checks for buffer overflow when copying multiple bytes
00505 *
00506 * \param[in] p    - pointer to destination.
00507 * \param[in] size - number of bytes to copy
00508 *
00509 * \return 1 if overflow detected, else 0
00510 *
00511 ********************************************************************************** */
00512 uint8_t MEM_BufferCheck(uint8_t *p, uint32_t size)
00513 {
00514     uint32_t i;
00515 
00516     if( (p < (uint8_t*)memHeap) || (p > ((uint8_t*)memHeap + sizeof(memHeap))) )
00517         return 0;
00518 
00519     for(i=0; i<mTotalNoOfMsgs_c-1; i++)
00520     {
00521         if( p > (uint8_t*)memTrack[i].blockAddr && 
00522             p < (uint8_t*)memTrack[i+1].blockAddr )
00523         {
00524             if( (p+size) > ((uint8_t*)memTrack[i+1].blockAddr - sizeof(listHeader_t)) )
00525             {
00526 #ifdef MEM_DEBUG
00527                 panic(0,0,0,0);
00528 #endif
00529                 return 1;
00530             }
00531 
00532             break;
00533         }
00534     }
00535     return 0;
00536 }
00537 #endif /*MEM_TRACKING*/
00538 
00539 /*! *********************************************************************************
00540 * \brief     Performs a write-read-verify test for every byte in all memory pools.
00541 *
00542 * \return Returns MEM_SUCCESS_c if test was successful, MEM_ALLOC_ERROR_c if a
00543 *         buffer was not allocated successufuly, MEM_FREE_ERROR_c  if a
00544 *         buffer was not freed successufuly or MEM_UNKNOWN_ERROR_c if a verify error,
00545 *         heap overflow or data corruption occurred.
00546 *
00547 ********************************************************************************** */
00548 uint32_t MEM_WriteReadTest(void)
00549 {
00550   uint8_t *data, count = 1;
00551   uint32_t idx1,idx2,idx3;
00552   uint32_t freeMsgs;
00553   
00554   /*memory write test*/
00555   freeMsgs = MEM_GetAvailableBlocks(0);
00556   
00557   for(idx1=0; poolInfo[idx1].blockSize != 0; idx1++)
00558   {
00559     for(idx2=0; idx2 < poolInfo[idx1].poolSize; idx2++)
00560     {
00561       data = (uint8_t *)MEM_BufferAlloc(poolInfo[idx1].blockSize);
00562       
00563       if(data == NULL)
00564       {
00565         return MEM_ALLOC_ERROR_c;
00566       }
00567       
00568       for(idx3=0; idx3 < poolInfo[idx1].blockSize; idx3++)
00569       {
00570         if(data > memHeap + heapSize)
00571         {
00572           return MEM_UNKNOWN_ERROR_c;
00573         }
00574         *data = count & 0xff;
00575         data++;
00576       }
00577       count++;
00578     }
00579   }
00580   
00581   count = 1;
00582   data = memHeap;
00583   /*memory read test*/
00584   for(idx1=0; poolInfo[idx1].blockSize != 0; idx1++)
00585   {
00586     for(idx2=0; idx2 < poolInfo[idx1].poolSize; idx2++)
00587     {
00588       /*New block; jump over list header*/
00589       data = data + sizeof(listHeader_t); 
00590       for(idx3=0; idx3<poolInfo[idx1].blockSize; idx3++)
00591       {
00592         if(*data == count)
00593         {
00594           data++;
00595         }
00596         else
00597         {
00598           return MEM_UNKNOWN_ERROR_c;
00599         }
00600       }
00601       if(MEM_BufferFree( data - poolInfo[idx1].blockSize) != MEM_SUCCESS_c)
00602       {
00603         return MEM_FREE_ERROR_c;
00604       }
00605       count++;
00606     }
00607   }
00608   if(MEM_GetAvailableBlocks(0) != freeMsgs)
00609   {
00610     return MEM_UNKNOWN_ERROR_c;
00611   }
00612 #ifdef MEM_STATISTICS
00613   for(idx1 = 0; poolInfo[idx1].blockSize != 0; idx1++)
00614   {
00615     memPools[idx1].poolStatistics.allocatedBlocksPeak = 0;
00616   }
00617 #endif /*MEM_STATISTICS*/
00618   
00619   return MEM_SUCCESS_c;
00620 }