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

虚实映射其实就是一个建立页表的过程 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-inner-reflect.html 更多...

浏览源代码.

结构体

struct  MmuMapInfo
 

函数

 __attribute__ ((aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS)))
 
STATIC SPIN_LOCK_SOsGetPte1Lock (LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
 
STATIC INLINE VOID OsUnlockPte1 (SPIN_LOCK_S *lock, UINT32 intSave)
 
STATIC SPIN_LOCK_SOsGetPte1LockTmp (LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
 
STATIC INLINE VOID OsUnlockPte1Tmp (SPIN_LOCK_S *lock, UINT32 intSave)
 
STATIC INLINE SPIN_LOCK_SOsGetPte2Lock (LosArchMmu *archMmu, PTE_T pte1, UINT32 *intSave)
 
STATIC INLINE VOID OsUnlockPte2 (SPIN_LOCK_S *lock, UINT32 intSave)
 
STATIC INLINE PTE_TOsGetPte2BasePtr (PTE_T pte1)
 获取页表基地址 更多...
 
VADDR_TOsGFirstTableGet (VOID)
 
STATIC INLINE UINT32 OsUnmapL1Invalid (vaddr_t *vaddr, UINT32 *count)
 解除L1表的映射关系 更多...
 
STATIC INT32 OsMapParamCheck (UINT32 flags, VADDR_T vaddr, PADDR_T paddr)
 
STATIC VOID OsCvtPte2AttsToFlags (PTE_T l1Entry, PTE_T l2Entry, UINT32 *flags)
 
STATIC VOID OsPutL2Table (const LosArchMmu *archMmu, UINT32 l1Index, paddr_t l2Paddr)
 
STATIC VOID OsTryUnmapL1PTE (LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t vaddr, UINT32 scanIndex, UINT32 scanCount)
 
STATIC UINT32 OsCvtSecCacheFlagsToMMUFlags (UINT32 flags)
 
STATIC UINT32 OsCvtSecAccessFlagsToMMUFlags (UINT32 flags)
 
STATIC UINT32 OsCvtSecFlagsToAttrs (UINT32 flags)
 
STATIC VOID OsCvtSecAttsToFlags (PTE_T l1Entry, UINT32 *flags)
 
STATIC UINT32 OsUnmapL2PTE (LosArchMmu *archMmu, PTE_T *pte1, vaddr_t vaddr, UINT32 *count)
 
STATIC UINT32 OsUnmapSection (LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t *vaddr, UINT32 *count)
 
BOOL OsArchMmuInit (LosArchMmu *archMmu, VADDR_T *virtTtb)
 
STATUS_T LOS_ArchMmuQuery (const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
 LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。
本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限 更多...
 
STATUS_T LOS_ArchMmuUnmap (LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
 LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系 更多...
 
STATIC UINT32 OsMapSection (MmuMapInfo *mmuMapInfo, UINT32 *count)
 OsMapSection section页表格式项映射 更多...
 
STATIC STATUS_T OsGetL2Table (LosArchMmu *archMmu, UINT32 l1Index, paddr_t *ppa)
 获取L2页表,分配L2表(需物理内存) 更多...
 
STATIC UINT32 OsCvtPte2CacheFlagsToMMUFlags (UINT32 flags)
 
STATIC UINT32 OsCvtPte2AccessFlagsToMMUFlags (UINT32 flags)
 
STATIC UINT32 OsCvtPte2FlagsToAttrs (UINT32 flags)
 
STATIC UINT32 OsMapL1PTE (MmuMapInfo *mmuMapInfo, PTE_T *l1Entry, UINT32 *count)
 
STATIC UINT32 OsMapL2PageContinous (MmuMapInfo *mmuMapInfo, PTE_T *pte1, UINT32 *count)
 
status_t LOS_ArchMmuMap (LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
 LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间
所谓的map就是生成L1,L2页表项的过程 更多...
 
STATUS_T LOS_ArchMmuChangeProt (LosArchMmu *archMmu, VADDR_T vaddr, size_t count, UINT32 flags)
 LOS_ArchMmuChangeProt 修改进程空间虚拟地址区间的映射属性 改变内存段的访问权限,例如: 读/写/可执行/不可用 == 更多...
 
STATUS_T LOS_ArchMmuMove (LosArchMmu *archMmu, VADDR_T oldVaddr, VADDR_T newVaddr, size_t count, UINT32 flags)
 LOS_ArchMmuMove 将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。 更多...
 
VOID LOS_ArchMmuContextSwitch (LosArchMmu *archMmu)
 LOS_ArchMmuContextSwitch 切换MMU上下文 更多...
 
STATUS_T LOS_ArchMmuDestroy (LosArchMmu *archMmu)
 LOS_ArchMmuDestroy 销毁MMU 和 initMmu 相呼应,释放页表页 更多...
 
STATIC VOID OsSwitchTmpTTB (VOID)
 切换临时页表 更多...
 
STATIC VOID OsSetKSectionAttr (UINTPTR virtAddr, BOOL uncached)
 设置内核空间段属性,可看出内核空间是固定映射到物理地址 更多...
 
STATIC VOID OsKSectionNewAttrEnable (VOID)
 
VOID OsArchMmuInitPerCPU (VOID)
 
VOID OsInitMappingStartUp (VOID)
 OsInitMappingStartUp 开始初始化mmu 更多...
 

详细描述

虚实映射其实就是一个建立页表的过程 http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-inner-reflect.html

   虚实映射是指系统通过内存管理单元(MMU,Memory Management Unit)将进程空间的虚拟地址与实际的物理地址做映射,
   并指定相应的访问权限、缓存属性等。程序执行时,CPU访问的是虚拟内存,通过MMU页表条目找到对应的物理内存,
   并做相应的代码执行或数据读写操作。MMU的映射由页表(Page Table)来描述,其中保存虚拟地址和物理地址的映射关系以及访问权限等。
   每个进程在创建的时候都会创建一个页表,页表由一个个页表条目(Page Table Entry, PTE)构成,
   每个页表条目描述虚拟地址区间与物理地址区间的映射关系。MMU中有一块页表缓存,称为快表(TLB, Translation Lookaside Buffers),
   做地址转换时,MMU首先在TLB中查找,如果找到对应的页表条目可直接进行转换,提高了查询效率。

   虚实映射其实就是一个建立页表的过程。MMU有多级页表,LiteOS-A内核采用二级页表描述进程空间。每个一级页表条目描述符占用4个字节,
   可表示1MiB的内存空间的映射关系,即1GiB用户空间(LiteOS-A内核中用户空间占用1GiB)的虚拟内存空间需要1024个。系统创建用户进程时,
   在内存中申请一块4KiB大小的内存块作为一级页表的存储区域,二级页表根据当前进程的需要做动态的内存申请。

   用户程序加载启动时,会将代码段、数据段映射进虚拟内存空间(详细可参考动态加载与链接),此时并没有物理页做实际的映射;
   程序执行时,如下图粗箭头所示,CPU访问虚拟地址,通过MMU查找是否有对应的物理内存,若该虚拟地址无对应的物理地址则触发缺页异常,
   内核申请物理内存并将虚实映射关系及对应的属性配置信息写进页表,并把页表条目缓存至TLB,接着CPU可直接通过转换关系访问实际的物理内存;
   若CPU访问已缓存至TLB的页表条目,无需再访问保存在内存中的页表,可加快查找速度。

   开发流程
    1. 虚实映射相关接口的使用:
        通过LOS_ArchMmuMap映射一块物理内存。

    2. 对映射的地址区间做相关操作:
        通过LOS_ArchMmuQuery可以查询相应虚拟地址区间映射的物理地址区间及映射属性;
        通过LOS_ArchMmuChangeProt修改映射属性;
        通过LOS_ArchMmuMove做虚拟地址区间的重映射。
    3. 通过LOS_ArchMmuUnmap解除映射关系。

* 
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-17

@history

在文件 los_arch_mmu.c 中定义.

函数说明

◆ __attribute__()

__attribute__ ( (aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS))  )

在文件 los_arch_mmu.c98 行定义.

112{
113 SPIN_LOCK_S *lock = NULL;
114#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
115 LosVmPage *vmPage = NULL;
116
117 vmPage = OsVmPaddrToPage(paddr);
118 if (vmPage == NULL) {
119 return NULL;
120 }
121 lock = &vmPage->lock;
122#else
123 lock = &archMmu->lock;
124#endif
125
126 LOS_SpinLockSave(lock, intSave);
127 return lock;
128}
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
Definition: los_spinlock.c:98
LosVmPage * OsVmPaddrToPage(paddr_t paddr)
Definition: los_vm_phys.c:267
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
SPIN_LOCK_S lock
Definition: los_vm_page.h:63
函数调用图:

◆ LOS_ArchMmuChangeProt()

STATUS_T LOS_ArchMmuChangeProt ( LosArchMmu archMmu,
VADDR_T  vaddr,
size_t  count,
UINT32  flags 
)

LOS_ArchMmuChangeProt 修改进程空间虚拟地址区间的映射属性 改变内存段的访问权限,例如: 读/写/可执行/不可用 ==

参数
archMmu
count
flags
vaddr
返回
参见

在文件 los_arch_mmu.c949 行定义.

950{
951 STATUS_T status;
952 PADDR_T paddr = 0;
953
954 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
955 VM_ERR("invalid args: archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
956 return LOS_NOK;
957 }
958
959 while (count > 0) {
960 count--;
961 status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);//1. 先查出物理地址
962 if (status != LOS_OK) {
963 vaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
964 continue;
965 }
966
967 status = LOS_ArchMmuUnmap(archMmu, vaddr, 1);//2. 取消原有映射
968 if (status < 0) {
969 VM_ERR("invalid args:aspace %p, vaddr %p, count %d", archMmu, vaddr, count);
970 return LOS_NOK;
971 }
972
973 status = LOS_ArchMmuMap(archMmu, vaddr, paddr, 1, flags);//3. 重新映射 虚实地址
974 if (status < 0) {
975 VM_ERR("invalid args:aspace %p, vaddr %p, count %d",
976 archMmu, vaddr, count);
977 return LOS_NOK;
978 }
979 vaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
980 }
981 return LOS_OK;
982}
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
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
int STATUS_T
Definition: los_typedef.h:215
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuContextSwitch()

VOID LOS_ArchMmuContextSwitch ( LosArchMmu archMmu)

LOS_ArchMmuContextSwitch 切换MMU上下文

参数
archMmu
返回
参见

在文件 los_arch_mmu.c1044 行定义.

1045{
1046 UINT32 ttbr;//B4.1.153 TTBCR, Translation Table Base Control Register,
1047 UINT32 ttbcr = OsArmReadTtbcr();//读取TTB寄存器的状态值
1048 if (archMmu) {
1049 ttbr = MMU_TTBRx_FLAGS | (archMmu->physTtb);//提供进程的映射页表地址,切换MMU代表要换进程,同一进程的线程切换并不需要切MMU
1050 /* enable TTBR0 */
1051 ttbcr &= ~MMU_DESCRIPTOR_TTBCR_PD0;//使能TTBR0 B4.1.154 TTBR0, Translation Table Base Register 0
1052 } else {
1053 ttbr = 0;
1054 /* disable TTBR0 */
1055 ttbcr |= MMU_DESCRIPTOR_TTBCR_PD0;//禁用TTBR0
1056 }
1057
1058#ifdef LOSCFG_KERNEL_VM
1059 /* from armv7a arm B3.10.4, we should do synchronization changes of ASID and TTBR. */
1060 OsArmWriteContextidr(LOS_GetKVmSpace()->archMmu.asid);//这里先把asid切到内核空间的ID
1061 ISB; //指令必须同步 ,清楚流水线中未执行指令
1062#endif
1063 OsArmWriteTtbr0(ttbr);//通过r0寄存器将进程页面基址写入TTB
1064 ISB;
1065 OsArmWriteTtbcr(ttbcr);//写入TTB状态位
1066 ISB;
1067#ifdef LOSCFG_KERNEL_VM
1068 if (archMmu) {
1069 OsArmWriteContextidr(archMmu->asid);//通过R0寄存器写入进程标识符至C13寄存器
1070 ISB; // 可查看 鸿蒙内核源码分析(优雅的宏篇)
1071 }
1072#endif
1073}
STATIC INLINE VOID OsArmWriteTtbcr(UINT32 val)
Definition: arm.h:124
STATIC INLINE VOID OsArmWriteContextidr(UINT32 val)
Definition: arm.h:228
STATIC INLINE UINT32 OsArmReadTtbcr(VOID)
Definition: arm.h:117
STATIC INLINE VOID OsArmWriteTtbr0(UINT32 val)
Definition: arm.h:98
unsigned int UINT32
Definition: los_typedef.h:57
LosVmSpace * LOS_GetKVmSpace(VOID)
内核空间只有g_kVmSpace一个,所有的内核进程都共用一个内核空间
Definition: los_vm_map.c:130
UINT32 asid
Definition: los_arch_mmu.h:92
PADDR_T physTtb
Definition: los_arch_mmu.h:91
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuDestroy()

STATUS_T LOS_ArchMmuDestroy ( LosArchMmu archMmu)

LOS_ArchMmuDestroy 销毁MMU 和 initMmu 相呼应,释放页表页

参数
archMmu
返回
参见

在文件 los_arch_mmu.c1083 行定义.

1084{
1085#ifdef LOSCFG_KERNEL_VM
1086 LosVmPage *page = NULL;
1087 /* free all of the pages allocated in archMmu->ptList */
1088 while ((page = LOS_ListRemoveHeadType(&archMmu->ptList, LosVmPage, node)) != NULL) {
1089 LOS_PhysPageFree(page);//释放物理页
1090 }
1091
1092 OsArmWriteTlbiasidis(archMmu->asid);
1093 OsFreeAsid(archMmu->asid);//释放asid
1094#endif
1095 return LOS_OK;
1096}
STATIC INLINE VOID OsArmWriteTlbiasidis(UINT32 val)
记录由协处理器记录当前是哪个进程在跑
Definition: arm.h:514
VOID OsFreeAsid(UINT32 asid)
释放 asid
Definition: los_asid.c:96
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
Definition: los_vm_phys.c:546
LOS_DL_LIST ptList
Definition: los_arch_mmu.h:93
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuMap()

status_t LOS_ArchMmuMap ( LosArchMmu archMmu,
VADDR_T  vaddr,
PADDR_T  paddr,
size_t  count,
UINT32  flags 
)

LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间
所谓的map就是生成L1,L2页表项的过程

参数
archMmu
count
flags
paddr
vaddr
返回
参见

在文件 los_arch_mmu.c891 行定义.

892{
893 PTE_T *l1Entry = NULL;
894 UINT32 saveCounts = 0;
895 INT32 mapped = 0;
896 INT32 tryTime = TRY_MAX_TIMES;
897 INT32 checkRst;
898 MmuMapInfo mmuMapInfo = {
899 .archMmu = archMmu,
900 .vaddr = &vaddr,
901 .paddr = &paddr,
902 .flags = &flags,
903 };
904
905 checkRst = OsMapParamCheck(flags, vaddr, paddr);//检查参数
906 if (checkRst < 0) {
907 return checkRst;
908 }
909
910 /* see what kind of mapping we can use */
911 while (count > 0) {
912 if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(*mmuMapInfo.vaddr) &&
913 MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(*mmuMapInfo.paddr) &&
914 count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
915 /* compute the arch flags for L1 sections cache, r ,w ,x, domain and type */
916 saveCounts = OsMapSection(&mmuMapInfo, &count);
917 } else {
918 /* have to use a L2 mapping, we only allocate 4KB for L1, support 0 ~ 1GB */
919 l1Entry = OsGetPte1Ptr(archMmu->virtTtb, *mmuMapInfo.vaddr);
920 if (OsIsPte1Invalid(*l1Entry)) {
921 saveCounts = OsMapL1PTE(&mmuMapInfo, l1Entry, &count);
922 } else if (OsIsPte1PageTable(*l1Entry)) {
923 saveCounts = OsMapL2PageContinous(&mmuMapInfo, l1Entry, &count);
924 } else {
925 LOS_Panic("%s %d, unimplemented tt_entry %x\n", __FUNCTION__, __LINE__, l1Entry);
926 }
927 }
928 mapped += saveCounts;
929 tryTime = (saveCounts == 0) ? (tryTime - 1) : tryTime;
930 if (tryTime == 0) {
931 return LOS_ERRNO_VM_TIMED_OUT;
932 }
933 }
934
935 return mapped;
936}
NORETURN VOID LOS_Panic(const CHAR *fmt,...)
Kernel panic function.
STATIC INT32 OsMapParamCheck(UINT32 flags, VADDR_T vaddr, PADDR_T paddr)
Definition: los_arch_mmu.c:204
STATIC UINT32 OsMapL2PageContinous(MmuMapInfo *mmuMapInfo, PTE_T *pte1, UINT32 *count)
Definition: los_arch_mmu.c:851
STATIC UINT32 OsMapSection(MmuMapInfo *mmuMapInfo, UINT32 *count)
OsMapSection section页表格式项映射
Definition: los_arch_mmu.c:666
STATIC UINT32 OsMapL1PTE(MmuMapInfo *mmuMapInfo, PTE_T *l1Entry, UINT32 *count)
Definition: los_arch_mmu.c:806
STATIC INLINE BOOL OsIsPte1PageTable(PTE_T pte1)
Definition: los_pte_ops.h:87
STATIC INLINE PTE_T * OsGetPte1Ptr(PTE_T *pte1BasePtr, vaddr_t va)
pte1BasePtr L1 转换页表基地址
Definition: los_pte_ops.h:77
STATIC INLINE BOOL OsIsPte1Invalid(PTE_T pte1)
Definition: los_pte_ops.h:92
signed int INT32
Definition: los_typedef.h:60
unsigned long PTE_T
Definition: los_typedef.h:213
VADDR_T * virtTtb
Definition: los_arch_mmu.h:90
LosArchMmu * archMmu
Definition: los_arch_mmu.c:90
VADDR_T * vaddr
Definition: los_arch_mmu.c:91
PADDR_T * paddr
Definition: los_arch_mmu.c:92
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuMove()

STATUS_T LOS_ArchMmuMove ( LosArchMmu archMmu,
VADDR_T  oldVaddr,
VADDR_T  newVaddr,
size_t  count,
UINT32  flags 
)

LOS_ArchMmuMove 将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。

参数
archMmu
count
flags
newVaddr
oldVaddr
返回
参见

在文件 los_arch_mmu.c996 行定义.

997{
998 STATUS_T status;
999 PADDR_T paddr = 0;
1000
1001 if ((archMmu == NULL) || (oldVaddr == 0) || (newVaddr == 0) || (count == 0)) {
1002 VM_ERR("invalid args: archMmu %p, oldVaddr %p, newVaddr %p, count %d",
1003 archMmu, oldVaddr, newVaddr, count);
1004 return LOS_NOK;
1005 }
1006
1007 while (count > 0) {
1008 count--;
1009 status = LOS_ArchMmuQuery(archMmu, oldVaddr, &paddr, NULL);
1010 if (status != LOS_OK) {
1011 oldVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1012 newVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1013 continue;
1014 }
1015 // we need to clear the mapping here and remain the phy page.
1016 status = LOS_ArchMmuUnmap(archMmu, oldVaddr, 1);
1017 if (status < 0) {
1018 VM_ERR("invalid args: archMmu %p, vaddr %p, count %d",
1019 archMmu, oldVaddr, count);
1020 return LOS_NOK;
1021 }
1022
1023 status = LOS_ArchMmuMap(archMmu, newVaddr, paddr, 1, flags);
1024 if (status < 0) {
1025 VM_ERR("invalid args:archMmu %p, old_vaddr %p, new_addr %p, count %d",
1026 archMmu, oldVaddr, newVaddr, count);
1027 return LOS_NOK;
1028 }
1029 oldVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1030 newVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1031 }
1032
1033 return LOS_OK;
1034}
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuQuery()

STATUS_T LOS_ArchMmuQuery ( const LosArchMmu archMmu,
VADDR_T  vaddr,
PADDR_T paddr,
UINT32 flags 
)

LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。
本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限

参数
archMmu
flags
paddr
vaddr
返回
参见

在文件 los_arch_mmu.c569 行定义.

570{//archMmu->virtTtb:转换表基地址
571 PTE_T l1Entry = OsGetPte1(archMmu->virtTtb, vaddr);//获取PTE vaddr右移20位 得到L1描述子地址
572 PTE_T l2Entry;
573 PTE_T* l2Base = NULL;
574
575 if (OsIsPte1Invalid(l1Entry)) {//判断L1描述子地址是否有效
576 return LOS_ERRNO_VM_NOT_FOUND;//无效返回虚拟地址未查询到
577 } else if (OsIsPte1Section(l1Entry)) {// section页表项: l1Entry低二位是否为 10
578 if (paddr != NULL) {//物理地址 = 节基地址(section页表项的高12位) + 虚拟地址低20位
579 *paddr = MMU_DESCRIPTOR_L1_SECTION_ADDR(l1Entry) + (vaddr & (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1));
580 }
581
582 if (flags != NULL) {
583 OsCvtSecAttsToFlags(l1Entry, flags);//获取虚拟内存的flag信息
584 }
585 } else if (OsIsPte1PageTable(l1Entry)) {//PAGE_TABLE页表项: l1Entry低二位是否为 01
586 l2Base = OsGetPte2BasePtr(l1Entry);//获取L2转换表基地址
587 if (l2Base == NULL) {
588 return LOS_ERRNO_VM_NOT_FOUND;
589 }
590 l2Entry = OsGetPte2(l2Base, vaddr);//获取L2描述子地址
591 if (OsIsPte2SmallPage(l2Entry) || OsIsPte2SmallPageXN(l2Entry)) {
592 if (paddr != NULL) {//物理地址 = 小页基地址(L2页表项的高20位) + 虚拟地址低12位
593 *paddr = MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(l2Entry) + (vaddr & (MMU_DESCRIPTOR_L2_SMALL_SIZE - 1));
594 }
595
596 if (flags != NULL) {
597 OsCvtPte2AttsToFlags(l1Entry, l2Entry, flags);//获取虚拟内存的flag信息
598 }
599 } else if (OsIsPte2LargePage(l2Entry)) {//鸿蒙目前暂不支持64K大页,未来手机版应该会支持。
600 LOS_Panic("%s %d, large page unimplemented\n", __FUNCTION__, __LINE__);
601 } else {
602 return LOS_ERRNO_VM_NOT_FOUND;
603 }
604 }
605
606 return LOS_OK;
607}
STATIC VOID OsCvtSecAttsToFlags(PTE_T l1Entry, UINT32 *flags)
Definition: los_arch_mmu.c:437
STATIC INLINE PTE_T * OsGetPte2BasePtr(PTE_T pte1)
获取页表基地址
Definition: los_arch_mmu.c:180
STATIC VOID OsCvtPte2AttsToFlags(PTE_T l1Entry, PTE_T l2Entry, UINT32 *flags)
Definition: los_arch_mmu.c:221
STATIC INLINE PTE_T OsGetPte1(PTE_T *pte1BasePtr, vaddr_t va)
Definition: los_pte_ops.h:82
STATIC INLINE PTE_T OsGetPte2(PTE_T *pte2BasePtr, vaddr_t va)
Definition: los_pte_ops.h:112
STATIC INLINE BOOL OsIsPte2SmallPageXN(PTE_T pte2)
Definition: los_pte_ops.h:160
STATIC INLINE BOOL OsIsPte2LargePage(PTE_T pte2)
Definition: los_pte_ops.h:165
STATIC INLINE BOOL OsIsPte2SmallPage(PTE_T pte2)
Definition: los_pte_ops.h:155
STATIC INLINE BOOL OsIsPte1Section(PTE_T pte1)
Definition: los_pte_ops.h:97
函数调用图:
这是这个函数的调用关系图:

◆ LOS_ArchMmuUnmap()

STATUS_T LOS_ArchMmuUnmap ( LosArchMmu archMmu,
VADDR_T  vaddr,
size_t  count 
)

LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系

参数
archMmu
count
vaddr
返回
参见

在文件 los_arch_mmu.c619 行定义.

620{
621 PTE_T *l1Entry = NULL;
622 INT32 unmapped = 0;
623 UINT32 unmapCount = 0;
624 INT32 tryTime = TRY_MAX_TIMES;
625
626 while (count > 0) {
627 l1Entry = OsGetPte1Ptr(archMmu->virtTtb, vaddr);//获取L1表
628 if (OsIsPte1Invalid(*l1Entry)) {//L1表是否有效
629 unmapCount = OsUnmapL1Invalid(&vaddr, &count);//取消L1表内的映射
630 } else if (OsIsPte1Section(*l1Entry)) {
631 if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(vaddr) && count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
632 unmapCount = OsUnmapSection(archMmu, l1Entry, &vaddr, &count);
633 } else {
634 LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
635 }
636 } else if (OsIsPte1PageTable(*l1Entry)) {
637 unmapCount = OsUnmapL2PTE(archMmu, l1Entry, vaddr, &count);//取消L2表的映射
638 OsTryUnmapL1PTE(archMmu, l1Entry, vaddr, OsGetPte2Index(vaddr) + unmapCount,
639 MMU_DESCRIPTOR_L2_NUMBERS_PER_L1);
640 vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
641 } else {
642 LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
643 }
644 tryTime = (unmapCount == 0) ? (tryTime - 1) : tryTime;
645 if (tryTime == 0) {
646 return LOS_ERRNO_VM_FAULT;
647 }
648 unmapped += unmapCount;
649 }
651 return unmapped;
652}
STATIC VOID OsTryUnmapL1PTE(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t vaddr, UINT32 scanIndex, UINT32 scanCount)
Definition: los_arch_mmu.c:292
STATIC UINT32 OsUnmapSection(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t *vaddr, UINT32 *count)
Definition: los_arch_mmu.c:515
STATIC INLINE UINT32 OsUnmapL1Invalid(vaddr_t *vaddr, UINT32 *count)
解除L1表的映射关系
Definition: los_arch_mmu.c:192
STATIC UINT32 OsUnmapL2PTE(LosArchMmu *archMmu, PTE_T *pte1, vaddr_t vaddr, UINT32 *count)
Definition: los_arch_mmu.c:482
STATIC INLINE UINT32 OsGetPte2Index(vaddr_t va)
Definition: los_pte_ops.h:102
STATIC INLINE VOID OsArmInvalidateTlbBarrier(VOID)
Definition: los_tlb_v6.h:48
函数调用图:
这是这个函数的调用关系图:

◆ OsArchMmuInit()

BOOL OsArchMmuInit ( LosArchMmu archMmu,
VADDR_T virtTtb 
)

在文件 los_arch_mmu.c537 行定义.

538{
539#ifdef LOSCFG_KERNEL_VM
540 if (OsAllocAsid(&archMmu->asid) != LOS_OK) {//分配一个asid,ASID可用来唯一标识进程空间
541 VM_ERR("alloc arch mmu asid failed");//地址空间标识码(address-space identifier,ASID)为CP15协处理器 C13寄存器
542 return FALSE;
543 }
544#endif
545
546#ifndef LOSCFG_PAGE_TABLE_FINE_LOCK
547 LOS_SpinInit(&archMmu->lock);
548#endif
549 LOS_ListInit(&archMmu->ptList);//初始化页表,双循环进程所有物理页框 LOS_ListAdd(&processCB->vmSpace->archMmu.ptList, &(vmPage->node));
550 archMmu->virtTtb = virtTtb;//为L1页表在内存位置 section(".bss.prebss.translation_table") UINT8 g_firstPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS]
551 archMmu->physTtb = (VADDR_T)(UINTPTR)virtTtb - KERNEL_ASPACE_BASE + SYS_MEM_BASE;// TTB寄存器是CP15协处理器的C2寄存器,存页表的基地址
552 //SYS_MEM_BASE = 0x80000000 KERNEL_ASPACE_BASE = 0x40000000 见于 ..\vendor\hi3516dv300\config\board\include\board.h
553 //archMmu->physTtb = (VADDR_T)(UINTPTR)virtTtb + 0x40000000;
554 return TRUE;
555}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
STATUS_T OsAllocAsid(UINT32 *asid)
Definition: los_asid.c:78
VOID LOS_SpinInit(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:37
unsigned long VADDR_T
Definition: los_typedef.h:208
unsigned long UINTPTR
Definition: los_typedef.h:68
SPIN_LOCK_S lock
Definition: los_arch_mmu.h:88
函数调用图:
这是这个函数的调用关系图:

◆ OsArchMmuInitPerCPU()

VOID OsArchMmuInitPerCPU ( VOID  )

在文件 los_arch_mmu.c1243 行定义.

1244{
1245 UINT32 n = __builtin_clz(KERNEL_ASPACE_BASE) + 1;
1246 UINT32 ttbcr = MMU_DESCRIPTOR_TTBCR_PD0 | n;
1247
1248 OsArmWriteTtbr1(OsArmReadTtbr0());//读取地址转换表基地址
1249 ISB;//指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
1250 OsArmWriteTtbcr(ttbcr);
1251 ISB;
1252 OsArmWriteTtbr0(0);
1253 ISB;
1254}
STATIC INLINE UINT32 OsArmReadTtbr0(VOID)
Definition: arm.h:91
STATIC INLINE VOID OsArmWriteTtbr1(UINT32 val)
Definition: arm.h:111
函数调用图:
这是这个函数的调用关系图:

◆ OsCvtPte2AccessFlagsToMMUFlags()

STATIC UINT32 OsCvtPte2AccessFlagsToMMUFlags ( UINT32  flags)

在文件 los_arch_mmu.c752 行定义.

753{
754 UINT32 mmuFlags = 0;
755
756 switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
757 case 0:
758 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
759 break;
760 case VM_MAP_REGION_FLAG_PERM_READ:
761 case VM_MAP_REGION_FLAG_PERM_USER:
762 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_NA;
763 break;
764 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
765 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_RO;
766 break;
767 case VM_MAP_REGION_FLAG_PERM_WRITE:
768 case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
769 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_NA;
770 break;
771 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
772 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
773 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_RW;
774 break;
775 default:
776 break;
777 }
778 return mmuFlags;
779}
这是这个函数的调用关系图:

◆ OsCvtPte2AttsToFlags()

STATIC VOID OsCvtPte2AttsToFlags ( PTE_T  l1Entry,
PTE_T  l2Entry,
UINT32 flags 
)

在文件 los_arch_mmu.c221 行定义.

222{
223 *flags = 0;
224 /* NS flag is only present on L1 entry */
225 if (l1Entry & MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE) {
226 *flags |= VM_MAP_REGION_FLAG_NS;
227 }
228
229 switch (l2Entry & MMU_DESCRIPTOR_L2_TEX_TYPE_MASK) {
230 case MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED:
231 *flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
232 break;
233 case MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE:
234 *flags |= VM_MAP_REGION_FLAG_UNCACHED;
235 break;
236 case MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED:
237 case MMU_DESCRIPTOR_L2_TYPE_DEVICE_NON_SHARED:
238 *flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
239 break;
240 default:
241 break;
242 }
243
244 *flags |= VM_MAP_REGION_FLAG_PERM_READ;
245
246 switch (l2Entry & MMU_DESCRIPTOR_L2_AP_MASK) {
247 case MMU_DESCRIPTOR_L2_AP_P_RO_U_NA:
248 break;
249 case MMU_DESCRIPTOR_L2_AP_P_RW_U_NA:
250 *flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
251 break;
252 case MMU_DESCRIPTOR_L2_AP_P_RO_U_RO:
253 *flags |= VM_MAP_REGION_FLAG_PERM_USER;
254 break;
255 case MMU_DESCRIPTOR_L2_AP_P_RW_U_RW:
256 *flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
257 break;
258 default:
259 break;
260 }
261 if ((l2Entry & MMU_DESCRIPTOR_L2_TYPE_MASK) != MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN) {
262 *flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
263 }
264}
这是这个函数的调用关系图:

◆ OsCvtPte2CacheFlagsToMMUFlags()

STATIC UINT32 OsCvtPte2CacheFlagsToMMUFlags ( UINT32  flags)

在文件 los_arch_mmu.c726 行定义.

727{
728 UINT32 mmuFlags = 0;
729
730 switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
731 case VM_MAP_REGION_FLAG_CACHED:
732#ifdef LOSCFG_KERNEL_SMP
733 mmuFlags |= MMU_DESCRIPTOR_L2_SHAREABLE;
734#endif
735 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
736 break;
737 case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
738 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED;
739 break;
740 case VM_MAP_REGION_FLAG_UNCACHED:
741 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE;
742 break;
743 case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
744 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED;
745 break;
746 default:
747 return LOS_ERRNO_VM_INVALID_ARGS;
748 }
749 return mmuFlags;
750}
这是这个函数的调用关系图:

◆ OsCvtPte2FlagsToAttrs()

STATIC UINT32 OsCvtPte2FlagsToAttrs ( UINT32  flags)

在文件 los_arch_mmu.c782 行定义.

783{
784 UINT32 mmuFlags;
785
786 mmuFlags = OsCvtPte2CacheFlagsToMMUFlags(flags);
787 if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
788 return mmuFlags;
789 }
790
791 mmuFlags |= OsCvtPte2AccessFlagsToMMUFlags(flags);
792
793 if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
794 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN;
795 } else {
796 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE;
797 }
798
799 if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
800 mmuFlags |= MMU_DESCRIPTOR_L2_NON_GLOBAL;
801 }
802
803 return mmuFlags;
804}
STATIC UINT32 OsCvtPte2CacheFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:726
STATIC UINT32 OsCvtPte2AccessFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:752
函数调用图:
这是这个函数的调用关系图:

◆ OsCvtSecAccessFlagsToMMUFlags()

STATIC UINT32 OsCvtSecAccessFlagsToMMUFlags ( UINT32  flags)

在文件 los_arch_mmu.c379 行定义.

380{
381 UINT32 mmuFlags = 0;
382
383 switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
384 case 0:
385 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
386 break;
387 case VM_MAP_REGION_FLAG_PERM_READ:
388 case VM_MAP_REGION_FLAG_PERM_USER:
389 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_NA;
390 break;
391 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
392 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_RO;
393 break;
394 case VM_MAP_REGION_FLAG_PERM_WRITE:
395 case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
396 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_NA;
397 break;
398 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
399 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
400 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_RW;
401 break;
402 default:
403 break;
404 }
405 return mmuFlags;
406}
这是这个函数的调用关系图:

◆ OsCvtSecAttsToFlags()

STATIC VOID OsCvtSecAttsToFlags ( PTE_T  l1Entry,
UINT32 flags 
)

在文件 los_arch_mmu.c437 行定义.

438{
439 *flags = 0;
440 if (l1Entry & MMU_DESCRIPTOR_L1_SECTION_NON_SECURE) {
441 *flags |= VM_MAP_REGION_FLAG_NS;
442 }
443
444 switch (l1Entry & MMU_DESCRIPTOR_L1_TEX_TYPE_MASK) {
445 case MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED:
446 *flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
447 break;
448 case MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE:
449 *flags |= VM_MAP_REGION_FLAG_UNCACHED;
450 break;
451 case MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED:
452 case MMU_DESCRIPTOR_L1_TYPE_DEVICE_NON_SHARED:
453 *flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
454 break;
455 default:
456 break;
457 }
458
459 *flags |= VM_MAP_REGION_FLAG_PERM_READ;
460
461 switch (l1Entry & MMU_DESCRIPTOR_L1_AP_MASK) {
462 case MMU_DESCRIPTOR_L1_AP_P_RO_U_NA:
463 break;
464 case MMU_DESCRIPTOR_L1_AP_P_RW_U_NA:
465 *flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
466 break;
467 case MMU_DESCRIPTOR_L1_AP_P_RO_U_RO:
468 *flags |= VM_MAP_REGION_FLAG_PERM_USER;
469 break;
470 case MMU_DESCRIPTOR_L1_AP_P_RW_U_RW:
471 *flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
472 break;
473 default:
474 break;
475 }
476
477 if (!(l1Entry & MMU_DESCRIPTOR_L1_SECTION_XN)) {
478 *flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
479 }
480}
这是这个函数的调用关系图:

