提交 1ca98594 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

注解内存模块几个重要结构体

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | 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)
上级 7e7f09da
......@@ -112,7 +112,7 @@ struct VmMapRegion {
VM_OFFSET_T pgOff; /**< region page offset to file | 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。*/
UINT32 regionFlags; /**< region flags: cow, user_wired | 线性区标签*/
UINT32 shmid; /**< shmid about shared region | shmid为共享线性区id,id背后就是共享线性区*/
UINT8 forkFlags; /**< vm space fork flags: COPY, ZERO, | fork的方式*/
UINT8 forkFlags; /**< vm space fork flags: COPY, ZERO, | 线性区标记方式*/
UINT8 regionType; /**< vm region type: ANON, FILE, DEV | 映射类型是匿名,文件,还是设备,所谓匿名可理解为内存映射*/
union {
struct VmRegionFile {//文件映射
......@@ -129,7 +129,7 @@ struct VmMapRegion {
} rd;
} unTypeData;
};
/// 虚拟内存地址空间,每个进程都有一个虚拟内存地址空间
typedef struct VmSpace {
LOS_DL_LIST node; /**< vm space dl list | 节点,通过它挂到全局虚拟空间 g_vmSpaceList 链表上*/
LosRbTree regionRbTree; /**< region red-black tree root | 采用红黑树方式管理本空间各个线性区*/
......
......@@ -43,19 +43,19 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
/*!
* @brief 物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。
伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
* @attention vmPage 中并没有虚拟地址,只有物理地址
\n 关于nPages和order的关系说明,当请求分配为5页时,order是等于3的,因为只有2^3才能满足5页的请求
*/
typedef struct VmPage {
LOS_DL_LIST node; /**< vm object dl list | 虚拟内存节点,通过它挂/摘到全局g_vmPhysSeg[segID]->freeList[order]物理页框链表上*/
LOS_DL_LIST node; /**< vm object dl list | 物理内框节点,通过它挂/摘到全局g_vmPhysSeg[segID]->freeList[order]物理页框链表上*/
PADDR_T physAddr; /**< vm page physical addr | 物理页框起始物理地址,只能用于计算,不会用于操作(读/写数据==)*/
Atomic refCounts; /**< vm page ref count | 被引用次数,共享内存会多次引用*/
Atomic refCounts; /**< vm page ref count | 被引用次数,共享内存会多次引用*/
UINT32 flags; /**< vm page flags | 页标签,同时可以有多个标签(共享/引用/活动/被锁==)*/
UINT8 order; /**< vm page in which order list | 被安置在伙伴算法的几号序列( 2^0,2^1,2^2,...,2^order)*/
UINT8 segID; /**< the segment id of vm page | 所属ID*/
UINT8 segID; /**< the segment id of vm page | 所属物理内存段编号ID*/
UINT16 nPages; /**< the vm page is used for kernel heap | 分配页数,标识从本页开始连续的几页将一块被分配*/
} LosVmPage;
......
......@@ -43,7 +43,7 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
/*!
* @brief
* @verbatim
LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,
......@@ -55,7 +55,7 @@ extern "C" {
#define VM_PHYS_SEG_MAX 32 ///< 最大支持32个段
#ifndef min
#define min(x, y) ((x) < (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#define VM_PAGE_TO_PHYS(page) (page->physAddr) ///< 获取物理页框的物理基地址
......@@ -64,11 +64,11 @@ extern "C" {
#define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1)) ///< 通过物理地址定位到order
struct VmFreeList {
LOS_DL_LIST node; ///< 双循环链表
UINT32 listCnt; ///< 双循环链表节点总数
LOS_DL_LIST node; ///< 双循环链表用于挂空闲物理内框节点,通过 VmPage->node 挂上来
UINT32 listCnt; ///< 空闲物理页总数
};
/**
/*!
* @brief Lru全称是Least Recently Used,即最近最久未使用的意思 针对匿名页和文件页各拆分成一个活跃,一个不活跃的链表。
*/
enum OsLruList {
......@@ -79,29 +79,29 @@ enum OsLruList {
VM_LRU_UNEVICTABLE, ///< 保存的是此zone中所有禁止换出的页的描述符
VM_NR_LRU_LISTS
};
/**
/*!
* @brief 物理段描述符
*/
typedef struct VmPhysSeg {
PADDR_T start; /* The start of physical memory area | 物理内存段的开始地址*/
size_t size; /* The size of physical memory area | 物理内存段的大小*/
LosVmPage *pageBase; /* The first page address of this area | 本段首个物理页框地址*/
SPIN_LOCK_S freeListLock; /* The buddy list spinlock | 伙伴算法自旋锁,用于操作freeList上锁*/
SPIN_LOCK_S freeListLock; /* The buddy list spinlock | 伙伴算法自旋锁,用于操作freeList链表*/
struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list | 伙伴算法的分组,默认分成10组 2^0,2^1,...,2^VM_LIST_ORDER_MAX*/
SPIN_LOCK_S lruLock; ///< 用于置换的自旋锁,用于操作lruList
size_t lruSize[VM_NR_LRU_LISTS]; ///< 5个双循环链表大小,如此方便得到size
LOS_DL_LIST lruList[VM_NR_LRU_LISTS]; ///< 页面置换算法,5个双循环链表头,它们分别描述五中不同类型的链表
} LosVmPhysSeg;
/**
/*!
* @brief 物理区描述,仅用于方案商配置范围使用
*/
struct VmPhysArea {
PADDR_T start;
size_t size;
PADDR_T start; ///< 物理内存区基地址
size_t size; ///< 物理内存总大小
};
extern struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];
extern INT32 g_vmPhysSegNum;
extern struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX]; ///< 物理内存采用段页式管理,先切段后伙伴算法页
extern INT32 g_vmPhysSegNum; ///< 段总数
UINT32 OsVmPagesToOrder(size_t nPages);
struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page);
......
......@@ -44,10 +44,10 @@ extern "C" {
* @file los_vm_zone.h
* @brief
* @verbatim
/@note_pic
鸿蒙虚拟内存全景图 从 0x00000000U 至 0xFFFFFFFFU
鸿蒙源码分析系列篇: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
@note_pic
鸿蒙虚拟内存全景图 从 0x00000000U 至 0xFFFFFFFFU
鸿蒙源码分析系列篇: https://blog.csdn.net/kuangyufei
https://my.oschina.net/u/3751245
+----------------------------+ 0xFFFFFFFFU
| IO设备未缓存 |
......@@ -146,7 +146,7 @@ extern "C" {
#define UNCACHED_VMM_BASE (KERNEL_VMM_BASE + KERNEL_VMM_SIZE) ///< 未缓存虚拟空间基地址,适用于DMA,LCD framebuf,
#define UNCACHED_VMM_SIZE DDR_MEM_SIZE ///<未缓存虚拟空间大小
#define VMALLOC_START (UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE) ///< 动态分配基地址
#define VMALLOC_START (UNCACHED_VMM_BASE + UNCACHED_VMM_SIZE) ///< 堆区基地址
#define VMALLOC_SIZE 0x08000000 ///< 128M
//UART,LCD,摄像头,I2C,中断控制器统称为外部设备
#ifdef LOSCFG_KERNEL_MMU //使用MMU时,只是虚拟地址不一样,但映射的物理设备空间一致.
......
......@@ -443,7 +443,7 @@ STATUS_T OsRegionOverlapCheck(LosVmSpace *space, LosVmMapRegion *region)
VOID OsDumpPte(VADDR_T vaddr)
{
UINT32 l1Index = vaddr >> MMU_DESCRIPTOR_L1_SMALL_SHIFT;
LosVmSpace *space = LOS_SpaceGet(vaddr);
LosVmSpace *space = LOS_SpaceGet(vaddr);//通过虚拟地址获取空间,内核分三个空间 内核进程空间,内核堆空间,用户进程空间
UINT32 ttEntry;
LosVmPage *page = NULL;
PTE_T *l2Table = NULL;
......
......@@ -228,30 +228,30 @@ BOOL OsKernVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//内核空间页
vmSpace->mapBase = KERNEL_VMM_BASE;//内核空间映射区基地址
vmSpace->mapSize = KERNEL_VMM_SIZE;//内核空间映射区大小
#ifdef LOSCFG_DRIVERS_TZDRIVER
vmSpace->codeStart = 0;
vmSpace->codeEnd = 0;
vmSpace->codeStart = 0; //代码区开始地址
vmSpace->codeEnd = 0; //代码区结束地址
#endif
return OsVmSpaceInitCommon(vmSpace, virtTtb);//virtTtb 用于初始化 mmu
}
///初始化内核堆空间
BOOL OsVMallocSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//内核动态空间的页表是动态申请得来,共用 L1表
{
vmSpace->base = VMALLOC_START;//内核堆空间基地址
vmSpace->size = VMALLOC_SIZE;//内核堆空间大小
vmSpace->mapBase = VMALLOC_START;//内核堆空间映射基地址
vmSpace->mapSize = VMALLOC_SIZE;//内核堆空间映射区大小
vmSpace->base = VMALLOC_START; //内核堆空间基地址
vmSpace->size = VMALLOC_SIZE; //内核堆空间大小
vmSpace->mapBase = VMALLOC_START; //内核堆空间映射基地址
vmSpace->mapSize = VMALLOC_SIZE; //内核堆空间映射区大小
#ifdef LOSCFG_DRIVERS_TZDRIVER
vmSpace->codeStart = 0;
vmSpace->codeEnd = 0;
#endif
return OsVmSpaceInitCommon(vmSpace, virtTtb);
return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作
}
///用户虚拟空间初始化
///内核进程虚拟空间初始化
VOID OsKSpaceInit(VOID)
{
OsVmMapInit();
OsKernVmSpaceInit(&g_kVmSpace, OsGFirstTableGet());
OsVMallocSpaceInit(&g_vMallocSpace, OsGFirstTableGet());
OsVmMapInit();//初始化后续操作 g_vmSpaceList 的互斥锁
OsKernVmSpaceInit(&g_kVmSpace, OsGFirstTableGet()); //初始化内核进程虚拟空间
OsVMallocSpaceInit(&g_vMallocSpace, OsGFirstTableGet());//初始化内核动态分配空间
}
/*!
* @brief OsUserVmSpaceInit 用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表
......@@ -270,12 +270,12 @@ BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
vmSpace->mapSize = USER_MAP_SIZE;//用户空间映射大小
vmSpace->heapBase = USER_HEAP_BASE;//用户堆区开始地址,只有用户进程需要设置这里,动态内存的开始地址
vmSpace->heapNow = USER_HEAP_BASE;//堆区最新指向地址,用户堆空间大小可通过系统调用 do_brk()扩展
vmSpace->heap = NULL;
vmSpace->heap = NULL; //用户空间的堆区基地址
#ifdef LOSCFG_DRIVERS_TZDRIVER
vmSpace->codeStart = 0;
vmSpace->codeEnd = 0;
#endif
return OsVmSpaceInitCommon(vmSpace, virtTtb);
return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作
}
/// 创建用户进程空间
LosVmSpace *OsCreateUserVmSpace(VOID)
......
......@@ -19,9 +19,9 @@
即1个页帧;第8组的内存块包含2的8次方个页帧,即256个页帧。相同大小的内存块挂在同一个链表上进行管理。
申请内存
系统申请12KiB内存,即3个页帧时,9个内存块组中索引为3的链表挂着一块大小为8个页帧的内存块满足要求,分配出12KiB内存后还剩余20KiB内存,
5个页帧,将5个页帧分成2的幂次方之和,即4跟1,尝试查找伙伴进行合并。4个页帧的内存块没有伙伴则直接插到索引为2的链表上,
继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为1的链表上,否则不做处理。
系统申请20KiB内存,按一页帧4K算,即5个页帧时,9个内存块组中索引为2的链表挂着一块大小为8个页帧的内存块满足要求,分配出20KiB内存后还剩余12KiB内存,
3个页帧,将3个页帧分成2的幂次方之和,即0跟1,尝试查找伙伴进行合并。2个页帧的内存块没有伙伴则直接插到索引为1的链表上,
继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为0的链表上,否则不做处理。
释放内存
系统释放12KiB内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,
若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,
......@@ -76,8 +76,8 @@
#define ONE_PAGE 1
/* Physical memory area array */
STATIC struct VmPhysArea g_physArea[] = {//这里只有一个区域,即只生成一个段
/* Physical memory area array | 物理内存区数组 */
STATIC struct VmPhysArea g_physArea[] = {///< 这里只有一个区域,即只生成一个段
{
.start = SYS_MEM_BASE, //整个物理内存基地址,#define SYS_MEM_BASE DDR_MEM_ADDR , 0x80000000
.size = SYS_MEM_SIZE_DEFAULT,//整个物理内存总大小 0x07f00000
......@@ -137,7 +137,7 @@ VOID OsVmPhysSegAdd(VOID)
}
}
}
///段区域大小调整
/// 段区域大小调整
VOID OsVmPhysAreaSizeAdjust(size_t size)
{
/*
......@@ -148,7 +148,7 @@ VOID OsVmPhysAreaSizeAdjust(size_t size)
g_physArea[0].size -= size;
}
//获得物理内存的总页数
/// 获得物理内存的总页数
UINT32 OsVmPhysPageNumGet(VOID)
{
UINT32 nPages = 0;
......@@ -160,7 +160,7 @@ UINT32 OsVmPhysPageNumGet(VOID)
return nPages;//返回所有物理内存总页数
}
///初始化空闲链表,分配物理页框使用伙伴算法
/// 初始化空闲链表,分配物理页框使用伙伴算法
STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg)
{
int i;
......@@ -177,7 +177,7 @@ STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg)
}
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
}
///物理段初始化
/// 物理段初始化
VOID OsVmPhysInit(VOID)
{
struct VmPhysSeg *seg = NULL;
......@@ -192,8 +192,7 @@ VOID OsVmPhysInit(VOID)
OsVmPhysLruInit(seg); //初始化LRU置换链表
}
}
///将页框挂入空闲链表,分配物理页框从空闲链表里拿
/// 将页框挂入空闲链表,分配物理页框从空闲链表里拿
STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
{
struct VmPhysSeg *seg = NULL;
......
git add -A
git commit -m ' 对虚拟内存/物理内存模块更详细的注解
git commit -m ' 注解内存模块几个重要结构体
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册