虚实映射解除函数LOS_ArchMmuUnmap
解除进程空间虚拟地址区间与物理地址区间的映射关系,其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count
,数量的单位是内存页数。 ⑴处函数OsGetPte1
用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效映射的数量,后文再详细分析该函数。如果页表项映射类型为L1 Section,并且虚拟地址1MiB对齐,映射的数量超过256,则执行⑶解除映射Section,后文详细分析函数OsUnmapSection
。如果页表项映射类型为Page Table,则执行⑷先解除二级页表映射,然后尝试解除一级页表映射,涉及的2个函数后文详细分析。从虚拟地址开始的需要接触映射的内存页中,可能部分是L2映射,部分是L1映射。完成L2映射后,需要判断是否存在L1映射,如果存在也需要解除映射。⑹处函数使TLB失效,涉及些cp15寄存器和汇编,后续再分析。
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
{
PTE_T l1Entry;
INT32 unmapped = 0;
UINT32 unmapCount = 0;
while (count > 0) {
⑴ l1Entry = OsGetPte1(archMmu->virtTtb, vaddr);
if (OsIsPte1Invalid(l1Entry)) {
⑵ unmapCount = OsUnmapL1Invalid(&vaddr, &count);
} else if (OsIsPte1Section(l1Entry)) {
if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(vaddr) && count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
⑶ unmapCount = OsUnmapSection(archMmu, &vaddr, &count);
} else {
LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
}
} else if (OsIsPte1PageTable(l1Entry)) {
⑷ unmapCount = OsUnmapL2PTE(archMmu, vaddr, &count);
OsTryUnmapL1PTE(archMmu, vaddr, OsGetPte2Index(vaddr) + unmapCount,
MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - unmapCount);
⑸ vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
} else {
LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
}
unmapped += unmapCount;
}
⑹ OsArmInvalidateTlbBarrier();
return unmapped;
}
5.1 函数OsUnmapL1Invalid
函数OsUnmapL1Invalid
用于解除无效的映射,会把虚拟地址增加,映射的数量减少。⑴处的MMU_DESCRIPTOR_L1_SMALL_SIZE
表示1MiB大小,*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE
对1MiB取余,MMU_DESCRIPTOR_L1_SMALL_SIZE - (*vadd