◆ OsCvtSecCacheFlagsToMMUFlags()

STATIC UINT32 OsCvtSecCacheFlagsToMMUFlags ( UINT32  flags)

在文件 los_arch_mmu.c353 行定义.

354{
355 UINT32 mmuFlags = 0;
356
357 switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
358 case VM_MAP_REGION_FLAG_CACHED:
359 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
360#ifdef LOSCFG_KERNEL_SMP
361 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_SHAREABLE;
362#endif
363 break;
364 case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
365 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED;
366 break;
367 case VM_MAP_REGION_FLAG_UNCACHED:
368 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE;
369 break;
370 case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
371 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED;
372 break;
373 default:
374 return LOS_ERRNO_VM_INVALID_ARGS;
375 }
376 return mmuFlags;
377}
这是这个函数的调用关系图:

◆ OsCvtSecFlagsToAttrs()

STATIC UINT32 OsCvtSecFlagsToAttrs ( UINT32  flags)

在文件 los_arch_mmu.c409 行定义.

410{
411 UINT32 mmuFlags;
412
413 mmuFlags = OsCvtSecCacheFlagsToMMUFlags(flags);
414 if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
415 return mmuFlags;
416 }
417
418 mmuFlags |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT;
419
420 mmuFlags |= OsCvtSecAccessFlagsToMMUFlags(flags);
421
422 if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
423 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_XN;
424 }
425
426 if (flags & VM_MAP_REGION_FLAG_NS) {
427 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_SECURE;
428 }
429
430 if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
431 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_GLOBAL;
432 }
433
434 return mmuFlags;
435}
STATIC UINT32 OsCvtSecAccessFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:379
STATIC UINT32 OsCvtSecCacheFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:353
函数调用图:
这是这个函数的调用关系图:

