鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除
虚实映射解除函数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
相关文章:

鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除
虚实映射解除函数LOS_ArchMmuUnmap解除进程空间虚拟地址区间与物理地址区间的映射关系,其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count,数量的单位是内存页数。 ⑴处函数OsGetPte1用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效…...

编程初学者用什么软件电脑:全方位指南及深度解析
编程初学者用什么软件电脑:全方位指南及深度解析 在数字化浪潮席卷而来的今天,编程技能逐渐成为了一项必备的基本素养。对于初学者来说,选择一款合适的编程软件电脑至关重要。本文将从四个方面、五个方面、六个方面和七个方面,深…...

代理IP池功能组件
1.IP池管理器:用于管理IP池,包括IP地址的添加、删除、查询和更新等操作。 2.代理IP获取器:用于从外部资源中获取代理IP,例如从公开代理IP网站上爬取代理IP、从代理服务商订购代理IP等。 3.IP质量检测器:用于检测代理…...

Sqlite3入门和c/c++下使用
1. SQLite3基本介绍 1.1 数据库的数据类型 1.2 基本语法 1. 创建数据表格 create table 表名(字段名 数据类型, 字段名 数据类型); create table student(id int, name varchar(256), address text, QQ char(32)); 2. 插入数据 insert into 表名 valu…...

pyinstaller打包exe多种失败原因解决方法
pyinstaller打包exe多种失败原因解决方法 目录 pyinstaller打包exe多种失败原因解决方法1、pyinstaller安装有问题1.1 安装pyinstaller1.2 采用anconda的环境启动 2、pyqt5与pyside6冲突2.1 打包生成.spec文件2.2 编辑spec文件 3、打包成功后打不开exe,exe闪退3.1 s…...

x64-linux下在vscode使用vcpkg
1.使用vscode远程连接上对应的linux ,或者直接在图形化界面上使用。 2.安装vcpkg 插件,然后打开插件设置。 注意:defalut和host的主机一定和你自己的主机一致,且必须符合vcpkg三元组格式,其中你可以选择工作台的设置&a…...

运营商二要素核验-手机号机主姓名核验接口-运营商二要素核验接口
通过电信运营商验证手机号码与姓名是否一致。广泛用于实名注册、风控审核等场景,如电商、游戏、直播、金融等需要用户实名认证的场景。支持携号转网核验。 更新周期:联通T1 电信T3 移动T3~5 均为工作日 接口地址: https://www.wapi.cn/api_de…...

C++设计模式-生产者消费者模式
运行在VS2022,x86,Debug下。 32. 生产者消费者模式 解耦生产者和消费者之间的关系,即生产者和消费者只依赖缓冲区,而不相互依赖。应用:多线程并发编程,可以解决生产者和消费者之间的同步问题。实现 生产者…...

VSTO Word.net 如何在另外的工程内添加CustomTaskPane
其他工程肯定是不能直接添加CustomTaskPane面板的,但我们可以在ThisAddIn 中先把对应的panel给新建出来再进行隐藏。步骤如下: 1.在另外工程中定义public static CustomTaskPane currMainForm;把需要隐藏的界面赋值给currMainForm; 2.在另外…...

ROS——自定义话题消息和使用方法
定义Person话题 定义Person发布者 /*** 该例程将发布/person_info话题,自定义消息类型: test_topic::Person*/#include <ros/ros.h> #include <test_topic/Person.h> //包含的头文件,ros相关的头文件,及自定义头文件…...

包装对象类型又是啥啊。。。
包装对象类型 目录 包装对象类型 目录包装对象的概念包装对象类型和字面量类型Objectobject 包装对象的概念 JavaScript 的8种类型之中,undefined和null其实是两个特殊值,object属于复合类型,剩下的五种属于原始类型(primiti…...

服务编排如何选?这几款可视化服务编排引擎,开发团队赶紧收藏
最近看到几款不错的服务编排的产品,先给大家上图看看 扣子: jvs-logic: node-red: jvs-rules: 上述几个产品是最近看到的 几个比较有特点的服务编排的系统。 接下来我对API详细分解下,说明下优点与挑战 服…...

web前端语言框架:探索现代前端开发的核心架构
web前端语言框架:探索现代前端开发的核心架构 在快速发展的web开发领域,前端语言框架的选择对于项目的成功至关重要。它们不仅影响着开发效率,更直接关系到用户体验与网站性能。本文将从四个方面、五个方面、六个方面和七个方面,…...

基于flask的网站如何使用https加密通信
文章目录 内容简介网站目录示例生成SSL证书单独使用Flask使用WSGI服务器Nginx反向代理参考资料 内容简介 HTTPS 是一种至关重要的网络安全协议,它通过在 HTTP 协议之上添加 SSL/TLS 层来确保数据传输的安全性和完整性。这有助于防止数据在客户端和服务器之间传输时…...

软件测试面试题(应届生)
设计员工管理系统的测试用例时,需要考虑系统的各种功能和可能的使用场景,以确保系统的稳定性和准确性。以下是一些设计测试用例的基本步骤和策略: 一、明确测试目标 首先,需要明确测试的目标,例如确保员工信息的准确…...

使用halo的jar方法搭建博客(数据库mysql
ssh连接远程主机 ➜ ~ ssh root 146.56.249.61 第一步.在CentOS 7上安装下载OpenJDK 17的tar.gz文件 wget https://download.java.net/java/GA/jdk17.0.1/2a2082e5a09d4267845be086888add4f/12/GPL/openjdk-17.0.1_linux-x64_bin.tar.gz解压 tar xvf openjdk-17.0.1_linux-…...

Linux - 复盘一次句柄数引发的故障
文章目录 Pre(内核、用户、进程)句柄数设置问题 shell修复 Pre Linux - 深入理解/proc虚拟文件系统:从基础到高级 (内核、用户、进程)句柄数设置 在Linux系统中,进程打开的最大句柄数可以通过多种方式配置…...

2024/06/13--代码随想录算法2/17| 62.不同路径、63. 不同路径 II、343. 整数拆分 (可跳过)、96.不同的二叉搜索树 (可跳过)
62.不同路径 力扣链接 动态规划5步曲 确定dp数组(dp table)以及下标的含义: dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。确定递推公式,dp[i][j] d…...

Android低代码开发 - 直接创建一个下拉刷新列表界面
看了我Android低代码开发 - 让IDE帮你写代码这篇文章的小伙伴,大概都对Dora全家桶开发框架有基本的认识了吧。本篇文章将会讲解如何使用dora-studio-plugin快捷创建一个下拉刷新列表界面。 效果演示 这样直接通过图形界面的方式就创建好了下拉刷新上拉加载空态界面…...

23.Dropout
在深度学习的训练过程中,过拟合是一个常见的问题。为了解决这个问题,研究者们提出了多种正则化技术,其中Dropout技术因其简单而有效的特点,得到了广泛的应用。本文将对Dropout技术的工作原理、主要优点、潜在缺点以及应用场景进行…...

电脑撤回的快捷键是什么?
下面给大家介绍了各种办公应用的撤回以及反向撤回快捷键介绍,在ps、excel中都是可以使用的。 撤回键是ctrl加什么 1、撤销的快捷键是“CtrlZ”,用于取消上一步操作,对与在电脑系统上或软件内的操作均适用。重复按下可以取消多步操作。 2、而…...

每日一题——Python实现PAT甲级1116 Come on! Let‘s C(举一反三+思想解读+逐步优化)五千字好文
一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码点评 时间复杂度分析 空间复杂度分析 总结 我要更强 优化思路 优化…...

spring-data-mongodb版本兼容问题
spring-data-mongodb与mongodb驱动有兼容性问题,不匹配会报NoSuchMethod异常,mongodb的java驱动包在4.0之后由mongodb-java-driver更名为mongodb-driver-sync。 spring-data-mongodb包依赖中有mongodb-driver-core,但缺诸如MongoCollection等…...

Java的核心类库
引言 在Java编程中,熟练掌握常用类与对象操作是开发的基础。Java的核心类库提供了丰富的功能,可以帮助开发者高效地处理各种编程任务。本文将详细介绍Java字符串操作、集合框架、日期与时间处理等内容,并通过图表和表格进行总结与示范。 字符…...

NSS题目练习9
[极客大挑战 2020]welcome 界面打开后一片空白,查看题目描述,翻译过来是 1.除了GET请求方法,还有一种常见的请求方法… 2.学习一些关于sha1和array的知识。 3.更仔细地检查phpinfo,你会发现标志在哪里。 补充: sh…...

JS 【算法】二分查找
使用场景 在有序数组中查找目标元素 const arr [1, 2, 3, 4, 5, 6, 7, 8, 9] const target 2 console.log(binarySearch1(arr, target)) console.log(binarySearch2(arr, target))循环实现 function binarySearch1(arr, target) {const length arr.lengthif (length 0) re…...

前端工程化工具系列(十四)—— Webpack(v5.91.0):应用模块打包器与构建工具
Webpack 是用于现代 JavaScript 应用程序的静态模块打包器。 当 webpack 处理应用程序时,它会在内部构建一个依赖关系图,该图映射项目所需的每个模块最终会生成一个或多个包。 1 概念 1.1 modules Webpack 中,无论是 JS 、CSS 还是图片等&…...

ThinkPHP+Bootstrap简约自适应网址导航网站源码
使用 ThinkPHPbootstrap 开发,后台采用全局 ajax 无刷新加载,前后台自适应,前台页面非常简洁适合自己收藏网站或做导航网站。 搭建教程: 1.整个主机 2.绑定解析域名 3.上传源码,解压 把解压出来的 nav.sql 文件导入数…...

Flutter 使用ffigen生成ffmpeg的dart接口
Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FFICustomPainter渲染视频 第五章 Windows使用Native窗口渲染视频 第六章 桌面端使用texture_rgba_renderer渲染视频 第七章 使用ff…...

(message): No CUDA toolset found.
解决方法: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\extras\visual_studio_integration\MSBuildExtensions\ 下的4个文件 复制到 D:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\BuildCustomizations\下。…...