更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_vm_map.c 文件参考

虚拟内存管理 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-virtual.html 更多...

浏览源代码.

函数

 LOS_DL_LIST_HEAD (g_vmSpaceList)
 初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上. 更多...
 
LosVmSpaceLOS_CurrSpaceGet (VOID)
 获取当前进程空间结构体指针 更多...
 
LosVmSpaceLOS_SpaceGet (VADDR_T vaddr)
 获取虚拟地址对应的进程空间结构体指针 更多...
 
LosVmSpaceLOS_GetKVmSpace (VOID)
 内核空间只有g_kVmSpace一个,所有的内核进程都共用一个内核空间 更多...
 
LOS_DL_LISTLOS_GetVmSpaceList (VOID)
 获取进程空间链表指针 g_vmSpaceList中挂的是进程空间 g_kVmSpace, g_vMallocSpace,所有用户进程的空间(独有一个进程空间) 更多...
 
LosVmSpaceLOS_GetVmallocSpace (VOID)
 获取内核堆空间的全局变量 更多...
 
ULONG_T OsRegionRbFreeFn (LosRbNode *pstNode)
 释放挂在红黑树上节点,等于释放了线性区 更多...
 
VOID * OsRegionRbGetKeyFn (LosRbNode *pstNode)
 通过红黑树节点找到对应的线性区 更多...
 
ULONG_T OsRegionRbCmpKeyFn (const VOID *pNodeKeyA, const VOID *pNodeKeyB)
 比较两个红黑树节点 更多...
 
STATIC BOOL OsVmSpaceInitCommon (LosVmSpace *vmSpace, VADDR_T *virtTtb)
 OsVmSpaceInitCommon 初始化进程虚拟空间,必须提供L1表的虚拟内存地址 更多...
 
VOID OsVmMapInit (VOID)
 @note_thinking 这个函数名称和内容不太搭 更多...
 
BOOL OsKernVmSpaceInit (LosVmSpace *vmSpace, VADDR_T *virtTtb)
 初始化内核虚拟空间 更多...
 
BOOL OsVMallocSpaceInit (LosVmSpace *vmSpace, VADDR_T *virtTtb)
 初始化内核堆空间 更多...
 
VOID OsKSpaceInit (VOID)
 内核虚拟空间初始化 更多...
 
BOOL OsUserVmSpaceInit (LosVmSpace *vmSpace, VADDR_T *virtTtb)
 OsUserVmSpaceInit 用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表 初始化用户进程虚拟空间,主要划分数据区,堆区,映射区和创建mmu 更多...
 
LosVmSpaceOsCreateUserVmSpace (VOID)
 创建用户进程空间 更多...
 
STATIC BOOL OsVmSpaceParamCheck (LosVmSpace *vmSpace)
 
STATUS_T LOS_VmSpaceClone (LosVmSpace *oldVmSpace, LosVmSpace *newVmSpace)
 
LosVmMapRegionOsFindRegion (LosRbTree *regionRbTree, VADDR_T vaddr, size_t len)
 通过虚拟(线性)地址查找所属线性区,红黑树 更多...
 
LosVmMapRegionLOS_RegionFind (LosVmSpace *vmSpace, VADDR_T addr)
 查找线性区 根据起始地址在进程空间内查找是否存在 更多...
 
LosVmMapRegionLOS_RegionRangeFind (LosVmSpace *vmSpace, VADDR_T addr, size_t len)
 查找线性区 根据地址区间在进程空间内查找是否存在 更多...
 
VADDR_T OsAllocRange (LosVmSpace *vmSpace, size_t len)
 分配指定长度的线性区 更多...
 
VADDR_T OsAllocSpecificRange (LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags)
 分配指定开始地址和长度的线性区 更多...
 
BOOL LOS_IsRegionFileValid (LosVmMapRegion *region)
 映射类型为文件的线性区是否有效 更多...
 
BOOL OsInsertRegion (LosRbTree *regionRbTree, LosVmMapRegion *region)
 向红黑树中插入线性区 更多...
 
LosVmMapRegionOsCreateRegion (VADDR_T vaddr, size_t len, UINT32 regionFlags, unsigned long offset)
 创建一个线性区 更多...
 
PADDR_T LOS_PaddrQuery (VOID *vaddr)
 通过虚拟地址查询映射的物理地址 更多...
 
LosVmMapRegionLOS_RegionAlloc (LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags, VM_OFFSET_T pgoff)
 
STATIC VOID OsAnonPagesRemove (LosArchMmu *archMmu, VADDR_T vaddr, UINT32 count)
 
STATIC VOID OsDevPagesRemove (LosArchMmu *archMmu, VADDR_T vaddr, UINT32 count)
 
STATIC VOID OsFilePagesRemove (LosVmSpace *space, LosVmMapRegion *region)
 
STATUS_T LOS_RegionFree (LosVmSpace *space, LosVmMapRegion *region)
 释放进程空间指定线性区 更多...
 

变量

LosMux g_vmSpaceListMux
 用于锁g_vmSpaceList的互斥量 更多...
 
LosVmSpace g_kVmSpace
 内核非分配空间,用于内核运行栈,代码区,数据区 更多...
 
LosVmSpace g_vMallocSpace
 内核分配空间,用于内核分配内存 更多...
 

详细描述

虚拟内存管理 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-virtual.html

基本概念
    虚拟内存管理是计算机系统管理内存的一种技术。每个进程都有连续的虚拟地址空间,虚拟地址空间的大小由CPU的位数决定,
    32位的硬件平台可以提供的最大的寻址空间为0-4GiB。整个4GiB空间分成两部分,LiteOS-A内核占据3GiB的高地址空间,
    1GiB的低地址空间留给进程使用。各个进程空间的虚拟地址空间是独立的,代码、数据互不影响。
   
    系统将虚拟内存分割为称为虚拟页的内存块,大小一般为4KiB或64KiB,LiteOS-A内核默认的页的大小是4KiB,
    根据需要可以对MMU(Memory Management Units)进行配置。虚拟内存管理操作的最小单位就是一个页,
    LiteOS-A内核中一个虚拟地址区间region包含地址连续的多个虚拟页,也可只有一个页。同样,物理内存也会按照页大小进行分割,
    分割后的每个内存块称为页帧。虚拟地址空间划分:内核态占高地址3GiB(0x40000000 ~ 0xFFFFFFFF),
    用户态占低地址1GiB(0x01000000 ~ 0x3F000000),具体见下表,详细可以查看或配置los_vm_zone.h。
    