◆ OsGetL2Table()

STATIC STATUS_T OsGetL2Table ( LosArchMmu archMmu,
UINT32  l1Index,
paddr_t ppa 
)

获取L2页表,分配L2表(需物理内存)

在文件 los_arch_mmu.c686 行定义.

687{
688 UINT32 index;
689 PTE_T ttEntry;
690 VADDR_T *kvaddr = NULL;
691 UINT32 l2Offset = (MMU_DESCRIPTOR_L2_SMALL_SIZE / MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) *
692 (l1Index & (MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE - 1));//计算偏移量,因为一个L2表最大是1K,而一个物理页框是4K,内核不铺张浪费把4个L2表放在一个页框中
693 /* lookup an existing l2 page table *///查询已存在的L2表
694 for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) {
695 ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index];
696 if ((ttEntry & MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) {
697 *ppa = (PADDR_T)ROUNDDOWN(MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(ttEntry), MMU_DESCRIPTOR_L2_SMALL_SIZE) +
698 l2Offset;
699 return LOS_OK;
700 }
701 }
702
703#ifdef LOSCFG_KERNEL_VM
704 /* not found: allocate one (paddr) */
705 LosVmPage *vmPage = LOS_PhysPageAlloc();
706 if (vmPage == NULL) {
707 VM_ERR("have no memory to save l2 page");
708 return LOS_ERRNO_VM_NO_MEMORY;
709 }
710 LOS_ListAdd(&archMmu->ptList, &vmPage->node);
711 kvaddr = OsVmPageToVaddr(vmPage);
712#else
713 kvaddr = LOS_MemAlloc(OS_SYS_MEM_ADDR, MMU_DESCRIPTOR_L2_SMALL_SIZE);
714 if (kvaddr == NULL) {
715 VM_ERR("have no memory to save l2 page");
716 return LOS_ERRNO_VM_NO_MEMORY;
717 }
718#endif
719 (VOID)memset_s(kvaddr, MMU_DESCRIPTOR_L2_SMALL_SIZE, 0, MMU_DESCRIPTOR_L2_SMALL_SIZE);
720
721 /* get physical address */
722 *ppa = OsKVaddrToPaddr((VADDR_T)kvaddr) + l2Offset;
723 return LOS_OK;
724}
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
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
PADDR_T OsKVaddrToPaddr(VADDR_T kvaddr)
Definition: los_vm_phys.c:519
LosVmPage * LOS_PhysPageAlloc(VOID)
申请一个物理页
Definition: los_vm_phys.c:566
VOID * OsVmPageToVaddr(LosVmPage *page)
通过page获取内核空间的虚拟地址 参考OsArchMmuInit #define SYS_MEM_BASE DDR_MEM_ADDR /* physical memory base 物理地址的起始...
Definition: los_vm_phys.c:288
LOS_DL_LIST node
Definition: los_vm_page.h:54
函数调用图:
这是这个函数的调用关系图:

◆ OsGetPte1Lock()

STATIC SPIN_LOCK_S * OsGetPte1Lock ( LosArchMmu archMmu,
PADDR_T  paddr,
UINT32 intSave 
)

在文件 los_arch_mmu.c130 行定义.

131{
132 return OsGetPteLock(archMmu, paddr, intSave);
133}
这是这个函数的调用关系图:

◆ OsGetPte1LockTmp()

STATIC SPIN_LOCK_S * OsGetPte1LockTmp ( LosArchMmu archMmu,
PADDR_T  paddr,
UINT32 intSave 
)

在文件 los_arch_mmu.c143 行定义.

144{
145 SPIN_LOCK_S *spinLock = NULL;
146#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
147 spinLock = OsGetPteLock(archMmu, paddr, intSave);
148#else
149 (VOID)archMmu;
150 (VOID)paddr;
151 (VOID)intSave;
152#endif
153 return spinLock;
154}
这是这个函数的调用关系图:

◆ OsGetPte2BasePtr()

STATIC INLINE PTE_T * OsGetPte2BasePtr ( PTE_T  pte1)

获取页表基地址

在文件 los_arch_mmu.c180 行定义.

181{
182 PADDR_T pa = MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1);
183 return LOS_PaddrToKVaddr(pa);
184}
VADDR_T * LOS_PaddrToKVaddr(PADDR_T paddr)
通过物理地址获取内核虚拟地址
Definition: los_vm_phys.c:688
函数调用图:
这是这个函数的调用关系图:

◆ OsGetPte2Lock()

STATIC INLINE SPIN_LOCK_S * OsGetPte2Lock ( LosArchMmu archMmu,
PTE_T  pte1,
UINT32 intSave 
)

在文件 los_arch_mmu.c169 行定义.

170{
171 PADDR_T pa = MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1);
172 return OsGetPteLock(archMmu, pa, intSave);
173}
这是这个函数的调用关系图:

◆ OsGFirstTableGet()

VADDR_T * OsGFirstTableGet ( VOID  )

在文件 los_arch_mmu.c186 行定义.

187{
188 return (VADDR_T *)g_firstPageTable;
189}
这是这个函数的调用关系图:

◆ OsInitMappingStartUp()

VOID OsInitMappingStartUp ( VOID  )

OsInitMappingStartUp 开始初始化mmu

返回
参见

在文件 los_arch_mmu.c1263 行定义.

