鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除 原创 精华
5、虚实映射解除函数LOS_ArchMmuUnmap
【#本文正在参与优质创作者激励#】
虚实映射解除函数LOS_ArchMmuUnmap
解除进程空间虚拟地址区间与物理地址区间的映射关系,其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count
,数量的单位是内存页数。 ⑴处函数OsGetPte1
用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效映射的数量,后文再详细分析该函数。如果页表项映射类型为L1 Section,并且虚拟地址1MiB对齐,映射的数量超过256,则执行⑶解除映射Section,后文详细分析函数OsUnmapSection
。如果页表项映射类型为Page Table,则执行⑷先解除二级页表映射,然后尝试解除一级页表映射,涉及的2个函数后文详细分析。从虚拟地址开始的需要接触映射的内存页中,可能部分是L2映射,部分是L1映射。完成L2映射后,需要判断是否存在L1映射,如果存在也需要解除映射。⑹处函数使TLB失效,涉及些cp15寄存器和汇编,后续再分析。
5.1 函数OsUnmapL1Invalid
函数OsUnmapL1Invalid
用于解除无效的映射,会把虚拟地址增加,映射的数量减少。⑴处的MMU_DESCRIPTOR_L1_SMALL_SIZE
表示1MiB大小,*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE
对1MiB取余,MMU_DESCRIPTOR_L1_SMALL_SIZE - (*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE)
表示1MiB大小的内存中分为2部分,一部分在虚拟地址vaddr
前,一部分在虚拟地址后,这里取虚拟地址之后的部分。然后向右偏移12位>>MMU_DESCRIPTOR_L2_SMALL_SHIFT
转换为内存页数量,再取内存页数的较小的数值。⑵处把解除映射的内存页数量左移12位转换为地址长度,然后更新虚拟地址。⑶处减去已经解除映射的数量。
5.2 函数OsUnmapSection
函数OsUnmapSection
用于解除一级页表的Section映射。⑴处把虚拟地址对应的页表项数据清除为0。⑵处使TLB寄存器失效,⑶更新虚拟地址和映射数量,虚拟地址增加1MiB大小,映射数量减去256。
5.3 函数OsUnmapL2PTE
函数OsUnmapL2PTE
用于解除L2页表映射。⑴处先调用函数OsGetPte1()
计算虚拟内存地址对应的L1页表项,然后调用函数OsGetPte2BasePtr()
计算虚拟地址对应的L2页表基地址。⑵处获取虚拟地址对应的的L2页表项索引,计算方式上文已经讲述。⑶处计算需要解除映射的内存页数量,MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - pte2Index
表示虚拟内存地址对应的能解除映射的最大数量,使用该值与count
取最小值。⑷处依次解除各个二级页表的映射,把对应的各个L2页表项设置为0。⑸处使TLB缓存失效。
5.4 OsTryUnmapL1PTE函数
函数OsTryUnmapL1PTE()
用于解除L1页表映射,其中参数需要MMU结构体、虚拟内存地址vaddr
、页表项索引scanIndex
和要解除映射的内存页数scanCount
。调用该函数时,页表项索引传入参数scanIndex
的实参为OsGetPte2Index(vaddr) + unmapCount
,即虚拟内存对应的L2页表项索引加上解除映射的页数量;要解除映射的内存页数量参数的实参为MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - unmapCount
,即256减去已经解除映射的数量。回忆上文调用该函数OsTryUnmapL1PTE()
的代码处,先调用OsUnmapL2PTE()
函数解除unmapCount
个映射,然后调用该函数解除映射MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - unmapCount
个映射。
⑴处先执行函数OsGetPte1(archMmu->virtTtb, vaddr)
获取页表项,然后执行函数OsGetPte2BasePtr()
获得L2页表项基地址。⑵处执行循环检测是否存在可以解除映射的页表映射。⑶当scanIndex
等于256时,置为0。⑷处当L2页表项不为0时,此时存在L2页表映射,跳出while循环。⑸处页数减1,不为0时则继续while循环。
当可以解除映射的数量为0时,执行⑹处代码,先获取L1页表项索引l1Index
,然后获取对应的页表项l1Entry
。执行⑺清零页表项,然后清理TLB缓存。⑻处调用函数OsPutL2Table()
释放L2页表项内存,其中第3个实际参数MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(l1Entry)
是L2y页表物理基地址。下面会详细看下函数的代码。
看下函数OsPutL2Table()
的实现。⑴处遍历检查是否存在有L1页表项指向此L2页表,如果存在则返回。否则,需要释放L2页表项占用的内存。如果开启虚拟内存,则执行⑵获取物理内存对应的内存页,然后释放内存页。如果没有开启虚拟内存,则执行⑶调用函数LOS_MemFree()
释放物理内存。
【#本文正在参与优质创作者激励#】
大佬的相关文章大家可以进入专栏进行学习:https://harmonyos.51cto.com/column/47
666