内核态地址规划:
   Zone名称       描述                                                      属性
   ----------------------------------------------------------------------------
   DMA zone     供IO设备的DMA使用。                                            Uncache
   
   Normal zone  加载内核代码段、数据段、堆和栈的地址区间。                                   Cache
   
   high mem zone可以分配连续的虚拟内存,但其所映射的物理内存不一定连续。Cache

用户态地址规划:
  Zone名称        描述                                                      属性
  ----------------------------------------------------------------------------
  代码段           用户态代码段地址区间。                                             Cache
  堆             用户态堆地址区间。                                               Cache
  栈             用户态栈地址区间。                                               Cache
  共享库           用于加载用户态共享库的地址区间,包括mmap所映射的区间。                           Cache

运行机制
   虚拟内存管理中,虚拟地址空间是连续的,但是其映射的物理内存并不一定是连续的,如下图所示。
   可执行程序加载运行,CPU访问虚拟地址空间的代码或数据时存在两种情况:
   
   1. CPU访问的虚拟地址所在的页,如V0,已经与具体的物理页P0做映射,CPU通过找到进程对应的页表条目(详见虚实映射),
   根据页表条目中的物理地址信息访问物理内存中的内容并返回。
   2. CPU访问的虚拟地址所在的页,如V2,没有与具体的物理页做映射,系统会触发缺页异常,系统申请一个物理页,
   并把相应的信息拷贝到物理页中,并且把物理页的起始地址更新到页表条目中。此时CPU重新执行访问虚拟内存的指令
   便能够访问到具体的代码或数据。
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-25

在文件 los_vm_map.c 中定义.

函数说明

◆ LOS_CurrSpaceGet()

LosVmSpace * LOS_CurrSpaceGet ( VOID  )

获取当前进程空间结构体指针

在文件 los_vm_map.c112 行定义.

113{
114 return OsCurrProcessGet()->vmSpace;
115}
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
LosVmSpace * vmSpace
函数调用图:
这是这个函数的调用关系图:

◆ LOS_DL_LIST_HEAD()

LOS_DL_LIST_HEAD ( g_vmSpaceList  )

初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上.

这是这个函数的调用关系图:

◆ LOS_GetKVmSpace()

LosVmSpace * LOS_GetKVmSpace ( VOID  )

内核空间只有g_kVmSpace一个,所有的内核进程都共用一个内核空间

在文件 los_vm_map.c130 行定义.

131{
132 return &g_kVmSpace;
133}
LosVmSpace g_kVmSpace
内核非分配空间,用于内核运行栈,代码区,数据区
Definition: los_vm_map.c:105
这是这个函数的调用关系图:

◆ LOS_GetVmallocSpace()

LosVmSpace * LOS_GetVmallocSpace ( VOID  )

获取内核堆空间的全局变量

在文件 los_vm_map.c140 行定义.

141{
142 return &g_vMallocSpace;
143}
LosVmSpace g_vMallocSpace
内核分配空间,用于内核分配内存
Definition: los_vm_map.c:106
这是这个函数的调用关系图:

◆ LOS_GetVmSpaceList()

LOS_DL_LIST * LOS_GetVmSpaceList ( VOID  )

获取进程空间链表指针 g_vmSpaceList中挂的是进程空间 g_kVmSpace, g_vMallocSpace,所有用户进程的空间(独有一个进程空间)

在文件 los_vm_map.c135 行定义.

136{
137 return &g_vmSpaceList;
138}
这是这个函数的调用关系图:

◆ LOS_IsRegionFileValid()

BOOL LOS_IsRegionFileValid ( LosVmMapRegion region)

映射类型为文件的线性区是否有效

在文件 los_vm_map.c512 行定义.

513{
514 if ((region != NULL) && (LOS_IsRegionTypeFile(region)) &&
515 (region->unTypeData.rf.vnode != NULL)) {
516 return TRUE;
517 }
518 return FALSE;
519}
STATIC INLINE BOOL LOS_IsRegionTypeFile(LosVmMapRegion *region)
是否为文件映射区
Definition: los_vm_map.h:234
struct VmMapRegion::@4::VmRegionFile rf
union VmMapRegion::@4 unTypeData
函数调用图:
这是这个函数的调用关系图:

◆ LOS_PaddrQuery()

PADDR_T LOS_PaddrQuery ( VOID *  vaddr)

通过虚拟地址查询映射的物理地址

在文件 los_vm_map.c550 行定义.

551{
552 PADDR_T paddr = 0;
553 STATUS_T status;
554 LosVmSpace *space = NULL;
555 LosArchMmu *archMmu = NULL;
556 //先取出对应空间的mmu
557 if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)vaddr)) {//是否内核空间地址
558 archMmu = &g_kVmSpace.archMmu;
559 } else if (LOS_IsUserAddress((VADDR_T)(UINTPTR)vaddr)) {//是否为用户空间地址
560 space = OsCurrProcessGet()->vmSpace;
561 archMmu = &space->archMmu;
562 } else if (LOS_IsVmallocAddress((VADDR_T)(UINTPTR)vaddr)) {//是否为分配空间地址,堆区地址
563 archMmu = &g_vMallocSpace.archMmu;
564 } else {
565 VM_ERR("vaddr is beyond range");
566 return 0;
567 }
568
569 status = LOS_ArchMmuQuery(archMmu, (VADDR_T)(UINTPTR)vaddr, &paddr, 0);//查询物理地址
570 if (status == LOS_OK) {
571 return paddr;
572 } else {
573 return 0;
574 }
575}
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
Definition: los_arch_mmu.c:569
unsigned long PADDR_T
Definition: los_typedef.h:207
unsigned long VADDR_T
Definition: los_typedef.h:208
int STATUS_T
Definition: los_typedef.h:215
unsigned long UINTPTR
Definition: los_typedef.h:68
STATIC INLINE BOOL LOS_IsKernelAddress(VADDR_T vaddr)
虚拟地址是否在内核空间
Definition: los_vm_map.h:213
STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr)
Definition: los_vm_map.h:287
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
虚拟地址是否在用户空间
Definition: los_vm_map.h:275
内存管理单元(英语:memory management unit,缩写为MMU),有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。
Definition: los_arch_mmu.h:86
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosArchMmu archMmu
Definition: los_vm_map.h:157
函数调用图:
这是这个函数的调用关系图:

◆ LOS_RegionAlloc()

LosVmMapRegion * LOS_RegionAlloc ( LosVmSpace vmSpace,
VADDR_T  vaddr,
size_t  len,
UINT32  regionFlags,
VM_OFFSET_T  pgoff 
)

这里不是真的分配物理内存,而是逻辑上画一个连续的区域,标记这个区域可以拿用,表示内存已经归你了。 但真正的物理内存的占用会延迟到使用的时候才由缺页中断调入内存

If addr is NULL, then the kernel chooses the address at which to create the mapping; this is the most portable method of creating a new mapping. If addr is not NULL, then the kernel takes it as where to place the mapping;

在文件 los_vm_map.c581 行定义.

582{
583 VADDR_T rstVaddr;
584 LosVmMapRegion *newRegion = NULL;
585 BOOL isInsertSucceed = FALSE;
586 /**
587 * If addr is NULL, then the kernel chooses the address at which to create the mapping;
588 * this is the most portable method of creating a new mapping. If addr is not NULL,
589 * then the kernel takes it as where to place the mapping;
590 */
591 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);//获得互斥锁
592 if (vaddr == 0) {//如果地址是0,根据线性区管理的实际情况,自动创建虚拟地址, 这是创建新映射的最便捷的方法。
593 rstVaddr = OsAllocRange(vmSpace, len);
594 } else {
595 /* if it is already mmapped here, we unmmap it | 如果已经被映射了, 则解除映射关系*/
596 rstVaddr = OsAllocSpecificRange(vmSpace, vaddr, len, regionFlags);//创建包含指定虚拟地址的线性区, rstVaddr != vaddr || rstVaddr == vaddr
597 if (rstVaddr == 0) {
598 VM_ERR("alloc specific range va: %#x, len: %#x failed", vaddr, len);
599 goto OUT;
600 }
601 }
602 if (rstVaddr == 0) {//没有可供映射的虚拟地址
603 goto OUT;
604 }
605
606 newRegion = OsCreateRegion(rstVaddr, len, regionFlags, pgoff);//创建一个线性区,指定线性区的开始地址rstVaddr ...
607 if (newRegion == NULL) {
608 goto OUT;
609 }
610 newRegion->space = vmSpace;
611 isInsertSucceed = OsInsertRegion(&vmSpace->regionRbTree, newRegion);//插入红黑树和双循环链表中管理
612 if (isInsertSucceed == FALSE) {//插入失败
613 (VOID)LOS_MemFree(m_aucSysMem0, newRegion);//从内存池中释放
614 newRegion = NULL;
615 }
616
617OUT:
618 (VOID)LOS_MuxRelease(&vmSpace->regionMux);//释放互斥锁
619 return newRegion;
620}
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
size_t BOOL
Definition: los_typedef.h:88
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
LosVmMapRegion * OsCreateRegion(VADDR_T vaddr, size_t len, UINT32 regionFlags, unsigned long offset)
创建一个线性区
Definition: los_vm_map.c:531
VADDR_T OsAllocRange(LosVmSpace *vmSpace, size_t len)
分配指定长度的线性区
Definition: los_vm_map.c:436
VADDR_T OsAllocSpecificRange(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags)
分配指定开始地址和长度的线性区
Definition: los_vm_map.c:485
BOOL OsInsertRegion(LosRbTree *regionRbTree, LosVmMapRegion *region)
向红黑树中插入线性区
Definition: los_vm_map.c:521
LosVmSpace * space
所属虚拟空间,虚拟空间由多个线性区组成
Definition: los_vm_map.h:121
LosRbTree regionRbTree
Definition: los_vm_map.h:148
LosMux regionMux
Definition: los_vm_map.h:149
函数调用图:
这是这个函数的调用关系图:

◆ LOS_RegionFind()

LosVmMapRegion * LOS_RegionFind ( LosVmSpace vmSpace,
VADDR_T  addr 
)

查找线性区 根据起始地址在进程空间内查找是否存在

在文件 los_vm_map.c414 行定义.

415{
416 LosVmMapRegion *region = NULL;
417
418 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);//因进程空间是隔离的,所以此处只会涉及到任务(线程)之间的竞争,故使用互斥锁,而自旋锁则用于CPU核间的竞争
419 region = OsFindRegion(&vmSpace->regionRbTree, addr, 1);
420 (VOID)LOS_MuxRelease(&vmSpace->regionMux);
421
422 return region;
423}
LosVmMapRegion * OsFindRegion(LosRbTree *regionRbTree, VADDR_T vaddr, size_t len)
通过虚拟(线性)地址查找所属线性区,红黑树
Definition: los_vm_map.c:400
函数调用图:
这是这个函数的调用关系图:

◆ LOS_RegionFree()

STATUS_T LOS_RegionFree ( LosVmSpace space,
LosVmMapRegion region 
)

释放进程空间指定线性区

复制线性区

劈开线性区

对线性区进行调整

删除线性区

根据指定参数范围[addr,addr+len] 释放用户空间中堆区所占用的物理内存

线性区是否支持扩展

解除一定范围的虚拟地址的映射关系

释放所有线性区

释放虚拟空间

释放虚拟空间,注意内核空间不能被释放掉,永驻内存

虚拟地址和size是否在空间

在进程空间中预留一块内存空间

实现从虚拟地址到物理地址的映射,将指定长度的物理地址区间与虚拟地址区间做映射,需提前申请物理地址区间

对外接口|释放内核堆空间内存

内核空间内存分配,申请小于16KiB的内存则通过堆内存池获取,否则申请多个连续物理页

申请具有对齐属性的内存,申请规则:申请小于16KiB的内存则通过堆内存池获取,否则申请多个连续物理页

重新分配内核内存空间

在文件 los_vm_map.c694 行定义.

这是这个函数的调用关系图:

◆ LOS_RegionRangeFind()

LosVmMapRegion * LOS_RegionRangeFind ( LosVmSpace vmSpace,
VADDR_T  addr,
size_t  len 
)

查找线性区 根据地址区间在进程空间内查找是否存在

在文件 los_vm_map.c425 行定义.

426{
427 LosVmMapRegion *region = NULL;
428
429 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);
430 region = OsFindRegion(&vmSpace->regionRbTree, addr, len);
431 (VOID)LOS_MuxRelease(&vmSpace->regionMux);
432
433 return region;
434}
函数调用图:
这是这个函数的调用关系图:

◆ LOS_SpaceGet()

LosVmSpace * LOS_SpaceGet ( VADDR_T  vaddr)

获取虚拟地址对应的进程空间结构体指针

在文件 los_vm_map.c117 行定义.

118{
119 if (LOS_IsKernelAddress(vaddr)) { //是否为内核空间
120 return LOS_GetKVmSpace(); //获取内核空间
121 } else if (LOS_IsUserAddress(vaddr)) {//是否为用户空间
122 return LOS_CurrSpaceGet();
123 } else if (LOS_IsVmallocAddress(vaddr)) {//是否为内核分配空间
124 return LOS_GetVmallocSpace();//获取内核分配空间
125 } else {
126 return NULL;
127 }
128}
LosVmSpace * LOS_CurrSpaceGet(VOID)
获取当前进程空间结构体指针
Definition: los_vm_map.c:112
LosVmSpace * LOS_GetVmallocSpace(VOID)
获取内核堆空间的全局变量
Definition: los_vm_map.c:140
LosVmSpace * LOS_GetKVmSpace(VOID)
内核空间只有g_kVmSpace一个,所有的内核进程都共用一个内核空间
Definition: los_vm_map.c:130
函数调用图:
这是这个函数的调用关系图:

◆ LOS_VmSpaceClone()

STATUS_T LOS_VmSpaceClone ( LosVmSpace oldVmSpace,
LosVmSpace newVmSpace 
)

在文件 los_vm_map.c318 行定义.

319{
320 LosVmMapRegion *oldRegion = NULL;
321 LosVmMapRegion *newRegion = NULL;
322 LosRbNode *pstRbNode = NULL;
323 LosRbNode *pstRbNodeNext = NULL;
324 STATUS_T ret = LOS_OK;
325 UINT32 numPages;
326 PADDR_T paddr;
327 VADDR_T vaddr;
328 UINT32 intSave;
329 LosVmPage *page = NULL;
330 UINT32 flags;
331 UINT32 i;
332
333 if ((OsVmSpaceParamCheck(oldVmSpace) == FALSE) || (OsVmSpaceParamCheck(newVmSpace) == FALSE)) {
334 return LOS_ERRNO_VM_INVALID_ARGS;
335 }
336
337 if ((OsIsVmRegionEmpty(oldVmSpace) == TRUE) || (oldVmSpace == &g_kVmSpace)) {//不允许clone内核空间,内核空间是独一无二的.
338 return LOS_ERRNO_VM_INVALID_ARGS;
339 }
340 //空间克隆的主体实现是:线性区重新一个个分配物理内存,重新映射.
341 /* search the region list */
342 newVmSpace->mapBase = oldVmSpace->mapBase; //复制映射区基址
343 newVmSpace->heapBase = oldVmSpace->heapBase; //复制堆区基址
344 newVmSpace->heapNow = oldVmSpace->heapNow; //复制堆区当前使用到哪了
345 (VOID)LOS_MuxAcquire(&oldVmSpace->regionMux);
346 RB_SCAN_SAFE(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)//红黑树循环开始
347 oldRegion = (LosVmMapRegion *)pstRbNode;
348 newRegion = OsVmRegionDup(newVmSpace, oldRegion, oldRegion->range.base, oldRegion->range.size);//复制线性区
349 if (newRegion == NULL) {
350 VM_ERR("dup new region failed");
351 ret = LOS_ERRNO_VM_NO_MEMORY;
352 break;
353 }
354
355#ifdef LOSCFG_KERNEL_SHM
356 if (oldRegion->regionFlags & VM_MAP_REGION_FLAG_SHM) {//如果老线性区是共享内存
357 OsShmFork(newVmSpace, oldRegion, newRegion);//fork共享线性区,如此新虚拟空间也能用那个线性区
358 continue;//不往下走了,因为共享内存不需要重新映射,下面无非就是需要MMU映射虚拟地址<-->物理地址
359 }
360#endif
361
362 if (oldRegion == oldVmSpace->heap) {//如果这个线性区是堆区
363 newVmSpace->heap = newRegion;//那么新的线性区也是新虚拟空间的堆区
364 }
365
366 numPages = newRegion->range.size >> PAGE_SHIFT;//计算线性区页数
367 for (i = 0; i < numPages; i++) {//一页一页进行重新映射
368 vaddr = newRegion->range.base + (i << PAGE_SHIFT);
369 if (LOS_ArchMmuQuery(&oldVmSpace->archMmu, vaddr, &paddr, &flags) != LOS_OK) {//先查物理地址
370 continue;
371 }
372
373 page = LOS_VmPageGet(paddr);//通过物理页获取物理内存的页框
374 if (page != NULL) {
375 LOS_AtomicInc(&page->refCounts);//refCounts 自增
376 }
377 if (flags & VM_MAP_REGION_FLAG_PERM_WRITE) {//可写入区标签
378 LOS_ArchMmuUnmap(&oldVmSpace->archMmu, vaddr, 1);//先删除老空间映射
379 LOS_ArchMmuMap(&oldVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);//老空间重新映射
380 }
381 LOS_ArchMmuMap(&newVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);//映射新空间
382
383#ifdef LOSCFG_FS_VFS //文件系统开关
384 if (LOS_IsRegionFileValid(oldRegion)) {//是都是一个文件映射线性区
385 LosFilePage *fpage = NULL;
386 LOS_SpinLockSave(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, &intSave);
387 fpage = OsFindGetEntry(&oldRegion->unTypeData.rf.vnode->mapping, newRegion->pgOff + i);
388 if ((fpage != NULL) && (fpage->vmPage == page)) { /* cow page no need map */
389 OsAddMapInfo(fpage, &newVmSpace->archMmu, vaddr);//添加文件页映射,记录页面被进程映射过
390 }
391 LOS_SpinUnlockRestore(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, intSave);
392 }
393#endif
394 }
395 RB_SCAN_SAFE_END(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)//红黑树循环结束
396 (VOID)LOS_MuxRelease(&oldVmSpace->regionMux);
397 return ret;
398}
STATIC INLINE VOID LOS_AtomicInc(Atomic *v)
Atomic addSelf.
Definition: los_atomic.h:253
STATUS_T LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间 所谓的map就是生成L1,L2页表项的过程
Definition: los_arch_mmu.c:891
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_spinlock.c:108
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
Definition: los_spinlock.c:98
unsigned int UINT32
Definition: los_typedef.h:57
VOID OsAddMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr)
LosFilePage * OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff)
STATIC BOOL OsVmSpaceParamCheck(LosVmSpace *vmSpace)
Definition: los_vm_map.c:309
BOOL LOS_IsRegionFileValid(LosVmMapRegion *region)
映射类型为文件的线性区是否有效
Definition: los_vm_map.c:512
STATIC INLINE BOOL OsIsVmRegionEmpty(LosVmSpace *vmSpace)
是否为一个空线性区
Definition: los_vm_map.h:293
LosVmMapRegion * OsVmRegionDup(LosVmSpace *space, LosVmMapRegion *oldRegion, VADDR_T vaddr, size_t size)
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
Definition: los_vm_page.c:120
VOID OsShmFork(LosVmSpace *space, LosVmMapRegion *oldRegion, LosVmMapRegion *newRegion)
fork 一个共享线性区
Definition: shm.c:393
文件页结构体
struct VmPage * vmPage
物理页框
UINT32 size
Definition: los_vm_map.h:85
VADDR_T base
Definition: los_vm_map.h:84
UINT32 regionFlags
Definition: los_vm_map.h:125
LosVmMapRange range
Definition: los_vm_map.h:123
VM_OFFSET_T pgOff
Definition: los_vm_map.h:124
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
Atomic refCounts
Definition: los_vm_page.h:57
LosVmMapRegion * heap
Definition: los_vm_map.h:154
VADDR_T mapBase
Definition: los_vm_map.h:155
VADDR_T heapBase
Definition: los_vm_map.h:152
VADDR_T heapNow
Definition: los_vm_map.h:153
函数调用图:
这是这个函数的调用关系图:

◆ OsAllocRange()

VADDR_T OsAllocRange ( LosVmSpace vmSpace,
size_t  len 
)

分配指定长度的线性区

在文件 los_vm_map.c436 行定义.

437{
438 LosVmMapRegion *curRegion = NULL;
439 LosRbNode *pstRbNode = NULL;
440 LosRbNode *pstRbNodeTmp = NULL;
441 LosRbTree *regionRbTree = &vmSpace->regionRbTree;
442 VADDR_T curEnd = vmSpace->mapBase;//获取映射区基地址
443 VADDR_T nextStart;
444
445 curRegion = LOS_RegionFind(vmSpace, vmSpace->mapBase);
446 if (curRegion != NULL) {
447 pstRbNode = &curRegion->rbNode;
448 curEnd = curRegion->range.base + curRegion->range.size;
449 RB_MID_SCAN(regionRbTree, pstRbNode)
450 curRegion = (LosVmMapRegion *)pstRbNode;
451 nextStart = curRegion->range.base;
452 if (nextStart < curEnd) {
453 continue;
454 }
455 if ((nextStart - curEnd) >= len) {
456 return curEnd;
457 } else {
458 curEnd = curRegion->range.base + curRegion->range.size;
459 }
460 RB_MID_SCAN_END(regionRbTree, pstRbNode)
461 } else {//红黑树扫描排序,从小到大
462 /* rbtree scan is sorted, from small to big */
463 RB_SCAN_SAFE(regionRbTree, pstRbNode, pstRbNodeTmp)
464 curRegion = (LosVmMapRegion *)pstRbNode;
465 nextStart = curRegion->range.base;
466 if (nextStart < curEnd) {
467 continue;
468 }
469 if ((nextStart - curEnd) >= len) {
470 return curEnd;
471 } else {
472 curEnd = curRegion->range.base + curRegion->range.size;
473 }
474 RB_SCAN_SAFE_END(regionRbTree, pstRbNode, pstRbNodeTmp)
475 }
476
477 nextStart = vmSpace->mapBase + vmSpace->mapSize;
478 if ((nextStart >= curEnd) && ((nextStart - curEnd) >= len)) {
479 return curEnd;
480 }
481
482 return 0;
483}
LosVmMapRegion * LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
查找线性区 根据起始地址在进程空间内查找是否存在
Definition: los_vm_map.c:414
LosRbNode rbNode
Definition: los_vm_map.h:120
UINT32 mapSize
Definition: los_vm_map.h:156
函数调用图:
这是这个函数的调用关系图:

◆ OsAllocSpecificRange()

VADDR_T OsAllocSpecificRange ( LosVmSpace vmSpace,
VADDR_T  vaddr,
size_t  len,
UINT32  regionFlags 
)

分配指定开始地址和长度的线性区

在文件 los_vm_map.c485 行定义.

486{
487 STATUS_T status;
488
489 if (LOS_IsRangeInSpace(vmSpace, vaddr, len) == FALSE) {//虚拟地址是否在进程空间范围内
490 return 0;
491 }
492
493 if ((LOS_RegionFind(vmSpace, vaddr) != NULL) ||
494 (LOS_RegionFind(vmSpace, vaddr + len - 1) != NULL) ||
495 (LOS_RegionRangeFind(vmSpace, vaddr, len - 1) != NULL)) {//没找到的情况
496 if ((regionFlags & VM_MAP_REGION_FLAG_FIXED_NOREPLACE) != 0) {
497 return 0;
498 } else if ((regionFlags & VM_MAP_REGION_FLAG_FIXED) != 0) {//线性区未填满,则解除这部分空间的映射
499 status = LOS_UnMMap(vaddr, len);//解除映射
500 if (status != LOS_OK) {
501 VM_ERR("unmap specific range va: %#x, len: %#x failed, status: %d", vaddr, len, status);
502 return 0;
503 }
504 } else {
505 return OsAllocRange(vmSpace, len);//默认分配一个
506 }
507 }
508
509 return vaddr;
510}
LosVmMapRegion * LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
查找线性区 根据地址区间在进程空间内查找是否存在
Definition: los_vm_map.c:425
BOOL LOS_IsRangeInSpace(const LosVmSpace *space, VADDR_T vaddr, size_t size)
STATUS_T LOS_UnMMap(VADDR_T addr, size_t size)
解除映射关系
函数调用图:
这是这个函数的调用关系图:

◆ OsAnonPagesRemove()

STATIC VOID OsAnonPagesRemove ( LosArchMmu archMmu,
VADDR_T  vaddr,
UINT32  count 
)

删除匿名页,匿名页就是内存映射页 1.解除映射关系 2.释放物理内存

在文件 los_vm_map.c625 行定义.