1264{
1265 OsArmInvalidateTlbBarrier();//使TLB失效
1266
1267 OsSwitchTmpTTB();//切换到临时TTB ,请想想为何要切换到临时 @note_thinking
1268
1269 OsSetKSectionAttr(KERNEL_VMM_BASE, FALSE);//设置内核空间属性
1270 OsSetKSectionAttr(UNCACHED_VMM_BASE, TRUE);//设置未缓存空间属性
1272}
STATIC VOID OsSetKSectionAttr(UINTPTR virtAddr, BOOL uncached)
设置内核空间段属性,可看出内核空间是固定映射到物理地址
STATIC VOID OsKSectionNewAttrEnable(VOID)
STATIC VOID OsSwitchTmpTTB(VOID)
切换临时页表
函数调用图:
这是这个函数的调用关系图:

◆ OsKSectionNewAttrEnable()

STATIC VOID OsKSectionNewAttrEnable ( VOID  )

在文件 los_arch_mmu.c1222 行定义.

1223{
1224 LosVmSpace *kSpace = LOS_GetKVmSpace();
1225 paddr_t oldTtPhyBase;
1226
1227 kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;
1228 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
1229
1230 /* we need free tmp ttbase */
1231 oldTtPhyBase = OsArmReadTtbr0();//读取TTB值
1232 oldTtPhyBase = oldTtPhyBase & MMU_DESCRIPTOR_L2_SMALL_FRAME;
1233 OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);//内核页表基地址写入CP15 c2(TTB寄存器)
1234 ISB;
1235
1236 /* we changed page table entry, so we need to clean TLB here */
1237 OsCleanTLB();//清空TLB缓冲区
1238
1239 (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)(UINTPTR)(oldTtPhyBase - SYS_MEM_BASE + KERNEL_VMM_BASE));//释放内存池
1240}
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
STATIC INLINE VOID OsCleanTLB(VOID)
Definition: los_tlb_v6.h:79
unsigned long paddr_t
Definition: los_typedef.h:209
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosArchMmu archMmu
Definition: los_vm_map.h:157
函数调用图:
这是这个函数的调用关系图:

◆ OsMapL1PTE()

STATIC UINT32 OsMapL1PTE ( MmuMapInfo mmuMapInfo,
PTE_T l1Entry,
UINT32 count 
)

在文件 los_arch_mmu.c806 行定义.

