鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除

news2024/10/7 6:47:27

虚实映射解除函数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 - (*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE)表示1MiB大小的内存中分为2部分,一部分在虚拟地址vaddr前,一部分在虚拟地址后,这里取虚拟地址之后的部分。然后向右偏移12位>>MMU_DESCRIPTOR_L2_SMALL_SHIFT转换为内存页数量,再取内存页数的较小的数值。⑵处把解除映射的内存页数量左移12位转换为地址长度,然后更新虚拟地址。⑶处减去已经解除映射的数量。

STATIC INLINE UINT32 OsUnmapL1Invalid(vaddr_t *vaddr, UINT32 *count)
{
    UINT32 unmapCount;

⑴  unmapCount = MIN2((MMU_DESCRIPTOR_L1_SMALL_SIZE - (*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE)) >>
        MMU_DESCRIPTOR_L2_SMALL_SHIFT, *count);
⑵  *vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
⑶  *count -= unmapCount;

    return unmapCount;
}

5.2 函数OsUnmapSection

函数OsUnmapSection用于解除一级页表的Section映射。⑴处把虚拟地址对应的页表项数据清除为0。⑵处使TLB寄存器失效,⑶更新虚拟地址和映射数量,虚拟地址增加1MiB大小,映射数量减去256。

STATIC UINT32 OsUnmapSection(LosArchMmu *archMmu, vaddr_t *vaddr, UINT32 *count)
{
⑴  OsClearPte1(OsGetPte1Ptr((PTE_T *)archMmu->virtTtb, *vaddr));
⑵  OsArmInvalidateTlbMvaNoBarrier(*vaddr);

⑶  *vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
    *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;

    return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
}

5.3 函数OsUnmapL2PTE

函数OsUnmapL2PTE用于解除L2页表映射。⑴处先调用函数OsGetPte1()计算虚拟内存地址对应的L1页表项,然后调用函数OsGetPte2BasePtr()计算虚拟地址对应的L2页表基地址。⑵处获取虚拟地址对应的的L2页表项索引,计算方式上文已经讲述。⑶处计算需要解除映射的内存页数量,MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - pte2Index表示虚拟内存地址对应的能解除映射的最大数量,使用该值与count取最小值。⑷处依次解除各个二级页表的映射,把对应的各个L2页表项设置为0。⑸处使TLB缓存失效。

STATIC UINT32 OsUnmapL2PTE(const LosArchMmu *archMmu, vaddr_t vaddr, UINT32 *count)
{
    UINT32 unmapCount;
    UINT32 pte2Index;
    PTE_T *pte2BasePtr = NULL;

⑴  pte2BasePtr = OsGetPte2BasePtr(OsGetPte1((PTE_T *)archMmu->virtTtb, vaddr));
    if (pte2BasePtr == NULL) {
        LOS_Panic("%s %d, pte2 base ptr is NULL\n", __FUNCTION__, __LINE__);
    }

⑵  pte2Index = OsGetPte2Index(vaddr);
⑶  unmapCount = MIN2(MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - pte2Index, *count);

    /* unmap page run */
⑷  OsClearPte2Continuous(&pte2BasePtr[pte2Index], unmapCount);

    /* invalidate tlb */
⑸  OsArmInvalidateTlbMvaRangeNoBarrier(vaddr, unmapCount);

    *count -= unmapCount;
    return unmapCount;
}

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页表物理基地址。下面会详细看下函数的代码。

STATIC VOID OsTryUnmapL1PTE(const LosArchMmu *archMmu, vaddr_t vaddr, UINT32 scanIndex, UINT32 scanCount)
{
    /*
     * Check if all pages related to this l1 entry are deallocated.
     * We only need to check pages that we did not clear above starting
     * from scanIndex and wrapped around SECTION.
     */
    UINT32 l1Index;
    PTE_T l1Entry;
    PTE_T *pte2BasePtr = NULL;

⑴  pte2BasePtr = OsGetPte2BasePtr(OsGetPte1(archMmu->virtTtb, vaddr));
    if (pte2BasePtr == NULL) {
        VM_ERR("pte2 base ptr is NULL");
        return;
    }

⑵  while (scanCount) {
⑶      if (scanIndex == MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
            scanIndex = 0;
        }
⑷      if (pte2BasePtr[scanIndex++]) {
            break;
        }
⑸      scanCount--;
    }

⑹  if (!scanCount) {
        l1Index = OsGetPte1Index(vaddr);
        l1Entry = archMmu->virtTtb[l1Index];
        /* we can kill l1 entry */
⑺      OsClearPte1(&archMmu->virtTtb[l1Index]);
        OsArmInvalidateTlbMvaNoBarrier(l1Index << MMU_DESCRIPTOR_L1_SMALL_SHIFT);

        /* try to free l2 page itself */
⑻      OsPutL2Table(archMmu, l1Index, MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(l1Entry));
    }
}

看下函数OsPutL2Table()的实现。⑴处遍历检查是否存在有L1页表项指向此L2页表,如果存在则返回。否则,需要释放L2页表项占用的内存。如果开启虚拟内存,则执行⑵获取物理内存对应的内存页,然后释放内存页。如果没有开启虚拟内存,则执行⑶调用函数LOS_MemFree()释放物理内存。

STATIC VOID OsPutL2Table(const LosArchMmu *archMmu, UINT32 l1Index, paddr_t l2Paddr)
{
    UINT32 index;
    PTE_T ttEntry;
    /* check if any l1 entry points to this l2 table */
    for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) {
⑴      ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index];
        if ((ttEntry &  MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) {
            return;
        }
    }
#ifdef LOSCFG_KERNEL_VM
    /* we can free this l2 table */
⑵  LosVmPage *vmPage = LOS_VmPageGet(l2Paddr);
    if (vmPage == NULL) {
        LOS_Panic("bad page table paddr %#x\n", l2Paddr);
        return;
    }

    LOS_ListDelete(&vmPage->node);
    LOS_PhysPageFree(vmPage);
#else
⑶  (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, LOS_PaddrToKVaddr(l2Paddr));
#endif
}

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1815974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【文献阅读】一种多波束阵列重构导航抗干扰算法

引言 针对导航信号在近地表的信号十分微弱、抗干扰能力差的问题&#xff0c;文章提出了自适应波束形成技术。 自适应波束形成技术可以分为调零抗干扰算法和多波束抗干扰算法。 调零抗干扰算法主要应用功率倒置技术&#xff0c;充分利用导航信号功率低于环境噪声功率的特点&…

Navicat平替软件汇总,各种数据库连接软件

文章目录 1、Navicat2、DataGrip3、Chat2DB4、DBeaver Community5、SQLyog6、beekeeper studio参考文档 1、Navicat 作者最喜欢的数据库连接软件Navicat premium 15安装教程报错解决办法 2、DataGrip 个人感觉界面作者就不喜欢&#xff0c;不爱用IDEA同一家公司出的下载地址…

线程池处理Runnable任务

1、线程池处理Runnable任务 1.1、ThreadPoolExecutor创建线程池对象示例 ExecutorService pools new ThreadPoolExecutor&#xff08;3&#xff0c;5&#xff0c;8&#xff0c;TimeUnit.SECONDS&#xff0c;new ArrayBlockingQueue<>(6)&#xff0c;Executors.default…

iOS/iPadOS18Beta是否值得升级体验?Bug汇总和升级办法分享!

苹果昨天发布了iOS/iPadOS18Beta更新&#xff0c;引入了诸多新功能/新特性&#xff0c;很多喜欢尝鲜的用户已经在第一时间进行了升级。 iOS/iPadOS18Beta目前存在不少Bug&#xff0c;建议暂时不要更新&#xff0c;轻则浪费装机时间&#xff0c;重则丢失相关数据&#xff0c;甚至…

【产品经理】ERP对接电商平台

电商ERP对接上游平台&#xff0c;会需要经历几个步骤环节&#xff0c;包括店铺设置等。 电商ERP对接上游电商平台&#xff0c;其主要设置为店铺设置、商品同步、库存同步&#xff0c;本次讲解下店铺设置应该如何进行设置&#xff0c;以及在设置过程中的可能出现的踩坑事项。 …

王德峰视频讲座,王德峰视频全部大全集,百度云百度网盘资源下载

王德峰教授的视频讲座其内容丰富、观点独到&#xff0c;深受广大学者和爱好者的喜爱。很多朋友想下载王德峰教授的讲座视频&#xff0c;今天我给大家分享一个下载王德峰教授视频的方法 搜索 “方圆资源网官网” 打开 “方圆资源网官网&#xff0c;找到王德峰教授的讲座 总之&a…

3D gaussian-splatting项目环境配置记录

1.前景 项目论文&#xff1a;https://arxiv.org/abs/2308.04079 GitHub项目下载地址&#xff1a;https://github.com/graphdeco-inria/gaussian-splatting git clone时里面的子模块小项目会git不到&#xff0c;需要单独github下来&#xff0c;放入相应文件夹。 sibr_viewer…

GUI编程03-事件监听

事件监听是指当某个事件发生的时候干一些什么。 例如之前在关闭frame窗口时就写过一个window窗口监听&#xff0c;当点击左上角❌时调用System.exit进行程序关闭。 1.按钮监听 下面的例子是监听按钮Button被点击时触发的事件 同时我们将窗口关闭监听事件进行了优化&#xff…

【多线程】进程与线程

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 操作系统2. 进程2.1 进程是什么2.2 进程管理2.3 进程调度2.3 内存管理2.4 进程间通信 3. 线程3.1 线程是什…

Keepalived LVS群集

一、Keepalived案例分析 企业应用中&#xff0c;单台服务器承担应用存在单点故障的危险 单点故障一旦发生&#xff0c;企业服务将发生中断&#xff0c;造成极大的危害 二、Keepalived工具介绍 专为LVS和HA设计的一款健康检查工具 支持故障自动切换&#xff08;Failover&#…

VLM训练——Trainer源码解读

本文将以LLaVa源码为例&#xff0c;解析如何使用Trainer训练/微调一个VLM。 1. 参数解析ModelArgumentsDataArgumentsTrainingArguments 2. 加载模型3. 加载数据4. 创建Trainer开始训练 1. 参数解析 VLM 和 LLM 相关训练框架都会引入 ModelArguments、DataArguments、Trainin…

高考志愿填报秘籍:个人篇

选择适合自己的大学和专业&#xff0c;对广大考生来说至关重要。从某种程度上来说&#xff0c;决定了考生未来所从事的行业和发展前景。为了帮助广大考生更加科学、合理地填报志愿&#xff0c;选择适合自己的大学和专业&#xff0c;本公众号将推出如何用AI填报高考志愿专栏文章…

Linux环境各种软件安装配置

安装Java 官网 找个喜欢的版本 下载好了传到linux里&#xff0c;xshell的xftp直接拖过去就可以传 #安装rpm包管理 yum install -y rpm or apt-get install rpm #查找Java rpm -qa | grep java\|jdk\|gcj\|jre #卸载java rpm -e --nodeps jdk-1.8-1.8.0_401-10.x86_64 #安装 …

明基的台灯值得入手吗?书客、柏曼真实横向测评对比

近年来人们在工作、学习、娱乐等方面对电子设备的依赖程度也越来越高&#xff0c;长时间使用电子设备会对眼睛造成一定的伤害&#xff0c;如眼疲劳、干涩、近视等。人们对于能够缓解眼疲劳的照明产品的需求逐渐增加。护眼台灯能够更好地模拟自然光&#xff0c;提供更加柔和舒适…

AD24设计步骤

一、元件库的创建 1、AD工程创建 然后创建原理图、PCB、库等文件 2、电阻容模型的创建 注意&#xff1a;防止管脚时设置栅格大小为100mil&#xff0c;防止线段等可以设置小一点,快捷键vgs设置栅格大小。 1.管脚的设置 2.元件的设置 3、IC类元件的创建 4、排针类元件模型创建…

机器学习笔记 - 用于3D数据分类、分割的Point Net简述

一、简述 在本文中,我们将了解Point Net,目前,处理图像数据的方法有很多。从传统的计算机视觉方法到使用卷积神经网络到Transformer方法,几乎任何 2D 图像应用都会有某种现有的方法。然而,当涉及到 3D 数据时,现成的工具和方法并不那么丰富。3D 空间中一个工具就是Point …

14、modbus poll 使用教程小记1

开发平台&#xff1a;Win10 64位 Modbus Slave版本&#xff1a;64位 7.0.0 Modbus Poll版本&#xff1a;64位 7.2.2 因为项目中经常会用到modbus协议&#xff0c;所以就避免不了的要使用modbus测试工具&#xff0c;Modbus Slave/Poll无疑是众多测试工具中应用最广泛的。 文章目…

dll文件丢失了要如何处理?教你一键修复所有dll缺失的方法

dll文件丢失了要如何处理&#xff1f;其实dll文件的丢失还是比较常见的&#xff0c;它的丢失会引起一些程序无法启动&#xff0c;所以我们必须要去修复dll文件&#xff0c;这点是毋容置疑的&#xff0c;其修复方法也是有很多种的&#xff0c;今天就来给大家详细的聊一下dll文件…

BUAA-2024年春-OO第四单元总结

正向建模与开发 在本单元中&#xff0c;我们需要模拟一个小型的图书管理系统&#xff0c;完成图书馆所支持的相关业务&#xff0c;并遵守一定的规章制度。与前几次不同的是&#xff0c;本单元中&#xff0c;我们需要预先将自己的设计思路用UML来实现&#xff0c;然后进行编程。…

Coze+Discord:打造你的免费AI助手(教您如何免费使用GPT-4o/Gemini等最新最强的大模型/Discord如何正确连接Coze)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 准备Discord📝 准备Coze🔌 连接💡 测试效果⚓️ 相关链接 ⚓️📖 介绍 📖 你是否想免费使用GPT-4o/Gemini等最新最强的大模型,但又不想花费高昂的费用?本文将教你如何通过Coze搭建Bot,并将其转发…