626{
627 status_t status;
628 paddr_t paddr;
629 LosVmPage *page = NULL;
630
631 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
632 VM_ERR("OsAnonPagesRemove invalid args, archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
633 return;
634 }
635
636 while (count > 0) {//一页页操作
637 count--;
638 status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);//通过虚拟地址拿到物理地址
639 if (status != LOS_OK) {//失败,拿下一页的物理地址
640 vaddr += PAGE_SIZE;
641 continue;
642 }
643
644 LOS_ArchMmuUnmap(archMmu, vaddr, 1);//解除一页的映射
645
646 page = LOS_VmPageGet(paddr);//通过物理地址获取所在物理页框的起始地址
647 if (page != NULL) {//获取成功
648 if (!OsIsPageShared(page)) {//不是共享页,共享页会有专门的共享标签,共享本质是有无多个进程对该页的引用
649 LOS_PhysPageFree(page);//释放物理页框
650 }
651 }
652 vaddr += PAGE_SIZE;
653 }
654}
int status_t
Definition: los_typedef.h:205
unsigned long paddr_t
Definition: los_typedef.h:209
STATIC INLINE BOOL OsIsPageShared(LosVmPage *page)
是否为共享页
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
Definition: los_vm_phys.c:546
函数调用图:
这是这个函数的调用关系图:

◆ OsCreateRegion()

LosVmMapRegion * OsCreateRegion ( VADDR_T  vaddr,
size_t  len,
UINT32  regionFlags,
unsigned long  offset 
)

创建一个线性区

在文件 los_vm_map.c531 行定义.

532{
533 LosVmMapRegion *region = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmMapRegion));//只是分配一个线性区结构体
534 if (region == NULL) {
535 VM_ERR("memory allocate for LosVmMapRegion failed");
536 return region;
537 }
538 //创建线性区的本质就是在画饼,见如下操作:
539 (void)memset_s(region, sizeof(LosVmMapRegion), 0, sizeof(LosVmMapRegion));
540 region->range.base = vaddr; //虚拟地址作为线性区的基地址
541 region->range.size = len; //线性区大小,这是线性区构思最巧妙的地方,只要不过分,蓝图随便画。
542 region->pgOff = offset; //页标
543 region->regionFlags = regionFlags;//标识,可读/可写/可执行
544 region->regionType = VM_MAP_REGION_TYPE_NONE;//未映射
545 region->forkFlags = 0; //
546 region->shmid = -1; //默认线性区为不共享,无共享资源ID
547 return region;
548}
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
struct VmMapRegion LosVmMapRegion
Definition: los_vm_map.h:89
UINT32 shmid
Definition: los_vm_map.h:126
UINT8 forkFlags
Definition: los_vm_map.h:127
UINT8 regionType
Definition: los_vm_map.h:128
ARG_NUM_3 ARG_NUM_1 ARG_NUM_2 ARG_NUM_2 ARG_NUM_3 ARG_NUM_1 ARG_NUM_4 ARG_NUM_2 ARG_NUM_2 ARG_NUM_5 ARG_NUM_2 void
函数调用图:
这是这个函数的调用关系图:

◆ OsCreateUserVmSpace()

LosVmSpace * OsCreateUserVmSpace ( VOID  )

创建用户进程空间

在文件 los_vm_map.c281 行定义.

282{
283 BOOL retVal = FALSE;
284
285 LosVmSpace *space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));//在内核空间申请用户进程空间
286 if (space == NULL) {
287 return NULL;
288 }
289 //此处为何直接申请物理页帧存放用户进程的页表,大概是因为所有页表都被存放在内核空间(g_kVmSpace)而非内核分配空间(g_vMallocSpace)
290 VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);//分配一个物理页用于存放虚实映射关系表, 即:L1表
291 if (ttb == NULL) {//若连页表都没有,剩下的也别玩了.
292 (VOID)LOS_MemFree(m_aucSysMem0, space);
293 return NULL;
294 }
295
296 (VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);//4K空间置0
297 retVal = OsUserVmSpaceInit(space, ttb);//初始化用户空间,mmu
298 LosVmPage *vmPage = OsVmVaddrToPage(ttb);//找到所在物理页框
299 if ((retVal == FALSE) || (vmPage == NULL)) {
300 (VOID)LOS_MemFree(m_aucSysMem0, space);
302 return NULL;
303 }
304 LOS_ListAdd(&space->archMmu.ptList, &(vmPage->node));//页表链表,先挂上L1,后续还会挂上 N个L2表
305
306 return space;
307}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a new node to a doubly linked list.
Definition: los_list.h:217
BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
OsUserVmSpaceInit 用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表 初始化用户进程虚拟空间,主要划分数据区,堆区,映射区和创建mmu
Definition: los_vm_map.c:265
VOID * LOS_PhysPagesAllocContiguous(size_t nPages)
分配连续的物理页
Definition: los_vm_phys.c:478
VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
释放指定页数地址连续的物理内存
Definition: los_vm_phys.c:494
LosVmPage * OsVmVaddrToPage(VOID *ptr)
通过虚拟地址找映射的物理页框
Definition: los_vm_phys.c:295
LOS_DL_LIST ptList
Definition: los_arch_mmu.h:93
LOS_DL_LIST node
Definition: los_vm_page.h:54
函数调用图:
这是这个函数的调用关系图:

◆ OsDevPagesRemove()

STATIC VOID OsDevPagesRemove ( LosArchMmu archMmu,
VADDR_T  vaddr,
UINT32  count 
)

在文件 los_vm_map.c656 行定义.

657{
658 status_t status;
659
660 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
661 VM_ERR("OsDevPagesRemove invalid args, archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
662 return;
663 }
664
665 status = LOS_ArchMmuQuery(archMmu, vaddr, NULL, NULL);
666 if (status != LOS_OK) {
667 return;
668 }
669
670 /* in order to unmap section */
671 LOS_ArchMmuUnmap(archMmu, vaddr, count);
672}
函数调用图:
这是这个函数的调用关系图:

◆ OsFilePagesRemove()

STATIC VOID OsFilePagesRemove ( LosVmSpace space,
LosVmMapRegion region 
)

在文件 los_vm_map.c675 行定义.

676{
677 VM_OFFSET_T offset;
678 size_t size;
679
680 if ((space == NULL) || (region == NULL) || (region->unTypeData.rf.vmFOps == NULL)) {
681 return;
682 }
683
684 offset = region->pgOff;
685 size = region->range.size;
686 while (size >= PAGE_SIZE) {
687 region->unTypeData.rf.vmFOps->remove(region, &space->archMmu, offset);
688 offset++;
689 size -= PAGE_SIZE;
690 }
691}
unsigned long VM_OFFSET_T
Definition: los_typedef.h:212
这是这个函数的调用关系图:

◆ OsFindRegion()

LosVmMapRegion * OsFindRegion ( LosRbTree regionRbTree,
VADDR_T  vaddr,
size_t  len 
)

通过虚拟(线性)地址查找所属线性区,红黑树

在文件 los_vm_map.c400 行定义.

401{
402 LosVmMapRegion *regionRst = NULL;
403 LosRbNode *pstRbNode = NULL;
404 LosVmMapRange rangeKey;
405 rangeKey.base = vaddr;
406 rangeKey.size = len;
407
408 if (LOS_RbGetNode(regionRbTree, (VOID *)&rangeKey, &pstRbNode)) {
409 regionRst = (LosVmMapRegion *)LOS_DL_LIST_ENTRY(pstRbNode, LosVmMapRegion, rbNode);
410 }
411 return regionRst;
412}
ULONG_T LOS_RbGetNode(LosRbTree *pstTree, VOID *pKey, LosRbNode **ppstNode)
Definition: los_rbtree.c:656
函数调用图:
这是这个函数的调用关系图:

◆ OsInsertRegion()

BOOL OsInsertRegion ( LosRbTree regionRbTree,
LosVmMapRegion region 
)

向红黑树中插入线性区

在文件 los_vm_map.c521 行定义.

522{
523 if (LOS_RbAddNode(regionRbTree, (LosRbNode *)region) == FALSE) {
524 VM_ERR("insert region failed, base: %#x, size: %#x", region->range.base, region->range.size);
525 OsDumpAspace(region->space);
526 return FALSE;
527 }
528 return TRUE;
529}
ULONG_T LOS_RbAddNode(LosRbTree *pstTree, LosRbNode *pstNew)
Definition: los_rbtree.c:705
VOID OsDumpAspace(LosVmSpace *space)
dump 指定虚拟空间的信息
Definition: los_vm_dump.c:396
函数调用图:
这是这个函数的调用关系图:

◆ OsKernVmSpaceInit()

BOOL OsKernVmSpaceInit ( LosVmSpace vmSpace,
VADDR_T virtTtb 
)

初始化内核虚拟空间

在文件 los_vm_map.c224 行定义.

225{
226 vmSpace->base = KERNEL_ASPACE_BASE;//内核空间基地址, 线性区将分配在此范围
227 vmSpace->size = KERNEL_ASPACE_SIZE;//内核空间大小
228 vmSpace->mapBase = KERNEL_VMM_BASE;//内核空间映射区基地址
229 vmSpace->mapSize = KERNEL_VMM_SIZE;//内核空间映射区大小
230#ifdef LOSCFG_DRIVERS_TZDRIVER
231 vmSpace->codeStart = 0; //代码区开始地址
232 vmSpace->codeEnd = 0; //代码区结束地址
233#endif
234 return OsVmSpaceInitCommon(vmSpace, virtTtb);//virtTtb 用于初始化 mmu
235}
STATIC BOOL OsVmSpaceInitCommon(LosVmSpace *vmSpace, VADDR_T *virtTtb)
OsVmSpaceInitCommon 初始化进程虚拟空间,必须提供L1表的虚拟内存地址
Definition: los_vm_map.c:199
VADDR_T base
Definition: los_vm_map.h:150
VADDR_T codeStart
Definition: los_vm_map.h:159
VADDR_T codeEnd
Definition: los_vm_map.h:160
UINT32 size
Definition: los_vm_map.h:151
函数调用图:
这是这个函数的调用关系图:

◆ OsKSpaceInit()

VOID OsKSpaceInit ( VOID  )

内核虚拟空间初始化

在文件 los_vm_map.c250 行定义.

251{
252 OsVmMapInit();//初始化后续操作 g_vmSpaceList 的互斥锁
253 OsKernVmSpaceInit(&g_kVmSpace, OsGFirstTableGet()); //初始化内核进程虚拟空间
254 OsVMallocSpaceInit(&g_vMallocSpace, OsGFirstTableGet());//初始化内核动态分配空间
255}
VADDR_T * OsGFirstTableGet(VOID)
Definition: los_arch_mmu.c:186
BOOL OsKernVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
初始化内核虚拟空间
Definition: los_vm_map.c:224
BOOL OsVMallocSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
初始化内核堆空间
Definition: los_vm_map.c:237
VOID OsVmMapInit(VOID)
@note_thinking 这个函数名称和内容不太搭
Definition: los_vm_map.c:216
函数调用图:
这是这个函数的调用关系图:

◆ OsRegionRbCmpKeyFn()

ULONG_T OsRegionRbCmpKeyFn ( const VOID *  pNodeKeyA,
const VOID *  pNodeKeyB 
)

比较两个红黑树节点

在文件 los_vm_map.c161 行定义.

162{
163 LosVmMapRange rangeA = *(LosVmMapRange *)pNodeKeyA;
164 LosVmMapRange rangeB = *(LosVmMapRange *)pNodeKeyB;
165 UINT32 startA = rangeA.base;
166 UINT32 endA = rangeA.base + rangeA.size - 1;
167 UINT32 startB = rangeB.base;
168 UINT32 endB = rangeB.base + rangeB.size - 1;
169
170 if (startA > endB) {// A基地址大于B的结束地址
171 return RB_BIGGER; //说明线性区A更大,在右边
172 } else if (startA >= startB) {
173 if (endA <= endB) {
174 return RB_EQUAL; //相等,说明 A在B中
175 } else {
176 return RB_BIGGER; //说明 A的结束地址更大
177 }
178 } else if (startA <= startB) { //A基地址小于等于B的基地址
179 if (endA >= endB) {
180 return RB_EQUAL; //相等 说明 B在A中
181 } else {
182 return RB_SMALLER;//说明A的结束地址更小
183 }
184 } else if (endA < startB) {//A结束地址小于B的开始地址
185 return RB_SMALLER;//说明A在
186 }
187 return RB_EQUAL;
188}
这是这个函数的调用关系图:

◆ OsRegionRbFreeFn()

ULONG_T OsRegionRbFreeFn ( LosRbNode pstNode)

释放挂在红黑树上节点,等于释放了线性区

在文件 los_vm_map.c149 行定义.

150{
151 LOS_MemFree(m_aucSysMem0, pstNode);
152 return LOS_OK;
153}
函数调用图:
这是这个函数的调用关系图:

◆ OsRegionRbGetKeyFn()

VOID * OsRegionRbGetKeyFn ( LosRbNode pstNode)

通过红黑树节点找到对应的线性区

在文件 los_vm_map.c155 行定义.

156{
157 LosVmMapRegion *region = (LosVmMapRegion *)LOS_DL_LIST_ENTRY(pstNode, LosVmMapRegion, rbNode);
158 return (VOID *)&region->range;
159}
这是这个函数的调用关系图:

◆ OsUserVmSpaceInit()

BOOL OsUserVmSpaceInit ( LosVmSpace vmSpace,
VADDR_T virtTtb 
)

OsUserVmSpaceInit 用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表 初始化用户进程虚拟空间,主要划分数据区,堆区,映射区和创建mmu

参数
virtTtb
vmSpace
返回
参见

在文件 los_vm_map.c265 行定义.

266{
267 vmSpace->base = USER_ASPACE_BASE;//用户空间基地址
268 vmSpace->size = USER_ASPACE_SIZE;//用户空间大小
269 vmSpace->mapBase = USER_MAP_BASE;//用户空间映射基地址
270 vmSpace->mapSize = USER_MAP_SIZE;//用户空间映射大小
271 vmSpace->heapBase = USER_HEAP_BASE;//用户堆区开始地址,只有用户进程需要设置这里,动态内存的开始地址
272 vmSpace->heapNow = USER_HEAP_BASE;//堆区最新指向地址,用户堆空间大小可通过系统调用 do_brk()扩展
273 vmSpace->heap = NULL; //最近分配的一个堆线性区
274#ifdef LOSCFG_DRIVERS_TZDRIVER
275 vmSpace->codeStart = 0;
276 vmSpace->codeEnd = 0;
277#endif
278 return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作
279}
函数调用图:
这是这个函数的调用关系图:

◆ OsVMallocSpaceInit()

BOOL OsVMallocSpaceInit ( LosVmSpace vmSpace,
VADDR_T virtTtb 
)

初始化内核堆空间

在文件 los_vm_map.c237 行定义.

238{
239 vmSpace->base = VMALLOC_START; //内核堆空间基地址
240 vmSpace->size = VMALLOC_SIZE; //内核堆空间大小
241 vmSpace->mapBase = VMALLOC_START; //内核堆空间映射基地址
242 vmSpace->mapSize = VMALLOC_SIZE; //内核堆空间映射区大小
243#ifdef LOSCFG_DRIVERS_TZDRIVER
244 vmSpace->codeStart = 0;
245 vmSpace->codeEnd = 0;
246#endif
247 return OsVmSpaceInitCommon(vmSpace, virtTtb);//创建MMU,为后续的虚实映射做好初始化的工作
248}
函数调用图:
这是这个函数的调用关系图:

◆ OsVmMapInit()

VOID OsVmMapInit ( VOID  )

@note_thinking 这个函数名称和内容不太搭

在文件 los_vm_map.c216 行定义.

217{
218 status_t retval = LOS_MuxInit(&g_vmSpaceListMux, NULL);//初始化虚拟空间的互斥量
219 if (retval != LOS_OK) {
220 VM_ERR("Create mutex for g_vmSpaceList failed, status: %d", retval);
221 }
222}
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
LosMux g_vmSpaceListMux
用于锁g_vmSpaceList的互斥量
Definition: los_vm_map.c:103
函数调用图:
这是这个函数的调用关系图:

◆ OsVmSpaceInitCommon()

STATIC BOOL OsVmSpaceInitCommon ( LosVmSpace vmSpace,
VADDR_T virtTtb 
)

OsVmSpaceInitCommon 初始化进程虚拟空间,必须提供L1表的虚拟内存地址

参数
virtTtbL1表的地址,TTB表地址
vmSpace
返回
参见

在文件 los_vm_map.c199 行定义.

200{
201 LOS_RbInitTree(&vmSpace->regionRbTree, OsRegionRbCmpKeyFn, OsRegionRbFreeFn, OsRegionRbGetKeyFn);//初始化虚拟存储空间-以红黑树组织方式
202
203 status_t retval = LOS_MuxInit(&vmSpace->regionMux, NULL);//初始化互斥量
204 if (retval != LOS_OK) {
205 VM_ERR("Create mutex for vm space failed, status: %d", retval);
206 return FALSE;
207 }
208
210 LOS_ListAdd(&g_vmSpaceList, &vmSpace->node);//将虚拟空间挂入全局虚拟空间双循环链表上
212
213 return OsArchMmuInit(&vmSpace->archMmu, virtTtb);//对mmu初始化
214}
BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb)
Definition: los_arch_mmu.c:537
VOID LOS_RbInitTree(LosRbTree *pstTree, pfRBCmpKeyFn pfCmpKey, pfRBFreeFn pfFree, pfRBGetKeyFn pfGetKey)
Definition: los_rbtree.c:524
ULONG_T OsRegionRbCmpKeyFn(const VOID *pNodeKeyA, const VOID *pNodeKeyB)
比较两个红黑树节点
Definition: los_vm_map.c:161
ULONG_T OsRegionRbFreeFn(LosRbNode *pstNode)
释放挂在红黑树上节点,等于释放了线性区
Definition: los_vm_map.c:149
VOID * OsRegionRbGetKeyFn(LosRbNode *pstNode)
通过红黑树节点找到对应的线性区
Definition: los_vm_map.c:155
LOS_DL_LIST node
Definition: los_vm_map.h:147
函数调用图:
这是这个函数的调用关系图:

◆ OsVmSpaceParamCheck()

STATIC BOOL OsVmSpaceParamCheck ( LosVmSpace vmSpace)

在文件 los_vm_map.c309 行定义.

310{
311 if (vmSpace == NULL) {
312 return FALSE;
313 }
314 return TRUE;
315}
这是这个函数的调用关系图:

变量说明

◆ g_kVmSpace

LosVmSpace g_kVmSpace

内核非分配空间,用于内核运行栈,代码区,数据区

在文件 los_vm_map.c105 行定义.

◆ g_vMallocSpace

LosVmSpace g_vMallocSpace

内核分配空间,用于内核分配内存

在文件 los_vm_map.c106 行定义.

◆ g_vmSpaceListMux

LosMux g_vmSpaceListMux

用于锁g_vmSpaceList的互斥量

在文件 los_vm_map.c103 行定义.