807{
808 PADDR_T pte2Base = 0;
809 PADDR_T pte1Paddr;
810 SPIN_LOCK_S *pte1Lock = NULL;
811 SPIN_LOCK_S *pte2Lock = NULL;
812 PTE_T *pte2BasePtr = NULL;
813 UINT32 saveCounts, archFlags, pte1IntSave, pte2IntSave;
814
815 pte1Paddr = OsGetPte1Paddr(mmuMapInfo->archMmu->physTtb, *mmuMapInfo->vaddr);
816 pte1Lock = OsGetPte1Lock(mmuMapInfo->archMmu, pte1Paddr, &pte1IntSave);
817 if (!OsIsPte1Invalid(*l1Entry)) {
818 OsUnlockPte1(pte1Lock, pte1IntSave);
819 return 0;
820 }
821 if (OsGetL2Table(mmuMapInfo->archMmu, OsGetPte1Index(*mmuMapInfo->vaddr), &pte2Base) != LOS_OK) {
822 LOS_Panic("%s %d, failed to allocate pagetable\n", __FUNCTION__, __LINE__);
823 }
824
825 *l1Entry = pte2Base | MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE;
826 if (*mmuMapInfo->flags & VM_MAP_REGION_FLAG_NS) {
827 *l1Entry |= MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE;
828 }
829 *l1Entry &= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_MASK;
830 *l1Entry |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT; // use client AP
831 OsSavePte1(OsGetPte1Ptr(mmuMapInfo->archMmu->virtTtb, *mmuMapInfo->vaddr), *l1Entry);
832 OsUnlockPte1(pte1Lock, pte1IntSave);
833
834 pte2Lock = OsGetPte2Lock(mmuMapInfo->archMmu, *l1Entry, &pte2IntSave);
835 if (pte2Lock == NULL) {
836 LOS_Panic("pte2 should not be null!\n");
837 }
838 pte2BasePtr = (PTE_T *)LOS_PaddrToKVaddr(pte2Base);
839
840 /* compute the arch flags for L2 4K pages */
841 archFlags = OsCvtPte2FlagsToAttrs(*mmuMapInfo->flags);
842 saveCounts = OsSavePte2Continuous(pte2BasePtr, OsGetPte2Index(*mmuMapInfo->vaddr), *mmuMapInfo->paddr | archFlags,
843 *count);
844 OsUnlockPte2(pte2Lock, pte2IntSave);
845 *mmuMapInfo->paddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
846 *mmuMapInfo->vaddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
847 *count -= saveCounts;
848 return saveCounts;
849}
STATIC STATUS_T OsGetL2Table(LosArchMmu *archMmu, UINT32 l1Index, paddr_t *ppa)
获取L2页表,分配L2表(需物理内存)
Definition: los_arch_mmu.c:686
STATIC INLINE VOID OsUnlockPte2(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:175
STATIC UINT32 OsCvtPte2FlagsToAttrs(UINT32 flags)
Definition: los_arch_mmu.c:782
STATIC INLINE VOID OsUnlockPte1(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:135
STATIC SPIN_LOCK_S * OsGetPte1Lock(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
Definition: los_arch_mmu.c:130
STATIC INLINE SPIN_LOCK_S * OsGetPte2Lock(LosArchMmu *archMmu, PTE_T pte1, UINT32 *intSave)
Definition: los_arch_mmu.c:169
STATIC INLINE VOID OsSavePte1(PTE_T *pte1Ptr, PTE_T pte1)
PTE(Page Table Entry),页表条目,保存L1页表项至L1页表
Definition: los_pte_ops.h:50
STATIC INLINE UINT32 OsSavePte2Continuous(PTE_T *pte2BasePtr, UINT32 index, PTE_T pte2, UINT32 count)
Definition: los_pte_ops.h:124
STATIC INLINE PADDR_T OsGetPte1Paddr(PADDR_T PhysTtb, vaddr_t va)
Definition: los_pte_ops.h:72
STATIC INLINE UINT32 OsGetPte1Index(vaddr_t va)
获取L1 页表项索引
Definition: los_pte_ops.h:62
UINT32 * flags
Definition: los_arch_mmu.c:93
函数调用图:
这是这个函数的调用关系图:

◆ OsMapL2PageContinous()

STATIC UINT32 OsMapL2PageContinous ( MmuMapInfo mmuMapInfo,
PTE_T pte1,
UINT32 count 
)

在文件 los_arch_mmu.c851 行定义.

852{
853 PTE_T *pte2BasePtr = NULL;
854 UINT32 archFlags;
855 UINT32 saveCounts;
856 UINT32 intSave;
857 SPIN_LOCK_S *lock = NULL;
858
859 lock = OsGetPte2Lock(mmuMapInfo->archMmu, *pte1, &intSave);
860 if (lock == NULL) {
861 return 0;
862 }
863 pte2BasePtr = OsGetPte2BasePtr(*pte1);
864 if (pte2BasePtr == NULL) {
865 OsUnlockPte2(lock, intSave);
866 return 0;
867 }
868
869 /* compute the arch flags for L2 4K pages */
870 archFlags = OsCvtPte2FlagsToAttrs(*mmuMapInfo->flags);
871 saveCounts = OsSavePte2Continuous(pte2BasePtr, OsGetPte2Index(*mmuMapInfo->vaddr), *mmuMapInfo->paddr | archFlags,
872 *count);
873 OsUnlockPte2(lock, intSave);
874 *mmuMapInfo->paddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
875 *mmuMapInfo->vaddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
876 *count -= saveCounts;
877 return saveCounts;
878}
函数调用图:
这是这个函数的调用关系图:

◆ OsMapParamCheck()

STATIC INT32 OsMapParamCheck ( UINT32  flags,
VADDR_T  vaddr,
PADDR_T  paddr 
)

在文件 los_arch_mmu.c204 行定义.

205{
206#if !WITH_ARCH_MMU_PICK_SPOT
207 if (flags & VM_MAP_REGION_FLAG_NS) {
208 /* WITH_ARCH_MMU_PICK_SPOT is required to support NS memory */
209 LOS_Panic("NS mem is not supported\n");
210 }
211#endif
212
213 /* paddr and vaddr must be aligned */
214 if (!MMU_DESCRIPTOR_IS_L2_SIZE_ALIGNED(vaddr) || !MMU_DESCRIPTOR_IS_L2_SIZE_ALIGNED(paddr)) {
215 return LOS_ERRNO_VM_INVALID_ARGS;
216 }
217
218 return 0;
219}
函数调用图:
这是这个函数的调用关系图:

◆ OsMapSection()

STATIC UINT32 OsMapSection ( MmuMapInfo mmuMapInfo,
UINT32 count 
)

OsMapSection section页表格式项映射

参数
archMmu
count
flags
paddr
vaddr
返回
参见

在文件 los_arch_mmu.c666 行定义.

667{
668 UINT32 mmuFlags = 0;
669 UINT32 intSave;
670 PADDR_T pte1Paddr;
671 SPIN_LOCK_S *lock = NULL;
672
673 mmuFlags |= OsCvtSecFlagsToAttrs(*mmuMapInfo->flags);
674 pte1Paddr = OsGetPte1Paddr(mmuMapInfo->archMmu->physTtb, *mmuMapInfo->vaddr);
675 lock = OsGetPte1Lock(mmuMapInfo->archMmu, pte1Paddr, &intSave);
676 OsSavePte1(OsGetPte1Ptr(mmuMapInfo->archMmu->virtTtb, *mmuMapInfo->vaddr),
677 OsTruncPte1(*mmuMapInfo->paddr) | mmuFlags | MMU_DESCRIPTOR_L1_TYPE_SECTION);
678 OsUnlockPte1(lock, intSave);
679 *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
680 *mmuMapInfo->vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
681 *mmuMapInfo->paddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
682
683 return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
684}
STATIC UINT32 OsCvtSecFlagsToAttrs(UINT32 flags)
Definition: los_arch_mmu.c:409
STATIC INLINE ADDR_T OsTruncPte1(ADDR_T addr)
生成 L1 section格式项地址
Definition: los_pte_ops.h:57
函数调用图:
这是这个函数的调用关系图:

◆ OsPutL2Table()

STATIC VOID OsPutL2Table ( const LosArchMmu archMmu,
UINT32  l1Index,
paddr_t  l2Paddr 
)

在文件 los_arch_mmu.c266 行定义.

267{
268 UINT32 index;
269 PTE_T ttEntry;
270 /* check if any l1 entry points to this l2 table */
271 for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) {
272 ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index];
273 if ((ttEntry & MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) {
274 return;
275 }
276 }
277#ifdef LOSCFG_KERNEL_VM
278 /* we can free this l2 table */
279 LosVmPage *vmPage = LOS_VmPageGet(l2Paddr);
280 if (vmPage == NULL) {
281 LOS_Panic("bad page table paddr %#x\n", l2Paddr);
282 return;
283 }
284
285 LOS_ListDelete(&vmPage->node);
286 LOS_PhysPageFree(vmPage);
287#else
288 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, LOS_PaddrToKVaddr(l2Paddr));
289#endif
290}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
Definition: los_vm_page.c:120
函数调用图:
这是这个函数的调用关系图:

◆ OsSetKSectionAttr()

STATIC VOID OsSetKSectionAttr ( UINTPTR  virtAddr,
BOOL  uncached 
)

设置内核空间段属性,可看出内核空间是固定映射到物理地址

在文件 los_arch_mmu.c1127 行定义.

1128{
1129 UINT32 offset = virtAddr - KERNEL_VMM_BASE;
1130 /* every section should be page aligned */
1131 UINTPTR textStart = (UINTPTR)&__text_start + offset;
1132 UINTPTR textEnd = (UINTPTR)&__text_end + offset;
1133 UINTPTR rodataStart = (UINTPTR)&__rodata_start + offset;
1134 UINTPTR rodataEnd = (UINTPTR)&__rodata_end + offset;
1135 UINTPTR ramDataStart = (UINTPTR)&__ram_data_start + offset;
1136 UINTPTR bssEnd = (UINTPTR)&__bss_end + offset;
1137 UINT32 bssEndBoundary = ROUNDUP(bssEnd, MB);
1138 LosArchMmuInitMapping mmuKernelMappings[] = {//初始化映射关系
1139 { //映射代码区
1140 .phys = SYS_MEM_BASE + textStart - virtAddr,
1141 .virt = textStart,//内核代码区
1142 .size = ROUNDUP(textEnd - textStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//代码区大小
1143 .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE,//代码段只读,可执行
1144 .name = "kernel_text"
1145 },
1146 { //映射只读数据
1147 .phys = SYS_MEM_BASE + rodataStart - virtAddr,
1148 .virt = rodataStart,//内核常量区
1149 .size = ROUNDUP(rodataEnd - rodataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//4K对齐
1150 .flags = VM_MAP_REGION_FLAG_PERM_READ,//常量段只读
1151 .name = "kernel_rodata"
1152 },
1153 { //映射全局未初始化区
1154 .phys = SYS_MEM_BASE + ramDataStart - virtAddr,
1155 .virt = ramDataStart,
1156 .size = ROUNDUP(bssEndBoundary - ramDataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
1157 .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE,//全局变量区可读可写
1158 .name = "kernel_data_bss"
1159 }
1160 };
1161 LosVmSpace *kSpace = LOS_GetKVmSpace();//获取内核空间
1162 status_t status;
1163 UINT32 length;
1164 INT32 i;
1165 LosArchMmuInitMapping *kernelMap = NULL;//内核映射
1166 UINT32 kmallocLength;
1167 UINT32 flags;
1168
1169 /* use second-level mapping of default READ and WRITE | 使用二级映射*/
1170 kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;//__attribute__((section(".bss.prebss.translation_table"))) UINT8 g_firstPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS];
1171 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);//通过TTB虚拟地址查询TTB物理地址
1172 status = LOS_ArchMmuUnmap(&kSpace->archMmu, virtAddr,
1173 (bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT);
1174 if (status != ((bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1175 VM_ERR("unmap failed, status: %d", status);
1176 return;
1177 }
1178
1179 flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE | VM_MAP_REGION_FLAG_PERM_EXECUTE;
1180 if (uncached) {
1181 flags |= VM_MAP_REGION_FLAG_UNCACHED;
1182 }
1183 status = LOS_ArchMmuMap(&kSpace->archMmu, virtAddr, SYS_MEM_BASE,
1184 (textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
1185 flags);
1186 if (status != ((textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1187 VM_ERR("mmap failed, status: %d", status);
1188 return;
1189 }
1190
1191 length = sizeof(mmuKernelMappings) / sizeof(LosArchMmuInitMapping);
1192 for (i = 0; i < length; i++) {
1193 kernelMap = &mmuKernelMappings[i];
1194 if (uncached) {
1195 kernelMap->flags |= VM_MAP_REGION_FLAG_UNCACHED;
1196 }
1197 status = LOS_ArchMmuMap(&kSpace->archMmu, kernelMap->virt, kernelMap->phys,
1198 kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT, kernelMap->flags);
1199 if (status != (kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1200 VM_ERR("mmap failed, status: %d", status);
1201 return;
1202 }
1203 LOS_VmSpaceReserve(kSpace, kernelMap->size, kernelMap->virt);//保留区
1204 }
1205 //将剩余空间映射好
1206 kmallocLength = virtAddr + SYS_MEM_SIZE_DEFAULT - bssEndBoundary;
1207 flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE;
1208 if (uncached) {
1209 flags |= VM_MAP_REGION_FLAG_UNCACHED;
1210 }
1211 status = LOS_ArchMmuMap(&kSpace->archMmu, bssEndBoundary,
1212 SYS_MEM_BASE + bssEndBoundary - virtAddr,
1213 kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
1214 flags);
1215 if (status != (kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1216 VM_ERR("mmap failed, status: %d", status);
1217 return;
1218 }
1219 LOS_VmSpaceReserve(kSpace, kmallocLength, bssEndBoundary);
1220}
CHAR __text_end
代码区结束地址
CHAR __rodata_end
ROM结束地址
CHAR __ram_data_start
RAM开始地址 可读可写
CHAR __bss_end
bss结束地址 attribute((section(".__bss_end")));
CHAR __text_start
代码区开始地址
CHAR __rodata_start
ROM开始地址 只读
int status_t
Definition: los_typedef.h:205
STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr)
VADDR_T virt
虚拟地址
Definition: los_vm_boot.h:54
unsigned int flags
标识 读/写/.. VM_MAP_REGION_FLAG_PERM_*
Definition: los_vm_boot.h:56
PADDR_T phys
物理地址
Definition: los_vm_boot.h:53
size_t size
大小
Definition: los_vm_boot.h:55
函数调用图:
这是这个函数的调用关系图:

◆ OsSwitchTmpTTB()

STATIC VOID OsSwitchTmpTTB ( VOID  )

切换临时页表

在文件 los_arch_mmu.c1098 行定义.

1099{
1100 PTE_T *tmpTtbase = NULL;
1101 errno_t err;
1102 LosVmSpace *kSpace = LOS_GetKVmSpace();
1103
1104 /* ttbr address should be 16KByte align | 页表应该 16Kb对齐,因为 TTB寄存器的低14位为 0 */
1105 tmpTtbase = LOS_MemAllocAlign(m_aucSysMem0, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
1106 MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);//分配页表
1107 if (tmpTtbase == NULL) {
1108 VM_ERR("memory alloc failed");
1109 return;
1110 }
1111
1112 kSpace->archMmu.virtTtb = tmpTtbase;
1113 err = memcpy_s(kSpace->archMmu.virtTtb, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
1114 g_firstPageTable, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);
1115 if (err != EOK) {
1116 (VOID)LOS_MemFree(m_aucSysMem0, tmpTtbase);
1117 kSpace->archMmu.virtTtb = (VADDR_T *)g_firstPageTable;
1118 VM_ERR("memcpy failed, errno: %d", err);
1119 return;
1120 }
1121 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
1122 OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);
1123 ISB;
1124}
VOID * LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
从指定内存池中申请size长度的内存且地址按boundary字节对齐的内存
Definition: los_memory.c:1150
函数调用图:
这是这个函数的调用关系图:

◆ OsTryUnmapL1PTE()

STATIC VOID OsTryUnmapL1PTE ( LosArchMmu archMmu,
PTE_T l1Entry,
vaddr_t  vaddr,
UINT32  scanIndex,
UINT32  scanCount 
)

在文件 los_arch_mmu.c292 行定义.

293{
294 /*
295 * Check if all pages related to this l1 entry are deallocated.
296 * We only need to check pages that we did not clear above starting
297 * from scanIndex and wrapped around SECTION.
298 */
299 UINT32 l1Index;
300 PTE_T *pte2BasePtr = NULL;
301 SPIN_LOCK_S *pte1Lock = NULL;
302 SPIN_LOCK_S *pte2Lock = NULL;
303 UINT32 pte1IntSave;
304 UINT32 pte2IntSave;
305 PTE_T pte1Val;
306 PADDR_T pte1Paddr;
307
308 pte1Paddr = OsGetPte1Paddr(archMmu->physTtb, vaddr);
309 pte2Lock = OsGetPte2Lock(archMmu, *l1Entry, &pte2IntSave);
310 if (pte2Lock == NULL) {
311 return;
312 }
313 pte2BasePtr = OsGetPte2BasePtr(*l1Entry);
314 if (pte2BasePtr == NULL) {
315 OsUnlockPte2(pte2Lock, pte2IntSave);
316 return;
317 }
318
319 while (scanCount) {
320 if (scanIndex == MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
321 scanIndex = 0;
322 }
323 if (pte2BasePtr[scanIndex++]) {
324 break;
325 }
326 scanCount--;
327 }
328
329 if (!scanCount) {
330 /*
331 * The pte1 of kprocess is placed in kernel image when compiled. So the pte1Lock will be null.
332 * There is no situation to simultaneous access the pte1 of kprocess.
333 */
334 pte1Lock = OsGetPte1LockTmp(archMmu, pte1Paddr, &pte1IntSave);
335 if (!OsIsPte1PageTable(*l1Entry)) {
336 OsUnlockPte1Tmp(pte1Lock, pte1IntSave);
337 OsUnlockPte2(pte2Lock, pte2IntSave);
338 return;
339 }
340 pte1Val = *l1Entry;
341 /* we can kill l1 entry */
342 OsClearPte1(l1Entry);
343 l1Index = OsGetPte1Index(vaddr);
344 OsArmInvalidateTlbMvaNoBarrier(l1Index << MMU_DESCRIPTOR_L1_SMALL_SHIFT);
345
346 /* try to free l2 page itself */
347 OsPutL2Table(archMmu, l1Index, MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1Val));
348 OsUnlockPte1Tmp(pte1Lock, pte1IntSave);
349 }
350 OsUnlockPte2(pte2Lock, pte2IntSave);
351}
STATIC INLINE VOID OsUnlockPte1Tmp(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:156
STATIC VOID OsPutL2Table(const LosArchMmu *archMmu, UINT32 l1Index, paddr_t l2Paddr)
Definition: los_arch_mmu.c:266
STATIC SPIN_LOCK_S * OsGetPte1LockTmp(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
Definition: los_arch_mmu.c:143
STATIC INLINE VOID OsClearPte1(PTE_T *pte1Ptr)
Definition: los_pte_ops.h:67
STATIC INLINE VOID OsArmInvalidateTlbMvaNoBarrier(VADDR_T va)
Definition: los_tlb_v6.h:59
函数调用图:
这是这个函数的调用关系图:

◆ OsUnlockPte1()

STATIC INLINE VOID OsUnlockPte1 ( SPIN_LOCK_S lock,
UINT32  intSave 
)

在文件 los_arch_mmu.c135 行定义.

136{
137 if (lock == NULL) {
138 return;
139 }
140 LOS_SpinUnlockRestore(lock, intSave);
141}
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_spinlock.c:108
函数调用图:
这是这个函数的调用关系图:

◆ OsUnlockPte1Tmp()

STATIC INLINE VOID OsUnlockPte1Tmp ( SPIN_LOCK_S lock,
UINT32  intSave 
)

在文件 los_arch_mmu.c156 行定义.

157{
158#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
159 if (lock == NULL) {
160 return;
161 }
162 LOS_SpinUnlockRestore(lock, intSave);
163#else
164 (VOID)lock;
165 (VOID)intSave;
166#endif
167}
函数调用图:
这是这个函数的调用关系图:

◆ OsUnlockPte2()

STATIC INLINE VOID OsUnlockPte2 ( SPIN_LOCK_S lock,
UINT32  intSave 
)

在文件 los_arch_mmu.c175 行定义.

176{
177 return OsUnlockPte1(lock, intSave);
178}
函数调用图:
这是这个函数的调用关系图:

◆ OsUnmapL1Invalid()

STATIC INLINE UINT32 OsUnmapL1Invalid ( vaddr_t vaddr,
UINT32 count 
)

解除L1表的映射关系

在文件 los_arch_mmu.c192 行定义.

193{
194 UINT32 unmapCount;
195
196 unmapCount = MIN2((MMU_DESCRIPTOR_L1_SMALL_SIZE - (*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE)) >>
197 MMU_DESCRIPTOR_L2_SMALL_SHIFT, *count);
198 *vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
199 *count -= unmapCount;
200
201 return unmapCount;
202}
这是这个函数的调用关系图:

◆ OsUnmapL2PTE()

STATIC UINT32 OsUnmapL2PTE ( LosArchMmu archMmu,
PTE_T pte1,
vaddr_t  vaddr,
UINT32 count 
)

在文件 los_arch_mmu.c482 行定义.

483{
484 UINT32 unmapCount;
485 UINT32 pte2Index;
486 UINT32 intSave;
487 PTE_T *pte2BasePtr = NULL;
488 SPIN_LOCK_S *lock = NULL;
489
490 pte2Index = OsGetPte2Index(vaddr);
491 unmapCount = MIN2(MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - pte2Index, *count);
492
493 lock = OsGetPte2Lock(archMmu, *pte1, &intSave);
494 if (lock == NULL) {
495 return unmapCount;
496 }
497
498 pte2BasePtr = OsGetPte2BasePtr(*pte1);
499 if (pte2BasePtr == NULL) {
500 OsUnlockPte2(lock, intSave);
501 return unmapCount;
502 }
503
504 /* unmap page run */
505 OsClearPte2Continuous(&pte2BasePtr[pte2Index], unmapCount);
506
507 /* invalidate tlb */
508 OsArmInvalidateTlbMvaRangeNoBarrier(vaddr, unmapCount);
509 OsUnlockPte2(lock, intSave);
510
511 *count -= unmapCount;
512 return unmapCount;
513}
STATIC INLINE VOID OsClearPte2Continuous(PTE_T *pte2Ptr, UINT32 count)
Definition: los_pte_ops.h:143
STATIC INLINE VOID OsArmInvalidateTlbMvaRangeNoBarrier(VADDR_T start, UINT32 count)
Definition: los_tlb_v6.h:68
函数调用图:
这是这个函数的调用关系图:

◆ OsUnmapSection()

STATIC UINT32 OsUnmapSection ( LosArchMmu archMmu,
PTE_T l1Entry,
vaddr_t vaddr,
UINT32 count 
)

在文件 los_arch_mmu.c515 行定义.

516{
517 UINT32 intSave;
518 PADDR_T pte1Paddr;
519 SPIN_LOCK_S *lock = NULL;
520
521 pte1Paddr = OsGetPte1Paddr(archMmu->physTtb, *vaddr);
522 lock = OsGetPte1Lock(archMmu, pte1Paddr, &intSave);
523 if (!OsIsPte1Section(*l1Entry)) {
524 OsUnlockPte1(lock, intSave);
525 return 0;
526 }
527 OsClearPte1(OsGetPte1Ptr((PTE_T *)archMmu->virtTtb, *vaddr));
529 OsUnlockPte1(lock, intSave);
530
531 *vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
532 *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
533
534 return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
535}
函数调用图:
这是这个函数的调用关系图: