页表部分注解 , 博客见于 鸿蒙内核源码分析(页表管理)

    百图画鸿蒙 + 百文说内核 + 百万注源码  => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 9281a817
...@@ -169,7 +169,7 @@ extern "C" { ...@@ -169,7 +169,7 @@ extern "C" {
#define MMU_DESCRIPTOR_L2_AP_P_RO_U_NA (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_1) #define MMU_DESCRIPTOR_L2_AP_P_RO_U_NA (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_1)
#define MMU_DESCRIPTOR_L2_AP_MASK (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_3) #define MMU_DESCRIPTOR_L2_AP_MASK (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_3)
#define MMU_DESCRIPTOR_L2_SHAREABLE (1 << 10) #define MMU_DESCRIPTOR_L2_SHAREABLE (1 << 10)
#define MMU_DESCRIPTOR_L2_NON_GLOBAL (1 << 11) #define MMU_DESCRIPTOR_L2_NON_GLOBAL (1 << 11)
#define MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(x) ((x) & MMU_DESCRIPTOR_L2_SMALL_FRAME) #define MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(x) ((x) & MMU_DESCRIPTOR_L2_SMALL_FRAME)
......
...@@ -125,7 +125,7 @@ STATIC INT32 AddEmmcParts(INT32 rootAddr, INT32 rootSize, INT32 userAddr, INT32 ...@@ -125,7 +125,7 @@ STATIC INT32 AddEmmcParts(INT32 rootAddr, INT32 rootSize, INT32 userAddr, INT32
} }
#endif #endif
//增加一个分 //增加一个分
STATIC INT32 AddPartitions(CHAR *dev, UINT64 rootAddr, UINT64 rootSize, UINT64 userAddr, UINT64 userSize) STATIC INT32 AddPartitions(CHAR *dev, UINT64 rootAddr, UINT64 rootSize, UINT64 userAddr, UINT64 userSize)
{ {
#ifdef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 #ifdef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
...@@ -166,14 +166,14 @@ STATIC INT32 AddPartitions(CHAR *dev, UINT64 rootAddr, UINT64 rootSize, UINT64 u ...@@ -166,14 +166,14 @@ STATIC INT32 AddPartitions(CHAR *dev, UINT64 rootAddr, UINT64 rootSize, UINT64 u
return LOS_NOK; return LOS_NOK;
} }
//获取根文件系统参 //获取根文件系统参
STATIC INT32 ParseRootArgs(CHAR **dev, CHAR **fstype, UINT64 *rootAddr, UINT64 *rootSize, UINT32 *mountFlags) STATIC INT32 ParseRootArgs(CHAR **dev, CHAR **fstype, UINT64 *rootAddr, UINT64 *rootSize, UINT32 *mountFlags)
{ {
INT32 ret; INT32 ret;
CHAR *rootAddrStr = NULL; CHAR *rootAddrStr = NULL;
CHAR *rootSizeStr = NULL; CHAR *rootSizeStr = NULL;
CHAR *rwTag = NULL; CHAR *rwTag = NULL;
//获取文件系统放在哪种设备 //获取文件系统放在哪种设备
ret = LOS_GetArgValue("root", dev);//root = flash | mmc | ret = LOS_GetArgValue("root", dev);//root = flash | mmc |
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINT_ERR("Cannot find root!"); PRINT_ERR("Cannot find root!");
...@@ -185,7 +185,7 @@ STATIC INT32 ParseRootArgs(CHAR **dev, CHAR **fstype, UINT64 *rootAddr, UINT64 * ...@@ -185,7 +185,7 @@ STATIC INT32 ParseRootArgs(CHAR **dev, CHAR **fstype, UINT64 *rootAddr, UINT64 *
PRINT_ERR("Cannot find fstype!"); PRINT_ERR("Cannot find fstype!");
return ret; return ret;
} }
//获取内核地址空间开始位 //获取内核地址空间开始位
ret = LOS_GetArgValue("rootaddr", &rootAddrStr); ret = LOS_GetArgValue("rootaddr", &rootAddrStr);
if (ret != LOS_OK) { if (ret != LOS_OK) {
*rootAddr = ROOTFS_ADDR; *rootAddr = ROOTFS_ADDR;
...@@ -345,7 +345,7 @@ INT32 OsMountRootfs() ...@@ -345,7 +345,7 @@ INT32 OsMountRootfs()
UINT64 userAddr; UINT64 userAddr;
UINT64 userSize; UINT64 userSize;
UINT32 mountFlags; UINT32 mountFlags;
//获取根文件系统参? //获取根文件系统参?
ret = ParseRootArgs(&dev, &fstype, &rootAddr, &rootSize, &mountFlags); ret = ParseRootArgs(&dev, &fstype, &rootAddr, &rootSize, &mountFlags);
if (ret != LOS_OK) { if (ret != LOS_OK) {
return ret; return ret;
...@@ -355,7 +355,7 @@ INT32 OsMountRootfs() ...@@ -355,7 +355,7 @@ INT32 OsMountRootfs()
if (ret != LOS_OK) { if (ret != LOS_OK) {
return ret; return ret;
} }
//检查内核和用户空间的有效? //检查内核和用户空间的有效?
ret = CheckValidation(rootAddr, rootSize, userAddr, userSize); ret = CheckValidation(rootAddr, rootSize, userAddr, userSize);
if (ret != LOS_OK) { if (ret != LOS_OK) {
return ret; return ret;
......
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! /*!
* @file los_swtmr.c * @file los_swtmr.c
* @brief 软定时器主文件 * @brief 软定时器主文件
...@@ -93,6 +62,37 @@ ...@@ -93,6 +62,37 @@
@endverbatim @endverbatim
*/ */
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_swtmr_pri.h" #include "los_swtmr_pri.h"
#include "los_init.h" #include "los_init.h"
#include "los_process_pri.h" #include "los_process_pri.h"
...@@ -405,16 +405,15 @@ STATIC UINT32 SwtmrBaseInit(VOID) ...@@ -405,16 +405,15 @@ STATIC UINT32 SwtmrBaseInit(VOID)
return LOS_ERRNO_SWTMR_NO_MEMORY; return LOS_ERRNO_SWTMR_NO_MEMORY;
} }
(VOID)memset_s(swtmr, size, 0, size);//清0 (VOID)memset_s(swtmr, size, 0, size);//清0
g_swtmrCBArray = swtmr;//软时钟 g_swtmrCBArray = swtmr;//软时钟
LOS_ListInit(&g_swtmrFreeList);//初始化空闲链表 LOS_ListInit(&g_swtmrFreeList);//初始化空闲链表
for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) { for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
swtmr->usTimerID = index;//按顺序赋值 swtmr->usTimerID = index;//按顺序赋值
LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表 LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表
} }
//想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请的内存大小,因为需要点前缀内存承载头部信息. //想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请的内存大小,因为需要点前缀内存承载头部信息.
size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE); size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);//规划一片内存区域作为软时钟处理函数的静态内存池。
//规划一片内存区域作为软时钟处理函数的静态内存池。
g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, size); /* system resident resource */ g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, size); /* system resident resource */
if (g_swtmrHandlerPool == NULL) { if (g_swtmrHandlerPool == NULL) {
return LOS_ERRNO_SWTMR_NO_MEMORY; return LOS_ERRNO_SWTMR_NO_MEMORY;
......
...@@ -509,7 +509,7 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsTaskCreateParamCheck(const UINT32 *taskID, ...@@ -509,7 +509,7 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 OsTaskCreateParamCheck(const UINT32 *taskID,
TSK_INIT_PARAM_S *initParam, VOID **pool) TSK_INIT_PARAM_S *initParam, VOID **pool)
{ {
UINT32 poolSize = OS_SYS_MEM_SIZE; UINT32 poolSize = OS_SYS_MEM_SIZE;
*pool = (VOID *)m_aucSysMem1;//默认使用 *pool = (VOID *)m_aucSysMem1;//默认使用 系统动态内存池地址的起始地址
if (taskID == NULL) { if (taskID == NULL) {
return LOS_ERRNO_TSK_ID_INVALID; return LOS_ERRNO_TSK_ID_INVALID;
...@@ -657,7 +657,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S ...@@ -657,7 +657,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S
LosTaskCB *taskCB = NULL; LosTaskCB *taskCB = NULL;
VOID *pool = NULL; VOID *pool = NULL;
errRet = OsTaskCreateParamCheck(taskID, initParam, &pool);//参数检查 errRet = OsTaskCreateParamCheck(taskID, initParam, &pool);//参数检查,获取内存池 *pool = (VOID *)m_aucSysMem1;
if (errRet != LOS_OK) { if (errRet != LOS_OK) {
return errRet; return errRet;
} }
...@@ -719,8 +719,8 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in ...@@ -719,8 +719,8 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in
return LOS_ERRNO_TSK_YIELD_IN_INT; return LOS_ERRNO_TSK_YIELD_IN_INT;
} }
if (OsProcessIsUserMode(OsCurrProcessGet())) { if (OsProcessIsUserMode(OsCurrProcessGet())) { //当前进程为用户进程
initParam->processID = OsGetKernelInitProcessID(); initParam->processID = OsGetKernelInitProcessID();//@note_thinking 为什么进程ID变成了内核态根进程
} else { } else {
initParam->processID = OsCurrProcessGet()->processID; initParam->processID = OsCurrProcessGet()->processID;
} }
......
...@@ -42,7 +42,7 @@ extern "C" { ...@@ -42,7 +42,7 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
typedef struct { typedef struct {
UINT32 memUsed; UINT32 memUsed; ///< 记录任务内存使用量
} TskMemUsedInfo; } TskMemUsedInfo;
extern VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID); extern VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID);
...@@ -53,7 +53,7 @@ extern VOID OsTaskMemClear(UINT32 taskID); ...@@ -53,7 +53,7 @@ extern VOID OsTaskMemClear(UINT32 taskID);
#ifdef LOS_MEM_SLAB #ifdef LOS_MEM_SLAB
typedef struct { typedef struct {
UINT32 slabUsed; UINT32 slabUsed; ///< 任务占用以slab分配方式内存量
} TskSlabUsedInfo; } TskSlabUsedInfo;
extern VOID OsTaskSlabUsedInc(UINT32 usedSize, UINT32 taskID); extern VOID OsTaskSlabUsedInc(UINT32 usedSize, UINT32 taskID);
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
| 包括 IO设备 | | 包括 IO设备 |
| PERIPH_PMM_SIZE | | PERIPH_PMM_SIZE |
+----------------------------+ 外围设备基地址 PERIPH_DEVICE_BASE +----------------------------+ 外围设备基地址 PERIPH_DEVICE_BASE
| Vmalloc | | Vmalloc 空间 |
| kernel heap |内核堆空间 | 内核栈 内核堆 |内核动态分配空间
| 128M | | 128M |
| 映射区 | | 映射区 |
+----------------------------+ 内核动态分配开始地址 VMALLOC_START +----------------------------+ 内核动态分配开始地址 VMALLOC_START
......
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
#include "los_memstat_pri.h" #include "los_memstat_pri.h"
#include "los_task_pri.h" #include "los_task_pri.h"
/// 记录每个任务对内存的使用情况
LITE_OS_SEC_BSS_MINOR STATIC TskMemUsedInfo g_tskMemUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT]; LITE_OS_SEC_BSS_MINOR STATIC TskMemUsedInfo g_tskMemUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT];
/// 计算指定任务对内存使用增加量
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID) LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID)
{ {
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) { if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
...@@ -43,9 +43,9 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID) ...@@ -43,9 +43,9 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedInc(UINT32 usedSize, UINT32 taskID)
if (OS_INT_ACTIVE) { if (OS_INT_ACTIVE) {
return; return;
} }
g_tskMemUsedInfo[taskID].memUsed += usedSize; g_tskMemUsedInfo[taskID].memUsed += usedSize; ///< 叠加
} }
/// 计算指定任务对内存使用减少量
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID) LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID)
{ {
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) { if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
...@@ -59,9 +59,9 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID) ...@@ -59,9 +59,9 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemUsedDec(UINT32 usedSize, UINT32 taskID)
OsCurrTaskGet()->taskName, g_tskMemUsedInfo[taskID].memUsed, usedSize); OsCurrTaskGet()->taskName, g_tskMemUsedInfo[taskID].memUsed, usedSize);
return; return;
} }
g_tskMemUsedInfo[taskID].memUsed -= usedSize; g_tskMemUsedInfo[taskID].memUsed -= usedSize; ///< 递减
} }
/// 获取指定任务对内存的使用情况
LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID) LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID)
{ {
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) { if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
...@@ -70,7 +70,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID) ...@@ -70,7 +70,7 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsTaskMemUsage(UINT32 taskID)
return g_tskMemUsedInfo[taskID].memUsed; return g_tskMemUsedInfo[taskID].memUsed;
} }
/// 清空任务内存使用记录
LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID) LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID)
{ {
if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) { if (taskID >= LOSCFG_BASE_CORE_TSK_LIMIT) {
...@@ -82,8 +82,8 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID) ...@@ -82,8 +82,8 @@ LITE_OS_SEC_TEXT_MINOR VOID OsTaskMemClear(UINT32 taskID)
} }
g_tskMemUsedInfo[taskID].memUsed = 0; g_tskMemUsedInfo[taskID].memUsed = 0;
} }
// Slab是一种内存分配器,通过将内存划分不同大小的空间分配给对象使用来进行缓存管理,应用于内核对象的缓存。
#ifdef LOS_MEM_SLAB #ifdef LOS_MEM_SLAB //
LITE_OS_SEC_BSS_MINOR STATIC TskSlabUsedInfo g_tskSlabUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT]; LITE_OS_SEC_BSS_MINOR STATIC TskSlabUsedInfo g_tskSlabUsedInfo[LOSCFG_BASE_CORE_TSK_LIMIT];
LITE_OS_SEC_TEXT_MINOR VOID OsTaskSlabUsedInc(UINT32 usedSize, UINT32 taskID) LITE_OS_SEC_TEXT_MINOR VOID OsTaskSlabUsedInc(UINT32 usedSize, UINT32 taskID)
......
...@@ -4,251 +4,251 @@ ...@@ -4,251 +4,251 @@
* @link * @link
@verbatim @verbatim
使用场景 使用场景
当用户需要使用固定长度的内存时,可以通过静态内存分配的方式获取内存,一旦使用完毕, 当用户需要使用固定长度的内存时,可以通过静态内存分配的方式获取内存,一旦使用完毕,
通过静态内存释放函数归还所占用内存,使之可以重复使用。 通过静态内存释放函数归还所占用内存,使之可以重复使用。
开发流程 开发流程
通过make menuconfig配置静态内存管理模块。 通过make menuconfig配置静态内存管理模块。
规划一片内存区域作为静态内存池。 规划一片内存区域作为静态内存池。
调用LOS_MemboxInit初始化静态内存池。 调用LOS_MemboxInit初始化静态内存池。
初始化会将入参指定的内存区域分割为N块(N值取决于静态内存总大小和块大小),将所有内存块挂到空闲链表,在内存起始处放置控制头。 初始化会将入参指定的内存区域分割为N块(N值取决于静态内存总大小和块大小),将所有内存块挂到空闲链表,在内存起始处放置控制头。
调用LOS_MemboxAlloc接口分配静态内存。 调用LOS_MemboxAlloc接口分配静态内存。
系统将会从空闲链表中获取第一个空闲块,并返回该内存块的起始地址。 系统将会从空闲链表中获取第一个空闲块,并返回该内存块的起始地址。
调用LOS_MemboxClr接口。将入参地址对应的内存块清零。 调用LOS_MemboxClr接口。将入参地址对应的内存块清零。
调用LOS_MemboxFree接口。将该内存块加入空闲链表。 调用LOS_MemboxFree接口。将该内存块加入空闲链表。
注意事项 注意事项
静态内存池区域,如果是通过动态内存分配方式获得的,在不需要静态内存池时, 静态内存池区域,如果是通过动态内存分配方式获得的,在不需要静态内存池时,
需要释放该段内存,避免发生内存泄露。 需要释放该段内存,避免发生内存泄露。
静态内存不常用,因为需要使用者去确保不会超出使用范围 静态内存不常用,因为需要使用者去确保不会超出使用范围
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2022-04-02 * @date 2022-04-02
*/ */
/* /*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: * are permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* 3. Neither the name of the copyright holder nor the names of its contributors may be used * 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written * to endorse or promote products derived from this software without specific prior written
* permission. * permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "los_membox.h" #include "los_membox.h"
#include "los_hwi.h" #include "los_hwi.h"
#include "los_spinlock.h" #include "los_spinlock.h"
#ifdef LOSCFG_AARCH64 #ifdef LOSCFG_AARCH64
#define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5 //魔法数字,@note_good 点赞,设计的很精巧,node内容从下一个节点地址变成魔法数字 #define OS_MEMBOX_MAGIC 0xa55a5aa5a55a5aa5 //魔法数字,@note_good 点赞,设计的很精巧,node内容从下一个节点地址变成魔法数字
#else #else
#define OS_MEMBOX_MAGIC 0xa55a5aa5 #define OS_MEMBOX_MAGIC 0xa55a5aa5
#endif #endif
#define OS_MEMBOX_SET_MAGIC(addr) \ #define OS_MEMBOX_SET_MAGIC(addr) \
((LOS_MEMBOX_NODE *)(addr))->pstNext = (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC //设置魔法数字 ((LOS_MEMBOX_NODE *)(addr))->pstNext = (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC //设置魔法数字
#define OS_MEMBOX_CHECK_MAGIC(addr) \ #define OS_MEMBOX_CHECK_MAGIC(addr) \
((((LOS_MEMBOX_NODE *)(addr))->pstNext == (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC) ? LOS_OK : LOS_NOK) ((((LOS_MEMBOX_NODE *)(addr))->pstNext == (LOS_MEMBOX_NODE *)OS_MEMBOX_MAGIC) ? LOS_OK : LOS_NOK)
#define OS_MEMBOX_USER_ADDR(addr) \ #define OS_MEMBOX_USER_ADDR(addr) \
((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE)) //@note_good 使用之前要去掉节点信息,太赞了! 很艺术化!! ((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE)) //@note_good 使用之前要去掉节点信息,太赞了! 很艺术化!!
#define OS_MEMBOX_NODE_ADDR(addr) \ #define OS_MEMBOX_NODE_ADDR(addr) \
((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE)) //节块 = (节头 + 节体) addr = 节体 ((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE)) //节块 = (节头 + 节体) addr = 节体
/* spinlock for mem module, only available on SMP mode */ /* spinlock for mem module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_memboxSpin); LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_memboxSpin);
#define MEMBOX_LOCK(state) LOS_SpinLockSave(&g_memboxSpin, &(state)) ///< 获取静态内存池自旋锁 #define MEMBOX_LOCK(state) LOS_SpinLockSave(&g_memboxSpin, &(state)) ///< 获取静态内存池自旋锁
#define MEMBOX_UNLOCK(state) LOS_SpinUnlockRestore(&g_memboxSpin, (state))///< 释放静态内存池自旋锁 #define MEMBOX_UNLOCK(state) LOS_SpinUnlockRestore(&g_memboxSpin, (state))///< 释放静态内存池自旋锁
/// 检查静态内存块 /// 检查静态内存块
STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node) STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node)
{ {
UINT32 offset; UINT32 offset;
if (boxInfo->uwBlkSize == 0) { if (boxInfo->uwBlkSize == 0) {
return LOS_NOK; return LOS_NOK;
} }
offset = (UINT32)((UINTPTR)node - (UINTPTR)(boxInfo + 1)); offset = (UINT32)((UINTPTR)node - (UINTPTR)(boxInfo + 1));
if ((offset % boxInfo->uwBlkSize) != 0) { if ((offset % boxInfo->uwBlkSize) != 0) {
return LOS_NOK; return LOS_NOK;
} }
if ((offset / boxInfo->uwBlkSize) >= boxInfo->uwBlkNum) { if ((offset / boxInfo->uwBlkSize) >= boxInfo->uwBlkNum) {
return LOS_NOK; return LOS_NOK;
} }
return OS_MEMBOX_CHECK_MAGIC(node);//检查魔法数字是否被修改过了 return OS_MEMBOX_CHECK_MAGIC(node);//检查魔法数字是否被修改过了
} }
/// 初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小 /// 初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小
LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize) LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize)
{ {
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;//在内存起始处安置池头 LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;//在内存起始处安置池头
LOS_MEMBOX_NODE *node = NULL; LOS_MEMBOX_NODE *node = NULL;
UINT32 index; UINT32 index;
UINT32 intSave; UINT32 intSave;
if (pool == NULL) { if (pool == NULL) {
return LOS_NOK; return LOS_NOK;
} }
if (blkSize == 0) { if (blkSize == 0) {
return LOS_NOK; return LOS_NOK;
} }
if (poolSize < sizeof(LOS_MEMBOX_INFO)) { if (poolSize < sizeof(LOS_MEMBOX_INFO)) {
return LOS_NOK; return LOS_NOK;
} }
MEMBOX_LOCK(intSave); MEMBOX_LOCK(intSave);
boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE); //节块总大小(节头+节体) boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE); //节块总大小(节头+节体)
boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize;//总节块数量 boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize;//总节块数量
boxInfo->uwBlkCnt = 0; //已分配的数量 boxInfo->uwBlkCnt = 0; //已分配的数量
if (boxInfo->uwBlkNum == 0) {//只有0块的情况 if (boxInfo->uwBlkNum == 0) {//只有0块的情况
MEMBOX_UNLOCK(intSave); MEMBOX_UNLOCK(intSave);
return LOS_NOK; return LOS_NOK;
} }
node = (LOS_MEMBOX_NODE *)(boxInfo + 1);//去除池头,找到第一个节块位置 node = (LOS_MEMBOX_NODE *)(boxInfo + 1);//去除池头,找到第一个节块位置
boxInfo->stFreeList.pstNext = node;//池头空闲链表指向第一个节块 boxInfo->stFreeList.pstNext = node;//池头空闲链表指向第一个节块
for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {//切割节块,挂入空闲链表 for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {//切割节块,挂入空闲链表
node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);//按块大小切割好,统一由pstNext指向 node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);//按块大小切割好,统一由pstNext指向
node = node->pstNext;//node存储了下一个节点的地址信息 node = node->pstNext;//node存储了下一个节点的地址信息
} }
node->pstNext = NULL;//最后一个为null node->pstNext = NULL;//最后一个为null
MEMBOX_UNLOCK(intSave); MEMBOX_UNLOCK(intSave);
return LOS_OK; return LOS_OK;
} }
/// 从指定的静态内存池中申请一块静态内存块,整个内核源码只有 OsSwtmrScan中用到了静态内存. /// 从指定的静态内存池中申请一块静态内存块,整个内核源码只有 OsSwtmrScan中用到了静态内存.
LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool) LITE_OS_SEC_TEXT VOID *LOS_MemboxAlloc(VOID *pool)
{ {
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
LOS_MEMBOX_NODE *node = NULL; LOS_MEMBOX_NODE *node = NULL;
LOS_MEMBOX_NODE *nodeTmp = NULL; LOS_MEMBOX_NODE *nodeTmp = NULL;
UINT32 intSave; UINT32 intSave;
if (pool == NULL) { if (pool == NULL) {
return NULL; return NULL;
} }
MEMBOX_LOCK(intSave); MEMBOX_LOCK(intSave);
node = &(boxInfo->stFreeList);//拿到空闲单链表 node = &(boxInfo->stFreeList);//拿到空闲单链表
if (node->pstNext != NULL) {//不需要遍历链表,因为这是空闲链表 if (node->pstNext != NULL) {//不需要遍历链表,因为这是空闲链表
nodeTmp = node->pstNext;//先记录要使用的节点 nodeTmp = node->pstNext;//先记录要使用的节点
node->pstNext = nodeTmp->pstNext;//不再空闲了,把节点摘出去了. node->pstNext = nodeTmp->pstNext;//不再空闲了,把节点摘出去了.
OS_MEMBOX_SET_MAGIC(nodeTmp);//为已使用的节块设置魔法数字 OS_MEMBOX_SET_MAGIC(nodeTmp);//为已使用的节块设置魔法数字
boxInfo->uwBlkCnt++;//已使用块数增加 boxInfo->uwBlkCnt++;//已使用块数增加
} }
MEMBOX_UNLOCK(intSave); MEMBOX_UNLOCK(intSave);
return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp);//返回可用的虚拟地址 return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp);//返回可用的虚拟地址
} }
/// 释放指定的一块静态内存块 /// 释放指定的一块静态内存块
LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box) LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box)
{ {
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
UINT32 ret = LOS_NOK; UINT32 ret = LOS_NOK;
UINT32 intSave; UINT32 intSave;
if ((pool == NULL) || (box == NULL)) { if ((pool == NULL) || (box == NULL)) {
return LOS_NOK; return LOS_NOK;
} }
MEMBOX_LOCK(intSave); MEMBOX_LOCK(intSave);
do { do {
LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box);//通过节体获取节块首地址 LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box);//通过节体获取节块首地址
if (OsCheckBoxMem(boxInfo, node) != LOS_OK) { if (OsCheckBoxMem(boxInfo, node) != LOS_OK) {
break; break;
} }
node->pstNext = boxInfo->stFreeList.pstNext;//节块指向空闲链表表头 node->pstNext = boxInfo->stFreeList.pstNext;//节块指向空闲链表表头
boxInfo->stFreeList.pstNext = node;//空闲链表表头反指向它,意味节块排到第一,下次申请将首个分配它 boxInfo->stFreeList.pstNext = node;//空闲链表表头反指向它,意味节块排到第一,下次申请将首个分配它
boxInfo->uwBlkCnt--;//已经使用的内存块减一 boxInfo->uwBlkCnt--;//已经使用的内存块减一
ret = LOS_OK; ret = LOS_OK;
} while (0);//将被编译时优化 } while (0);//将被编译时优化
MEMBOX_UNLOCK(intSave); MEMBOX_UNLOCK(intSave);
return ret; return ret;
} }
/// 清零指定静态内存块的内容 /// 清零指定静态内存块的内容
LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box) LITE_OS_SEC_TEXT_MINOR VOID LOS_MemboxClr(VOID *pool, VOID *box)
{ {
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
if ((pool == NULL) || (box == NULL)) { if ((pool == NULL) || (box == NULL)) {
return; return;
} }
//将魔法数字一并清除了. //将魔法数字一并清除了.
(VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0, (VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0,
(boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE)); (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE));
} }
/// 打印指定静态内存池所有节点信息(打印等级是LOS_INFO_LEVEL),包括内存池起始地址、 /// 打印指定静态内存池所有节点信息(打印等级是LOS_INFO_LEVEL),包括内存池起始地址、
/// 内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址 /// 内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址
LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool) LITE_OS_SEC_TEXT_MINOR VOID LOS_ShowBox(VOID *pool)
{ {
UINT32 index; UINT32 index;
UINT32 intSave; UINT32 intSave;
LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
LOS_MEMBOX_NODE *node = NULL; LOS_MEMBOX_NODE *node = NULL;
if (pool == NULL) { if (pool == NULL) {
return; return;
} }
MEMBOX_LOCK(intSave); MEMBOX_LOCK(intSave);
PRINT_INFO("membox(%p,0x%x,0x%x):\r\n", pool, boxInfo->uwBlkSize, boxInfo->uwBlkNum); PRINT_INFO("membox(%p,0x%x,0x%x):\r\n", pool, boxInfo->uwBlkSize, boxInfo->uwBlkNum);
PRINT_INFO("free node list:\r\n"); PRINT_INFO("free node list:\r\n");
for (node = boxInfo->stFreeList.pstNext, index = 0; node != NULL; for (node = boxInfo->stFreeList.pstNext, index = 0; node != NULL;
node = node->pstNext, ++index) { node = node->pstNext, ++index) {
PRINT_INFO("(%u,%p)\r\n", index, node); PRINT_INFO("(%u,%p)\r\n", index, node);
} }
PRINT_INFO("all node list:\r\n"); PRINT_INFO("all node list:\r\n");
node = (LOS_MEMBOX_NODE *)(boxInfo + 1); node = (LOS_MEMBOX_NODE *)(boxInfo + 1);
for (index = 0; index < boxInfo->uwBlkNum; ++index, node = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize)) { for (index = 0; index < boxInfo->uwBlkNum; ++index, node = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize)) {
PRINT_INFO("(%u,%p,%p)\r\n", index, node, node->pstNext); PRINT_INFO("(%u,%p,%p)\r\n", index, node, node->pstNext);
} }
MEMBOX_UNLOCK(intSave); MEMBOX_UNLOCK(intSave);
} }
/// 获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小 /// 获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32 *maxBlk, LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemboxStatisticsGet(const VOID *boxMem, UINT32 *maxBlk,
UINT32 *blkCnt, UINT32 *blkSize) UINT32 *blkCnt, UINT32 *blkSize)
{ {
if ((boxMem == NULL) || (maxBlk == NULL) || (blkCnt == NULL) || (blkSize == NULL)) { if ((boxMem == NULL) || (maxBlk == NULL) || (blkCnt == NULL) || (blkSize == NULL)) {
return LOS_NOK; return LOS_NOK;
} }
*maxBlk = ((OS_MEMBOX_S *)boxMem)->uwBlkNum; *maxBlk = ((OS_MEMBOX_S *)boxMem)->uwBlkNum;
*blkCnt = ((OS_MEMBOX_S *)boxMem)->uwBlkCnt; *blkCnt = ((OS_MEMBOX_S *)boxMem)->uwBlkCnt;
*blkSize = ((OS_MEMBOX_S *)boxMem)->uwBlkSize; *blkSize = ((OS_MEMBOX_S *)boxMem)->uwBlkSize;
return LOS_OK; return LOS_OK;
} }
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
#define OS_MEM_COLUMN_NUM 8 #define OS_MEM_COLUMN_NUM 8
UINT8 *m_aucSysMem0 = NULL; ///< 异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。 UINT8 *m_aucSysMem0 = NULL; ///< 异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
UINT8 *m_aucSysMem1 = NULL; ///< 系统动态内存池地址的起始地址 UINT8 *m_aucSysMem1 = NULL; ///< 系统动态内存池地址的起始地址 @note_thinking 能否不要用 0,1来命名核心变量 ???
#ifdef LOSCFG_MEM_MUL_POOL #ifdef LOSCFG_MEM_MUL_POOL
VOID *g_poolHead = NULL; ///内存池头,由它牵引多个内存池 VOID *g_poolHead = NULL; ///内存池头,由它牵引多个内存池
...@@ -378,14 +378,14 @@ STATIC INLINE struct OsMemNodeHead *PreSentinelNodeGet(const VOID *pool, const s ...@@ -378,14 +378,14 @@ STATIC INLINE struct OsMemNodeHead *PreSentinelNodeGet(const VOID *pool, const s
return NULL; return NULL;
} }
/// 大内存释放
UINT32 OsMemLargeNodeFree(const VOID *ptr) UINT32 OsMemLargeNodeFree(const VOID *ptr)
{ {
LosVmPage *page = OsVmVaddrToPage((VOID *)ptr); LosVmPage *page = OsVmVaddrToPage((VOID *)ptr);//获取物理页
if ((page == NULL) || (page->nPages == 0)) { if ((page == NULL) || (page->nPages == 0)) {
return LOS_NOK; return LOS_NOK;
} }
LOS_PhysPagesFreeContiguous((VOID *)ptr, page->nPages); LOS_PhysPagesFreeContiguous((VOID *)ptr, page->nPages);//释放连续的几个物理页
return LOS_OK; return LOS_OK;
} }
...@@ -2091,7 +2091,7 @@ UINT32 LOS_MemFreeNodeShow(VOID *pool) ...@@ -2091,7 +2091,7 @@ UINT32 LOS_MemFreeNodeShow(VOID *pool)
return LOS_OK; return LOS_OK;
} }
///内核空间动态内存(堆内存)初始化 ///内核空间动态内存(堆内存)初始化 , 争取系统动态内存池
STATUS_T OsKHeapInit(size_t size) STATUS_T OsKHeapInit(size_t size)
{ {
STATUS_T ret; STATUS_T ret;
...@@ -2110,38 +2110,38 @@ STATUS_T OsKHeapInit(size_t size) ...@@ -2110,38 +2110,38 @@ STATUS_T OsKHeapInit(size_t size)
return -1; return -1;
} }
m_aucSysMem0 = m_aucSysMem1 = ptr; m_aucSysMem0 = m_aucSysMem1 = ptr;// 指定内核内存池的位置
ret = LOS_MemInit(m_aucSysMem0, size); //初始化内存池 ret = LOS_MemInit(m_aucSysMem0, size); //初始化内存池,供内核分配动态内存
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINT_ERR("vmm_kheap_init LOS_MemInit failed!\n"); PRINT_ERR("vmm_kheap_init LOS_MemInit failed!\n");
g_vmBootMemBase -= size; g_vmBootMemBase -= size;
return ret; return ret;
} }
#if OS_MEM_EXPAND_ENABLE #if OS_MEM_EXPAND_ENABLE
LOS_MemExpandEnable(OS_SYS_MEM_ADDR); LOS_MemExpandEnable(OS_SYS_MEM_ADDR);//支持扩展系统动态内存
#endif #endif
return LOS_OK; return LOS_OK;
} }
///< 判断地址是否在堆区
BOOL OsMemIsHeapNode(const VOID *ptr) BOOL OsMemIsHeapNode(const VOID *ptr)
{ {
struct OsMemPoolHead *pool = (struct OsMemPoolHead *)m_aucSysMem1; struct OsMemPoolHead *pool = (struct OsMemPoolHead *)m_aucSysMem1;//内核堆区开始地址
struct OsMemNodeHead *firstNode = OS_MEM_FIRST_NODE(pool); struct OsMemNodeHead *firstNode = OS_MEM_FIRST_NODE(pool);//获取内存池首个节点
struct OsMemNodeHead *endNode = OS_MEM_END_NODE(pool, pool->info.totalSize); struct OsMemNodeHead *endNode = OS_MEM_END_NODE(pool, pool->info.totalSize);//获取内存池的尾节点
if (OS_MEM_MIDDLE_ADDR(firstNode, ptr, endNode)) { if (OS_MEM_MIDDLE_ADDR(firstNode, ptr, endNode)) {//如果在首尾范围内
return TRUE; return TRUE;
} }
#if OS_MEM_EXPAND_ENABLE #if OS_MEM_EXPAND_ENABLE//内存池经过扩展后,新旧块的虚拟地址是不连续的,所以需要跳块判断
UINT32 intSave; UINT32 intSave;
UINT32 size; UINT32 size;//详细查看百篇博客系列篇之 鸿蒙内核源码分析(内存池篇)
MEM_LOCK(pool, intSave); MEM_LOCK(pool, intSave); //获取自旋锁
while (OsMemIsLastSentinelNode(endNode) == FALSE) { while (OsMemIsLastSentinelNode(endNode) == FALSE) { //哨兵节点是内存池结束的标记
size = OS_MEM_NODE_GET_SIZE(endNode->sizeAndFlag); size = OS_MEM_NODE_GET_SIZE(endNode->sizeAndFlag);//获取节点大小
firstNode = OsMemSentinelNodeGet(endNode); firstNode = OsMemSentinelNodeGet(endNode);//获取下一块的开始地址
endNode = OS_MEM_END_NODE(firstNode, size); endNode = OS_MEM_END_NODE(firstNode, size);//获取下一块的尾节点
if (OS_MEM_MIDDLE_ADDR(firstNode, ptr, endNode)) { if (OS_MEM_MIDDLE_ADDR(firstNode, ptr, endNode)) {//判断地址是否在该块中
MEM_UNLOCK(pool, intSave); MEM_UNLOCK(pool, intSave);
return TRUE; return TRUE;
} }
......
/*!
* @file los_vm_iomap.c
* @brief DMA
* @link
@verbatim
直接内存访问
直接内存访问(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的
硬件子系统(电脑外设),可以独立地直接读写系统内存,而不需中央处理器(CPU)介入处理
在同等程度的处理器负担下,DMA是一种快速的数据传送方式。很多硬件的系统会使用DMA,包含硬盘控制器、
绘图显卡、网卡和声卡。
DMA是所有现代电脑的重要特色,它允许不同速度的硬件设备来沟通,而不需要依于中央处理器的大量中断负载。
否则,中央处理器需要从来源把每一片段的资料复制到寄存器,然后把它们再次写回到新的地方。在这个时间中,
中央处理器对于其他的工作来说就无法使用。
DMA传输常使用在将一个内存区从一个设备复制到另外一个。当中央处理器初始化这个传输动作,传输动作本身是
由DMA控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作
并没有让处理器工作拖延,使其可以被重新调度去处理其他的工作。DMA传输对于高性能嵌入式系统算法和网络是
很重要的。 举个例子,个人电脑的ISA DMA控制器拥有8个DMA通道,其中的7个通道是可以让计算机的中央处理器所利用。
每一个DMA通道有一个16位地址寄存器和一个16位计数寄存器。要初始化资料传输时,设备驱动程序一起设置DMA通道的
地址和计数寄存器,以及资料传输的方向,读取或写入。然后指示DMA硬件开始这个传输动作。当传输结束的时候,
设备就会以中断的方式通知中央处理器。
"分散-收集"(Scatter-gather)DMA允许在一次单一的DMA处理中传输资料到多个内存区域。相当于把多个简单的DMA要求
串在一起。同样,这样做的目的是要减轻中央处理器的多次输出输入中断和资料复制任务。
DRQ意为DMA要求;DACK意为DMA确认。这些符号一般在有DMA功能的电脑系统硬件概要上可以看到。
它们表示了介于中央处理器和DMA控制器之间的电子信号传输线路。
缓存一致性问题
DMA会导致缓存一致性问题。想像中央处理器带有缓存与外部内存的情况,DMA的运作则是去访问外部内存,
当中央处理器访问外部内存某个地址的时候,暂时先将新的值写入缓存中,但并未将外部内存的资料更新,
若在缓存中的资料尚未更新到外部内存前发生了DMA,则DMA过程将会读取到未更新的资料。
相同的,如果外部设备写入新的值到外部内存内,则中央处理器若访问缓存时则会访问到尚未更新的资料。
这些问题可以用两种方法来解决:
缓存同调系统(Cache-coherent system):以硬件方法来完成,当外部设备写入内存时以一个信号来通知
缓存控制器某内存地址的值已经过期或是应该更新资料。
非同调系统(Non-coherent system):以软件方法来完成,操作系统必须确认缓存读取时,DMA程序已经
开始或是禁止DMA发生。
第二种的方法会造成DMA的系统负担。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2022-04-02
*/
/* /*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
...@@ -36,7 +82,7 @@ ...@@ -36,7 +82,7 @@
#include "los_vm_map.h" #include "los_vm_map.h"
#include "los_memory.h" #include "los_memory.h"
/// 分配DMA空间
VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMemType type) VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMemType type)
{ {
VOID *kVaddr = NULL; VOID *kVaddr = NULL;
...@@ -51,9 +97,9 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe ...@@ -51,9 +97,9 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe
} }
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
kVaddr = LOS_KernelMallocAlign(size, align); kVaddr = LOS_KernelMallocAlign(size, align);//不走内存池方式, 直接申请物理页
#else #else
kVaddr = LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, align); kVaddr = LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, align);//从内存池中申请
#endif #endif
if (kVaddr == NULL) { if (kVaddr == NULL) {
VM_ERR("failed, size = %u, align = %u", size, align); VM_ERR("failed, size = %u, align = %u", size, align);
...@@ -61,16 +107,16 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe ...@@ -61,16 +107,16 @@ VOID *LOS_DmaMemAlloc(DMA_ADDR_T *dmaAddr, size_t size, size_t align, enum DmaMe
} }
if (dmaAddr != NULL) { if (dmaAddr != NULL) {
*dmaAddr = (DMA_ADDR_T)LOS_PaddrQuery(kVaddr); *dmaAddr = (DMA_ADDR_T)LOS_PaddrQuery(kVaddr);//查询物理地址, DMA直接将数据灌到物理地址
} }
if (type == DMA_NOCACHE) { if (type == DMA_NOCACHE) {//无缓存模式 , 计算新的虚拟地址
kVaddr = (VOID *)VMM_TO_UNCACHED_ADDR((UINTPTR)kVaddr); kVaddr = (VOID *)VMM_TO_UNCACHED_ADDR((UINTPTR)kVaddr);
} }
return kVaddr; return kVaddr;
} }
/// 释放 DMA指针
VOID LOS_DmaMemFree(VOID *vaddr) VOID LOS_DmaMemFree(VOID *vaddr)
{ {
UINTPTR addr; UINTPTR addr;
...@@ -79,13 +125,13 @@ VOID LOS_DmaMemFree(VOID *vaddr) ...@@ -79,13 +125,13 @@ VOID LOS_DmaMemFree(VOID *vaddr)
return; return;
} }
addr = (UINTPTR)vaddr; addr = (UINTPTR)vaddr;
// 未缓存区
if ((addr >= UNCACHED_VMM_BASE) && (addr < UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE)) { if ((addr >= UNCACHED_VMM_BASE) && (addr < UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE)) {
addr = UNCACHED_TO_VMM_ADDR(addr); addr = UNCACHED_TO_VMM_ADDR(addr); //转换成未缓存区地址
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
LOS_KernelFree((VOID *)addr); LOS_KernelFree((VOID *)addr);//
#else #else
LOS_MemFree(OS_SYS_MEM_ADDR, (VOID *)addr); LOS_MemFree(OS_SYS_MEM_ADDR, (VOID *)addr);//内存池方式释放
#endif #endif
} else if ((addr >= KERNEL_VMM_BASE) && (addr < KERNEL_VMM_BASE + KERNEL_VMM_SIZE)) { } else if ((addr >= KERNEL_VMM_BASE) && (addr < KERNEL_VMM_BASE + KERNEL_VMM_SIZE)) {
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
...@@ -98,7 +144,7 @@ VOID LOS_DmaMemFree(VOID *vaddr) ...@@ -98,7 +144,7 @@ VOID LOS_DmaMemFree(VOID *vaddr)
} }
return; return;
} }
/// 将DMA虚拟地址转成物理地址
DMA_ADDR_T LOS_DmaVaddrToPaddr(VOID *vaddr) DMA_ADDR_T LOS_DmaVaddrToPaddr(VOID *vaddr)
{ {
return (DMA_ADDR_T)LOS_PaddrQuery(vaddr); return (DMA_ADDR_T)LOS_PaddrQuery(vaddr);
......
...@@ -102,8 +102,8 @@ ...@@ -102,8 +102,8 @@
#define VM_MAP_WASTE_MEM_LEVEL (PAGE_SIZE >> 2) ///< 浪费内存大小(1K) #define VM_MAP_WASTE_MEM_LEVEL (PAGE_SIZE >> 2) ///< 浪费内存大小(1K)
LosMux g_vmSpaceListMux; ///< 用于锁g_vmSpaceList的互斥量 LosMux g_vmSpaceListMux; ///< 用于锁g_vmSpaceList的互斥量
LOS_DL_LIST_HEAD(g_vmSpaceList); ///< 初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上. LOS_DL_LIST_HEAD(g_vmSpaceList); ///< 初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上.
LosVmSpace g_kVmSpace; ///< 内核空间,用于内核运行栈,代码区,数据区 LosVmSpace g_kVmSpace; ///< 内核非分配空间,用于内核运行栈,代码区,数据区
LosVmSpace g_vMallocSpace; ///< 内核空间,用于内核分配内存 LosVmSpace g_vMallocSpace; ///< 内核分配空间,用于内核分配内存
/************************************************************ /************************************************************
* 获取进程空间系列接口 * 获取进程空间系列接口
...@@ -120,8 +120,8 @@ LosVmSpace *LOS_SpaceGet(VADDR_T vaddr) ...@@ -120,8 +120,8 @@ LosVmSpace *LOS_SpaceGet(VADDR_T vaddr)
return LOS_GetKVmSpace(); //获取内核空间 return LOS_GetKVmSpace(); //获取内核空间
} else if (LOS_IsUserAddress(vaddr)) {//是否为用户空间 } else if (LOS_IsUserAddress(vaddr)) {//是否为用户空间
return LOS_CurrSpaceGet(); return LOS_CurrSpaceGet();
} else if (LOS_IsVmallocAddress(vaddr)) {//是否为内核空间 } else if (LOS_IsVmallocAddress(vaddr)) {//是否为内核分配空间
return LOS_GetVmallocSpace();//获取内核空间 return LOS_GetVmallocSpace();//获取内核分配空间
} else { } else {
return NULL; return NULL;
} }
...@@ -246,7 +246,7 @@ BOOL OsVMallocSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//内核动态空 ...@@ -246,7 +246,7 @@ BOOL OsVMallocSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//内核动态空
#endif #endif
return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作 return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作
} }
///内核进程虚拟空间初始化 ///内核虚拟空间初始化
VOID OsKSpaceInit(VOID) VOID OsKSpaceInit(VOID)
{ {
OsVmMapInit();//初始化后续操作 g_vmSpaceList 的互斥锁 OsVmMapInit();//初始化后续操作 g_vmSpaceList 的互斥锁
...@@ -286,22 +286,22 @@ LosVmSpace *OsCreateUserVmSpace(VOID) ...@@ -286,22 +286,22 @@ LosVmSpace *OsCreateUserVmSpace(VOID)
if (space == NULL) { if (space == NULL) {
return NULL; return NULL;
} }
//此处为何直接申请物理页帧存放用户进程的页表,大概是因为所有页表都被存放在内核空间(g_kVmSpace)而非内核分配空间(g_vMallocSpace)
VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);//分配一个物理页用于存放虚实内存映射关系, 即:L1表 VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);//分配一个物理页用于存放虚实映射关系表, 即:L1表
if (ttb == NULL) {//若连映射页都没有,剩下的也别玩了. if (ttb == NULL) {//若连页表都没有,剩下的也别玩了.
(VOID)LOS_MemFree(m_aucSysMem0, space); (VOID)LOS_MemFree(m_aucSysMem0, space);
return NULL; return NULL;
} }
(VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE); (VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);//4K空间置0
retVal = OsUserVmSpaceInit(space, ttb);//初始化用户空间,mmu retVal = OsUserVmSpaceInit(space, ttb);//初始化用户空间,mmu
LosVmPage *vmPage = OsVmVaddrToPage(ttb); LosVmPage *vmPage = OsVmVaddrToPage(ttb);//找到所在物理页框
if ((retVal == FALSE) || (vmPage == NULL)) { if ((retVal == FALSE) || (vmPage == NULL)) {
(VOID)LOS_MemFree(m_aucSysMem0, space); (VOID)LOS_MemFree(m_aucSysMem0, space);
LOS_PhysPagesFreeContiguous(ttb, 1); LOS_PhysPagesFreeContiguous(ttb, 1);
return NULL; return NULL;
} }
LOS_ListAdd(&space->archMmu.ptList, &(vmPage->node)); LOS_ListAdd(&space->archMmu.ptList, &(vmPage->node));//页表链表,先挂上L1,后续还会挂上 N个L2表
return space; return space;
} }
...@@ -1222,7 +1222,7 @@ VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary) ...@@ -1222,7 +1222,7 @@ VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary)
{ {
VOID *ptr = NULL; VOID *ptr = NULL;
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
if (OsMemLargeAlloc(size) && IS_ALIGNED(PAGE_SIZE, boundary)) { if (OsMemLargeAlloc(size) && IS_ALIGNED(PAGE_SIZE, boundary)) {
ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT); ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
} else } else
...@@ -1278,7 +1278,7 @@ VOID LOS_KernelFree(VOID *ptr) ...@@ -1278,7 +1278,7 @@ VOID LOS_KernelFree(VOID *ptr)
{ {
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
UINT32 ret; UINT32 ret;
if (OsMemIsHeapNode(ptr) == FALSE) { if (OsMemIsHeapNode(ptr) == FALSE) {//判断地址是否在堆区
ret = OsMemLargeNodeFree(ptr); ret = OsMemLargeNodeFree(ptr);
if (ret != LOS_OK) { if (ret != LOS_OK) {
VM_ERR("KernelFree %p failed", ptr); VM_ERR("KernelFree %p failed", ptr);
...@@ -1287,7 +1287,7 @@ VOID LOS_KernelFree(VOID *ptr) ...@@ -1287,7 +1287,7 @@ VOID LOS_KernelFree(VOID *ptr)
} else } else
#endif #endif
{ {
(VOID)LOS_MemFree(OS_SYS_MEM_ADDR, ptr); (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, ptr);//从内存池中释放
} }
} }
......
...@@ -337,7 +337,7 @@ extern UINT32 __heap_end; ///< 堆区结束地址 ...@@ -337,7 +337,7 @@ extern UINT32 __heap_end; ///< 堆区结束地址
* Starting address of the system memory * Starting address of the system memory
*/ */
#ifndef OS_SYS_MEM_ADDR #ifndef OS_SYS_MEM_ADDR
#define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统内存起始地址 #define OS_SYS_MEM_ADDR (&m_aucSysMem1[0])//系统内存起始地址(指虚拟地址)
#endif #endif
/** /**
......
...@@ -291,7 +291,7 @@ LITE_OS_SEC_TEXT STATIC int LiteIpcMmap(struct file *filep, LosVmMapRegion *regi ...@@ -291,7 +291,7 @@ LITE_OS_SEC_TEXT STATIC int LiteIpcMmap(struct file *filep, LosVmMapRegion *regi
if (ret) { if (ret) {
goto ERROR_MAP_OUT; goto ERROR_MAP_OUT;
} }
/* ipc pool init */ /* ipc pool init | ipc单独创建了内存池管理*/
if (LOS_MemInit(ipcInfo->pool.kvaddr, region->range.size) != LOS_OK) {//初始化ipc池 if (LOS_MemInit(ipcInfo->pool.kvaddr, region->range.size) != LOS_OK) {//初始化ipc池
ret = -EINVAL; ret = -EINVAL;
goto ERROR_MAP_OUT; goto ERROR_MAP_OUT;
......
git add -A git add -A
git commit -m ' 对静态内存实现注解 git commit -m ' 页表部分注解 , 博客见于 鸿蒙内核源码分析(页表管理)
百图画鸿蒙 + 百文说内核 + 百万注源码 => 挖透鸿蒙内核源码 百图画鸿蒙 + 百文说内核 + 百万注源码 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内) 鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外) | https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册