1 /******************************************************************************/
2 /* src/kernel/MemMng/MemMngArea.c */
4 /* Copyright (C) 2017 Mochi. */
5 /******************************************************************************/
6 /******************************************************************************/
8 /******************************************************************************/
13 #include <kernel/MochiKernel.h>
14 #include <MLib/MLib.h>
15 #include <MLib/Basic/MLibBasic.h>
16 #include <MLib/Basic/MLibBasicList.h>
25 /******************************************************************************/
27 /******************************************************************************/
29 #ifdef DEBUG_LOG_ENABLE
30 #define DEBUG_LOG( ... ) \
31 DebugLogOutput( CMN_MODULE_MEMMNG_AREA, \
35 #define DEBUG_LOG( ... )
39 #define AREA_INFO_NUM ( 1000000 )
42 #define AREA_FREE_ADDR ( 0x100000 )
45 #define AREA_ALIGNMENT ( 0x1000 )
48 #define AREA_INFO_UNUSED ( 0 ) /** メモリ領域情報使用中 */
49 #define AREA_INFO_USED ( 1 ) /** メモリ領域情報未使用 */
53 MLibBasicListNode_t node; /**< 連結リストノード情報 */
54 uint32_t used; /**< 使用フラグ */
55 void *pAddr; /**< 先頭アドレス */
56 size_t size; /**< サイズ */
61 MochiKernelMemoryMap_t *pMemoryMap; /**< メモリマップ */
62 size_t memoryMapSize; /**< メモリマップサイズ */
63 MLibBasicList_t usedList; /**< 使用中メモリ領域リスト */
64 MLibBasicList_t freeList; /**< 未使用メモリ領域リスト */
65 MLibBasicList_t emptyList; /**< 空メモリ領域情報リスト */
66 AreaInfo_t areaInfo[ AREA_INFO_NUM ]; /**< メモリ領域情報 */
70 /******************************************************************************/
72 /******************************************************************************/
74 static AreaTbl_t gAreaTbl;
77 /******************************************************************************/
79 /******************************************************************************/
81 static void *AreaAlloc( AreaInfo_t *pFree );
84 static void *AreaAllocPartially( AreaInfo_t *pFree,
88 static CmnRet_t AreaFree( AreaInfo_t *pFree,
91 /* 指定メモリ領域解放(最後尾挿入) */
92 static CmnRet_t AreaFreeAfterTail( AreaInfo_t *pUsed );
95 static CmnRet_t AreaFreeBefore( AreaInfo_t *pFree,
99 static void AreaInitEmptyList( void );
102 static void AreaInitFreeList( MochiKernelMemoryMap_t *pMap,
106 static void AreaInitUsedList( void );
109 /******************************************************************************/
111 /******************************************************************************/
112 /******************************************************************************/
115 * @details 指定したサイズを満たすメモリ領域を割り当てる。
117 * @param[in] size 割当サイズ
120 * @retval NULL以外 割り当てたメモリ領域の先頭アドレス
122 * @note 割当サイズが4Kバイトアライメントでない場合は、割当サイズが4Kバ
123 * イトアライメントに合うよう加算して、メモリ領域を割り当てる。
125 /******************************************************************************/
126 void *MemMngAreaAlloc( size_t size )
128 void *pAddr; /* 割当メモリ領域先頭アドレス */
129 AreaInfo_t *pFree; /* 未使用メモリ領域情報 */
136 DEBUG_LOG( "%s() start. size=%#x", __func__, size );
143 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
151 size = MLIB_BASIC_ALIGN( size, AREA_ALIGNMENT );
154 /* 割当可能な未使用メモリ領域検索 */
157 pFree = ( AreaInfo_t * )
158 MLibBasicListGetNextNode( &( gAreaTbl.freeList ),
159 ( MLibBasicListNode_t * ) pFree );
162 if ( pFree == NULL ) {
166 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
172 } while ( pFree->size < size );
175 if ( pFree->size == size ) {
178 /* 同サイズの未使用メモリ領域からメモリ割当 */
179 pAddr = AreaAlloc( pFree );
184 /* 超過サイズの未使用メモリ領域からメモリ割当 */
185 pAddr = AreaAllocPartially( pFree, size );
189 DEBUG_LOG( "%s() end. ret=%010p", __func__, pAddr );
195 /******************************************************************************/
198 * @details 指定したメモリアドレスが先頭アドレスのメモリ領域を解放する。
200 * @param[in] *pAddr 先頭アドレス
202 * @retval CMN_SUCCESS 正常終了
203 * @retval CMN_FAILURE 異常終了
205 /******************************************************************************/
206 CmnRet_t MemMngAreaFree( void *pAddr )
208 CmnRet_t ret; /* 関数戻り値 */
209 MLibRet_t retMLib; /* MLib関数戻り値 */
210 AreaInfo_t *pFree; /* 未使用メモリ領域情報 */
211 AreaInfo_t *pInfo; /* 使用中メモリ領域情報 */
215 retMLib = MLIB_FAILURE;
220 DEBUG_LOG( "%s() start. pAddr=%010p", __func__, pAddr );
223 if ( pAddr == NULL ) {
227 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
235 pInfo = ( AreaInfo_t * )
236 MLibBasicListGetPrevNode( &( gAreaTbl.usedList ),
237 ( MLibBasicListNode_t * ) pInfo );
240 if ( pInfo == NULL ) {
244 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
250 } while ( pInfo->pAddr != pAddr );
252 /* 使用中メモリ領域リストから削除 */
253 retMLib = MLibBasicListRemove( &( gAreaTbl.usedList ),
254 ( MLibBasicListNode_t * ) pInfo );
257 if ( retMLib != MLIB_SUCCESS ) {
261 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
268 pFree = ( AreaInfo_t * )
269 MLibBasicListGetNextNode( &( gAreaTbl.freeList ),
270 ( MLibBasicListNode_t * ) pFree );
273 if ( pFree == NULL ) {
276 /* 未使用メモリ領域リストの最後尾に挿入 */
277 ret = AreaFreeAfterTail( pInfo );
279 } else if ( ( pInfo->pAddr + pInfo->size ) < pFree->pAddr ) {
283 ret = AreaFreeBefore( pFree, pInfo );
285 } else if ( ( pFree->pAddr + pFree->size ) < pInfo->pAddr ) {
295 ret = AreaFree( pFree, pInfo );
302 DEBUG_LOG( "%s() end. ret=%d", __func__, ret );
308 /******************************************************************************/
311 * @details メモリ領域管理テーブルを初期化する。
313 * @param[in] *pMap メモリマップ
314 * @param[in] mapSize メモリマップサイズ
316 /******************************************************************************/
317 void MemMngAreaInit( MochiKernelMemoryMap_t *pMap,
321 DEBUG_LOG( "%s() start.", __func__ );
327 AreaInitFreeList( pMap, mapSize );
333 DEBUG_LOG( "%s() end.", __func__ );
339 /******************************************************************************/
341 /******************************************************************************/
342 /******************************************************************************/
345 * @details 指定した未使用メモリ領域を割り当てる。
347 * @param[in] *pFree 未使用メモリ領域情報
350 * @retval NULL以外 割当メモリ領域の先頭アドレス
352 /******************************************************************************/
353 static void *AreaAlloc( AreaInfo_t *pFree )
355 MLibRet_t retMLib; /* MLib関数戻り値 */
358 DEBUG_LOG( "%s() start. pFree=%010p", __func__, pFree );
360 /* 未使用メモリ領域リストから削除 */
361 retMLib = MLibBasicListRemove( &( gAreaTbl.freeList ),
362 ( MLibBasicListNode_t * ) pFree );
365 if ( retMLib != MLIB_SUCCESS ) {
369 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
375 retMLib = MLibBasicListInsertTail( &( gAreaTbl.usedList ),
376 ( MLibBasicListNode_t * ) pFree );
379 if ( retMLib != MLIB_SUCCESS ) {
383 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
389 DEBUG_LOG( "%s() end. ret=%010p", __func__, pFree->pAddr );
396 /******************************************************************************/
398 * @brief 指定メモリ領域割当(一部)
399 * @details 指定した未使用メモリ領域から指定した領域サイズのメモリ領域を割
402 * @param[in] *pFree 未使用メモリ領域情報
403 * @param[in] size 割当てサイズ
406 * @retval NULL以外 割当メモリ領域の先頭アドレス
408 /******************************************************************************/
409 static void *AreaAllocPartially( AreaInfo_t *pFree,
412 MLibRet_t retMLib; /* MLib関数戻り値 */
413 AreaInfo_t *pEmpty; /* 空メモリ領域情報 */
416 retMLib = MLIB_FAILURE;
419 DEBUG_LOG( "%s() start. pFree=%010p, size=%#x", __func__, pFree, size );
421 /* 空メモリ領域情報リストからメモリ領域情報取得 */
422 pEmpty = ( AreaInfo_t * )
423 MLibBasicListRemoveTail( &( gAreaTbl.emptyList ) );
426 if ( pEmpty == NULL ) {
430 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
436 pEmpty->used = AREA_INFO_USED; /* 使用フラグ */
437 pEmpty->pAddr = pFree->pAddr; /* 先頭アドレス */
438 pEmpty->size = size; /* サイズ */
440 /* 空メモリ領域情報を使用中メモリ領域リストに追加 */
441 retMLib = MLibBasicListInsertTail( &( gAreaTbl.usedList ),
442 ( MLibBasicListNode_t * ) pEmpty );
445 if ( retMLib != MLIB_SUCCESS ) {
449 DEBUG_LOG( "%s() end. ret=NULL", __func__ );
455 pFree->pAddr += size; /* 先頭アドレス */
456 pFree->size -= size; /* サイズ */
459 DEBUG_LOG( "%s() end.", __func__ );
462 DEBUG_LOG( "%s() end. ret=%010p", __func__, pEmpty->pAddr );
465 return pEmpty->pAddr;
469 /******************************************************************************/
471 * @brief 指定メモリ領域解放(結合)
472 * @details 指定した使用中メモリ領域を指定した未使用メモリ領域に結合する。
474 * @param[in] *pFree 解放先未使用メモリ領域情報
475 * @param[in] *pUsed 使用中メモリ領域情報
477 * @retval CMN_SUCCESS 正常終了
478 * @retval CMN_FAILURE 異常終了
480 /******************************************************************************/
481 static CmnRet_t AreaFree( AreaInfo_t *pFree,
484 size_t size; /* 未使用メモリ領域サイズ */
485 MLibRet_t retMLib; /* MLib関数戻り値 */
486 AreaInfo_t *pNext; /* 未使用メモリ領域の次のメモリ領域情報 */
490 retMLib = MLIB_FAILURE;
494 DEBUG_LOG( "%s() start. pFree=%010p, pUsed=%010p", __func__, pFree, pUsed );
497 if ( pUsed->pAddr > pFree->pAddr ) {
498 /* 使用中メモリ領域が未使用メモリ領域の前 */
500 /* 未使用メモリ領域先頭アドレス設定 */
501 pFree->pAddr = pUsed->pAddr;
505 pFree->size += pUsed->size;
508 memset( pUsed, 0, sizeof ( AreaInfo_t ) );
510 /* 使用中メモリ領域情報を空メモリ領域情報リストの最後尾に挿入 */
511 retMLib = MLibBasicListInsertTail( &( gAreaTbl.emptyList ),
512 ( MLibBasicListNode_t * ) pUsed );
515 if ( retMLib != MLIB_SUCCESS ) {
521 /* 未使用メモリ領域の次のメモリ領域情報取得 */
522 pNext = ( AreaInfo_t * )
523 MLibBasicListGetNextNode( &( gAreaTbl.freeList ),
524 ( MLibBasicListNode_t * ) pFree );
527 if ( pNext == NULL ) {
531 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_SUCCESS );
537 if ( ( pFree->pAddr + pFree->size ) == pNext->pAddr ) {
540 /* 次メモリ領域情報を未使用メモリ領域リストから削除 */
541 retMLib = MLibBasicListRemove( &( gAreaTbl.freeList ),
542 ( MLibBasicListNode_t * ) pNext );
545 if ( retMLib != MLIB_SUCCESS ) {
552 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
558 pFree->size += pNext->size;
561 memset( pNext, 0, sizeof ( AreaInfo_t ) );
563 /* 次メモリ領域情報を空メモリ領域情報リストの最後尾に挿入 */
564 retMLib = MLibBasicListInsertTail( &( gAreaTbl.emptyList ),
565 ( MLibBasicListNode_t * ) pUsed );
568 if ( retMLib != MLIB_SUCCESS ) {
576 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_SUCCESS );
582 /******************************************************************************/
584 * @brief 指定メモリ領域解放(最後尾挿入)
585 * @details 指定した使用中メモリ領域を未使用メモリ領域リストの最後尾に挿入
588 * @param[in] *pUsed 使用中メモリ領域情報
590 * @retval CMN_SUCCESS 正常終了
591 * @retval CMN_FAILURE 異常終了
593 /******************************************************************************/
594 static CmnRet_t AreaFreeAfterTail( AreaInfo_t *pUsed )
596 MLibRet_t retMLib; /* MLib関数戻り値 */
599 DEBUG_LOG( "%s() start. pUsed=%010p", __func__, pUsed );
602 retMLib = MLibBasicListInsertTail( &( gAreaTbl.freeList ),
603 ( MLibBasicListNode_t * ) pUsed );
606 if ( retMLib != MLIB_SUCCESS ) {
610 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
616 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_SUCCESS );
622 /******************************************************************************/
624 * @brief 指定メモリ領域解放(前挿入)
625 * @details 指定した使用中メモリ領域を指定した未使用メモリ領域の前に挿入す
628 * @param[in] *pFree 未使用メモリ領域情報
629 * @param[in] *pUsed 使用中メモリ領域情報
631 * @retval CMN_SUCCESS 正常終了
632 * @retval CMN_FAILURE 異常終了
634 /******************************************************************************/
635 static CmnRet_t AreaFreeBefore( AreaInfo_t *pFree,
638 MLibRet_t retMLib; /* MLib関数戻り値 */
641 DEBUG_LOG( "%s() start. pFree=%010p, pUsed=%010p", __func__, pFree, pUsed );
643 /* 指定した未使用メモリ領域の前に挿入 */
644 retMLib = MLibBasicListInsertPrev( &( gAreaTbl.freeList ),
645 ( MLibBasicListNode_t * ) pFree,
646 ( MLibBasicListNode_t * ) pUsed );
649 if ( retMLib != MLIB_SUCCESS ) {
653 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_FAILURE );
659 DEBUG_LOG( "%s() end. ret=%d", __func__, CMN_SUCCESS );
665 /******************************************************************************/
667 * @brief 空メモリ領域情報リスト初期化
668 * @details 空メモリ領域情報リストを初期化する。
670 /******************************************************************************/
671 static void AreaInitEmptyList( void )
673 uint32_t index; /* メモリ領域情報リストインデックス */
674 MLibRet_t retMLib; /* MLIB関数戻り値 */
675 MLibBasicListNode_t *pEmpty; /* 空メモリ領域情報ノード */
678 DEBUG_LOG( "%s() start.", __func__ );
681 retMLib = MLibBasicListInit( &( gAreaTbl.emptyList ) );
684 if ( retMLib != MLIB_SUCCESS ) {
688 DEBUG_LOG( "ERROR!!! retMLib=%d", retMLib );
692 memset( gAreaTbl.areaInfo, 0, sizeof ( gAreaTbl.areaInfo ) );
694 for ( index = 0; index < AREA_INFO_NUM; index++ ) {
696 pEmpty = ( MLibBasicListNode_t * ) &( gAreaTbl.areaInfo[ index ] );
699 retMLib = MLibBasicListInsertTail( &( gAreaTbl.emptyList ),
703 if ( retMLib != MLIB_SUCCESS ) {
707 DEBUG_LOG( "ERROR!!! retMLib=%d", retMLib );
713 DEBUG_LOG( "%s() end.", __func__ );
719 /******************************************************************************/
721 * @brief 未使用メモリ領域リスト初期化
722 * @details 未使用メモリ領域リストをメモリマップを基に初期化する。
724 * @param[in] *pMap メモリマップ
725 * @param[in] mapSize メモリマップサイズ
727 * @attention 空メモリ領域情報リストを初期化済みである事。
729 /******************************************************************************/
730 static void AreaInitFreeList( MochiKernelMemoryMap_t *pMap,
733 size_t size; /* メモリ領域サイズ */
734 uint32_t index; /* インデックス */
735 uint32_t addr; /* メモリ領域先頭アドレス */
736 uint32_t delta; /* アライメント差分 */
737 MLibRet_t retMLib; /* MLIB関数戻り値 */
738 AreaInfo_t *pEmpty; /* 空メモリ領域情報 */
739 MochiKernelMemoryMap_t *pEntry; /* メモリマップエントリ */
746 retMLib = MLIB_FAILURE;
751 DEBUG_LOG( "%s() start. pMap=%010p, mapSize=%u", __func__, pMap, mapSize );
754 retMLib = MLibBasicListInit( &( gAreaTbl.freeList ) );
757 if ( retMLib != MLIB_SUCCESS ) {
764 if ( pMap == NULL ) {
772 gAreaTbl.pMemoryMap = pMap;
773 gAreaTbl.memoryMapSize = mapSize;
775 /* メモリマップ全エントリ毎に繰り返し */
776 for ( index = 0; index < gAreaTbl.memoryMapSize; index++ ) {
778 pEntry = &gAreaTbl.pMemoryMap[ index ];
781 if ( pEntry->type != MOCHIKERNEL_MEMORY_TYPE_AVAILABLE ) {
789 addr = ( uint32_t ) pEntry->pAddr; /* 先頭アドレス */
790 delta = addr % AREA_ALIGNMENT; /* 先頭アドレスアライメント差 */
791 size = pEntry->size; /* サイズ */
794 if ( addr < AREA_FREE_ADDR ) {
806 addr += AREA_ALIGNMENT - delta; /* 先頭アドレス */
807 size -= AREA_ALIGNMENT - delta; /* サイズ */
811 delta = size % AREA_ALIGNMENT;
813 /* メモリ領域サイズアライメント判定 */
822 if ( ( size / AREA_ALIGNMENT ) == 0 ) {
829 /* 空メモリ情報領域リストからメモリ領域情報取得 */
830 pEmpty = ( AreaInfo_t * )
831 MLibBasicListRemoveTail( &( gAreaTbl.emptyList ) );
834 if ( pEmpty == NULL ) {
841 pEmpty->used = AREA_INFO_USED; /* 使用フラグ */
842 pEmpty->pAddr = ( void * ) addr; /* 先頭アドレス */
843 pEmpty->size = size; /* サイズ */
845 /* 未使用メモリ領域リストの最後尾に挿入 */
846 retMLib = MLibBasicListInsertTail( &( gAreaTbl.usedList ),
847 ( MLibBasicListNode_t * ) pEmpty );
850 if ( retMLib != MLIB_SUCCESS ) {
858 DEBUG_LOG( "%s() end.", __func__ );
864 /******************************************************************************/
866 * @brief 使用中メモリ領域リスト初期化
867 * @details 使用中メモリ領域リストを初期化する。
869 /******************************************************************************/
870 static void AreaInitUsedList( void )
872 MLibRet_t retMLib; /* MLIB関数戻り値 */
875 DEBUG_LOG( "%s() start.", __func__ );
878 retMLib = MLibBasicListInit( &( gAreaTbl.usedList ) );
881 if ( retMLib != MLIB_SUCCESS ) {
885 DEBUG_LOG( "ERROR!!! retMLib=%d", retMLib );
889 DEBUG_LOG( "%s() end.", __func__ );
895 /******************************************************************************/