diff --git a/arch/arm/arm/src/los_exc.c b/arch/arm/arm/src/los_exc.c index d32f5e880ebdac67e2842d6f1a92bfc7634645e1..54b8f3af09a2f44feae75cbea6573a9fffd66d63 100644 --- a/arch/arm/arm/src/los_exc.c +++ b/arch/arm/arm/src/los_exc.c @@ -96,6 +96,7 @@ extern "C" { 当系统发生异常时,系统打印异常函数的栈帧中保存的寄存器内容,以及父函数、祖父函数的 栈帧中的LR、FP寄存器内容,用户就可以据此追溯函数间的调用关系,定位异常原因。 异常接管对系统运行期间发生的芯片硬件异常进行处理,不同芯片的异常类型存在差异,具体异常类型可以查看芯片手册。 + 异常接管一般的定位步骤如下: 打开编译后生成的镜像反汇编(asm)文件。 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。 diff --git a/arch/arm/include/los_hwi.h b/arch/arm/include/los_hwi.h index b497cec81d9cf88fb332bdb01bdecadc5e965ad0..3b6143e942ee02485dd6e8bdb3378922b4a45845 100644 --- a/arch/arm/include/los_hwi.h +++ b/arch/arm/include/los_hwi.h @@ -95,7 +95,7 @@ extern size_t g_intCount[]; * Value: 0x02000900 * * Solution: Ensure that the interrupt number is valid. - */ + */ //创建或删除中断时,传入了无效中断号 #define OS_ERRNO_HWI_NUM_INVALID LOS_ERRNO_OS_ERROR(LOS_MOD_HWI, 0x00) /** diff --git a/kernel/base/mem/bestfit/los_memory.c b/kernel/base/mem/bestfit/los_memory.c index d5f8c6c5bd49eb21de8b32a25412094eefd749c1..7ae551406e7f7ba1ae39deda2845bce871b8c736 100644 --- a/kernel/base/mem/bestfit/los_memory.c +++ b/kernel/base/mem/bestfit/los_memory.c @@ -52,6 +52,61 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ +/****************************************************************************** +基本概念 + 内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。 + 在系统运行过程中,内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用, + 使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。 + +内存管理分为静态内存管理和动态内存管理,提供内存初始化、分配、释放等功能。 + 动态内存:在动态内存池中分配用户指定大小的内存块。 + 优点:按需分配。 + 缺点:内存池中可能出现碎片。 + + 静态内存:在静态内存池中分配用户初始化时预设(固定)大小的内存块。 + 优点:分配和释放效率高,静态内存池中无碎片。 + 缺点:只能申请到初始化预设大小的内存块,不能按需申请。 + +动态内存运作机制 + 动态内存管理,即在内存资源充足的情况下,根据用户需求,从系统配置的一块比较大的连续内存 + (内存池,也是堆内存)中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。 + 与静态内存相比,动态内存管理的优点是按需分配,缺点是内存池中容易出现碎片。 + LiteOS动态内存支持bestfit(也称为dlink)和bestfit_little两种内存管理算法。 + +使用场景 + 动态内存管理的主要工作是动态分配并管理用户申请到的内存区间。 + 动态内存管理主要用于用户需要使用大小不等的内存块的场景。当用户需要使用内存时, + 可以通过操作系统的动态内存申请函数索取指定大小的内存块,一旦使用完毕, + 通过动态内存释放函数归还所占用内存,使之可以重复使用。 + + 对于bestfit_little算法,只支持宏开关LOSCFG_MEM_MUL_POOL控制的多内存池相关接口和 + 宏开关LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK控制的内存合法性检查接口,不支持其他内存调测功能。 + 通过LOS_MemAllocAlign/LOS_MemMallocAlign申请的内存进行LOS_MemRealloc/LOS_MemMrealloc操作后, + 不能保障新的内存首地址保持对齐。 + 对于bestfit_little算法,不支持对LOS_MemAllocAlign申请的内存进行LOS_MemRealloc操作,否则将返回失败。 + +注意事项 + 由于动态内存管理需要管理控制块数据结构来管理内存,这些数据结构会额外消耗内存, + 故实际用户可使用内存总量小于配置项OS_SYS_MEM_SIZE的大小。 + + 对齐分配内存接口LOS_MemAllocAlign/LOS_MemMallocAlign因为要进行地址对齐,可能会额外 + 消耗部分内存,故存在一些遗失内存,当系统释放该对齐内存时,同时回收由于对齐导致的遗失内存。 + + 重新分配内存接口LOS_MemRealloc/LOS_MemMrealloc如果分配成功,系统会自己判定是否需要 + 释放原来申请的内存,并返回重新分配的内存地址。如果重新分配失败,原来的内存保持不变, + 并返回NULL。禁止使用pPtr = LOS_MemRealloc(pool, pPtr, uwSize), + 即:不能使用原来的旧内存地址pPtr变量来接收返回值。 + + 对同一块内存多次调用LOS_MemFree/LOS_MemMfree时,第一次会返回成功,但对同一块内存多次 + 重复释放会导致非法指针操作,结果不可预知。 + + 由于动态内存管理的内存节点控制块结构体LosMemDynNode中,成员sizeAndFlag的数据类型为UINT32, + 高两位为标志位,余下的30位表示内存结点大小,因此用户初始化内存池的大小不能超过1G,否则会出现不可预知的结果。 + +参考 + https://gitee.com/LiteOS/LiteOS/blob/master/doc/Huawei_LiteOS_Kernel_Developer_Guide_zh.md +******************************************************************************/ + #define NODEDUMPSIZE 64 /* the dump size of current broken node when memcheck error */ #define COLUMN_NUM 8 /* column num of the output info of mem node */ @@ -1503,8 +1558,8 @@ STATIC VOID OsMemIntegrityCheckError(const LosMemDynNode *tmpNode, * Description : memory pool integrity checking * Input : pool --Pointer to memory pool * Return : LOS_OK --memory pool integrate or LOS_NOK--memory pool impaired - */ -LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemIntegrityCheck(const VOID *pool) //内存池完整性检查 + */ //对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 +LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemIntegrityCheck(const VOID *pool) { LosMemDynNode *tmpNode = NULL; LosMemDynNode *preNode = NULL; @@ -1826,7 +1881,7 @@ STATIC UINT32 OsMemInit(VOID *pool, UINT32 size) return LOS_OK; } -//初始化内存池 +//初始化一块指定的动态内存池,大小为size LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pool, UINT32 size) { UINT32 intSave; @@ -1861,7 +1916,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pool, UINT32 size) return LOS_OK; } -#ifdef LOSCFG_MEM_MUL_POOL +#ifdef LOSCFG_MEM_MUL_POOL //删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效 LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemDeInit(VOID *pool) { UINT32 intSave; @@ -1897,7 +1952,8 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemDeInit(VOID *pool) MEM_UNLOCK(intSave); return ret; } - +//打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、 +//最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效 LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemPoolList(VOID) { VOID *nextPool = g_poolHead; @@ -1911,7 +1967,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemPoolList(VOID) return index; } #endif -//动态分配内存 +//从指定动态内存池中申请size长度的内存 LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size) { VOID *ptr = NULL; @@ -1937,7 +1993,7 @@ LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size) return ptr; } - +//从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存 LITE_OS_SEC_TEXT VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { UINT32 useSize; @@ -2025,7 +2081,7 @@ LITE_OS_SEC_TEXT STATIC INLINE UINT32 OsMemBackupCheckAndRetore(VOID *pool, VOID return LOS_OK; } #endif - +//释放已申请的内存 LITE_OS_SEC_TEXT UINT32 LOS_MemFree(VOID *pool, VOID *ptr) { UINT32 ret = LOS_NOK; @@ -2158,7 +2214,7 @@ STATIC VOID *OsMemRealloc(VOID *pool, const VOID *ptr, LosMemDynNode *node, UINT } return tmpPtr; } - +//按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块 LITE_OS_SEC_TEXT_MINOR VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) { UINT32 intSave; @@ -2204,7 +2260,7 @@ OUT_UNLOCK: OUT: return newPtr; } - +//获取指定动态内存池的总使用量大小 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTotalUsedGet(VOID *pool) { LosMemDynNode *tmpNode = NULL; @@ -2244,7 +2300,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTotalUsedGet(VOID *pool) return memUsed; } - +//获取指定内存池已使用的内存块数量 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemUsedBlksGet(VOID *pool) { LosMemDynNode *tmpNode = NULL; @@ -2269,7 +2325,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemUsedBlksGet(VOID *pool) return blkNums; } - +//获取申请了指定内存块的任务ID LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTaskIdGet(VOID *ptr) { LosMemDynNode *tmpNode = NULL; @@ -2307,7 +2363,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTaskIdGet(VOID *ptr) MEM_UNLOCK(intSave); return OS_INVALID; } - +//获取指定内存池的空闲内存块数量 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemFreeBlksGet(VOID *pool) { LosMemDynNode *tmpNode = NULL; @@ -2332,7 +2388,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemFreeBlksGet(VOID *pool) return blkNums; } - +//获取内存池最后一个已使用内存块的结束地址 LITE_OS_SEC_TEXT_MINOR UINTPTR LOS_MemLastUsedGet(VOID *pool) { LosMemPoolInfo *poolInfo = (LosMemPoolInfo *)pool; @@ -2371,7 +2427,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemResetEndNode(VOID *pool, UINTPTR preAddr) OsMemNodeSave(endNode); #endif } - +//获取指定动态内存池的总大小 UINT32 LOS_MemPoolSizeGet(const VOID *pool) { UINT32 count = 0; @@ -2426,7 +2482,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemInfoPrint(VOID *pool) status.uwFreeNodeNum); #endif } - +//获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *poolStatus) { LosMemPoolInfo *poolInfo = (LosMemPoolInfo *)pool; @@ -2500,7 +2556,7 @@ STATIC INLINE VOID OsShowFreeNode(UINT32 index, UINT32 length, const UINT32 *cou count++; } } - +//打印指定内存池的空闲内存块的大小及数量 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemFreeNodeShow(VOID *pool) { LOS_DL_LIST *listNodeHead = NULL; @@ -2612,7 +2668,7 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemUsedNodeShow(VOID *pool) #endif #ifdef LOSCFG_BASE_MEM_NODE_SIZE_CHECK - +//获取指定内存块的总大小和可用大小,仅打开LOSCFG_BASE_MEM_NODE_SIZE_CHECK时有效 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemNodeSizeCheck(VOID *pool, VOID *ptr, UINT32 *totalSize, UINT32 *availSize) { const VOID *head = NULL; @@ -2683,7 +2739,7 @@ LITE_OS_SEC_TEXT_MINOR const VOID *OsMemFindNodeCtrl(const VOID *pool, const VOI } return head; } - +//设置内存检查级别 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemCheckLevelSet(UINT8 checkLevel) { if (checkLevel == LOS_MEM_CHECK_LEVEL_LOW) { @@ -2699,7 +2755,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemCheckLevelSet(UINT8 checkLevel) g_memCheckLevel = checkLevel; return LOS_OK; } - +//获得内存检查级别 LITE_OS_SEC_TEXT_MINOR UINT8 LOS_MemCheckLevelGet(VOID) { return g_memCheckLevel; @@ -2805,7 +2861,7 @@ STATIC INLINE UINT32 OsMemNodeSizeGet(VOID *ptr) return OS_MEM_NODE_GET_SIZE(node->selfNode.sizeAndFlag); } - +//从指定动态内存池分配size长度的内存给指定模块,并纳入模块统计 VOID *LOS_MemMalloc(VOID *pool, UINT32 size, UINT32 moduleID) { UINT32 intSave; @@ -2826,7 +2882,7 @@ VOID *LOS_MemMalloc(VOID *pool, UINT32 size, UINT32 moduleID) } return ptr; } - +//从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存给指定模块,并纳入模块统计 VOID *LOS_MemMallocAlign(VOID *pool, UINT32 size, UINT32 boundary, UINT32 moduleID) { UINT32 intSave; @@ -2847,7 +2903,7 @@ VOID *LOS_MemMallocAlign(VOID *pool, UINT32 size, UINT32 boundary, UINT32 module } return ptr; } - +//释放已经申请的内存块,并纳入模块统计 UINT32 LOS_MemMfree(VOID *pool, VOID *ptr, UINT32 moduleID) { UINT32 intSave; @@ -2880,7 +2936,7 @@ UINT32 LOS_MemMfree(VOID *pool, VOID *ptr, UINT32 moduleID) } return ret; } - +//按size大小重新分配内存块给指定模块,并将原内存块内容拷贝到新内存块,同时纳入模块统计。如果新内存块申请成功,则释放原内存块 VOID *LOS_MemMrealloc(VOID *pool, VOID *ptr, UINT32 size, UINT32 moduleID) { VOID *newPtr = NULL; @@ -2925,7 +2981,7 @@ VOID *LOS_MemMrealloc(VOID *pool, VOID *ptr, UINT32 size, UINT32 moduleID) } return newPtr; } - +//获取指定模块的内存使用量,仅打开LOSCFG_MEM_MUL_MODULE时有效 UINT32 LOS_MemMusedGet(UINT32 moduleID) { if (OsMemModCheck(moduleID) == LOS_NOK) { diff --git a/kernel/base/mem/membox/los_membox.c b/kernel/base/mem/membox/los_membox.c index e3025a117953aac54eea7efac59a2a6b453e0d69..174e78e92103b63739904b9f17a084d305521181 100644 --- a/kernel/base/mem/membox/los_membox.c +++ b/kernel/base/mem/membox/los_membox.c @@ -39,6 +39,27 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ +/****************************************************************************** +使用场景 + 当用户需要使用固定长度的内存时,可以通过静态内存分配的方式获取内存,一旦使用完毕, + 通过静态内存释放函数归还所占用内存,使之可以重复使用。 + +开发流程 + 通过make menuconfig配置静态内存管理模块。 + 规划一片内存区域作为静态内存池。 + 调用LOS_MemboxInit初始化静态内存池。 + 初始化会将入参指定的内存区域分割为N块(N值取决于静态内存总大小和块大小),将所有内存块挂到空闲链表,在内存起始处放置控制头。 + 调用LOS_MemboxAlloc接口分配静态内存。 + 系统将会从空闲链表中获取第一个空闲块,并返回该内存块的起始地址。 + 调用LOS_MemboxClr接口。将入参地址对应的内存块清零。 + 调用LOS_MemboxFree接口。将该内存块加入空闲链表。 + +注意事项 + 静态内存池区域,如果是通过动态内存分配方式获得的,在不需要静态内存池时, + 需要释放该段内存,避免发生内存泄露。 +******************************************************************************/ + + #ifdef LOSCFG_AARCH64 #define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5 #else @@ -77,7 +98,7 @@ STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *n return OS_MEMBOX_CHECK_MAGIC(node); } - +//初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小 LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize) { LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; @@ -125,7 +146,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 return LOS_OK; } - +//从指定的静态内存池中申请一块静态内存块 LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool) { LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; @@ -149,7 +170,7 @@ LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool) return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp); } - +//释放指定的一块静态内存块 LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box) { LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; @@ -176,7 +197,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box) return ret; } - +//清零指定静态内存块的内容 LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box) { LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; @@ -188,7 +209,8 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box) (VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE)); } - +//打印指定静态内存池所有节点信息(打印等级是LOS_INFO_LEVEL),包括内存池起始地址、 +//内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址 LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool) { UINT32 index; @@ -215,7 +237,7 @@ LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool) } MEMBOX_UNLOCK(intSave); } - +//获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32 *maxBlk, UINT32 *blkCnt, UINT32 *blkSize) { diff --git a/kernel/common/los_config.h b/kernel/common/los_config.h index b64b92bfa959ecdf86ef4cbdfc0241e52bfa1af1..c3b179d0c80d06c8658c26921da4bbcd090baeb7 100644 --- a/kernel/common/los_config.h +++ b/kernel/common/los_config.h @@ -322,14 +322,14 @@ extern UINT32 __heap_end; // 堆区结束地址 * Starting address of the system memory */ #ifndef OS_SYS_MEM_ADDR -#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])// 系统内存的起始地址 +#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统动态内存起始地址 #endif /** * @ingroup los_config * Memory size */ -#ifndef OS_SYS_MEM_SIZE +#ifndef OS_SYS_MEM_SIZE //系统动态内存池的大小(DDR自适应配置),以byte为单位,从bss段末尾至系统DDR末尾 #define OS_SYS_MEM_SIZE \ ((OS_SYS_FUNC_ADDR_END) - ((OS_EXC_INTERACTMEM_SIZE + ((UINTPTR)&__bss_end) + (64 - 1)) & ~(64 - 1))) #endif diff --git a/zzz/git/push.sh b/zzz/git/push.sh index 3212496e81ba41bc395d2aa3ce437754e66af11c..31dc8fe9eb186b6a86ec90b7574cd3011238ad34 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m '异常接管是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作 +git commit -m '完善内存模块的注解 搜索 @note_pic 方便理解画的字符图 搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善 搜索 @note_thinking 一点思考和吐槽的地方