Linux ARM64 将内核虚拟地址转化为物理地址
文章目录
- 前言
- 一、通用方案
- 1.1 kern_addr_valid
- 1.2 __pa
- 二、ARM64架构
- 2.1 AT S1E1R
- 2.2 is_kernel_addr_vaild
- 2.3 va2pa_helper
- 三、demo演示
- 参考资料
前言
本文介绍一种通用的将内核虚拟地址转化为物理地址的方案以及一种适用于ARM64 将内核虚拟地址转化为物理地址的方案,两种方案都可以。
一、通用方案
1.1 kern_addr_valid
int kern_addr_valid(unsigned long addr)
{pgd_t *pgdp;pud_t *pudp, pud;pmd_t *pmdp, pmd;pte_t *ptep, pte;if ((((long)addr) >> VA_BITS) != -1UL)return 0;pgdp = pgd_offset_k(addr);if (pgd_none(READ_ONCE(*pgdp)))return 0;pudp = pud_offset(pgdp, addr);pud = READ_ONCE(*pudp);if (pud_none(pud))return 0;if (pud_sect(pud))return pfn_valid(pud_pfn(pud));pmdp = pmd_offset(pudp, addr);pmd = READ_ONCE(*pmdp);if (pmd_none(pmd))return 0;if (pmd_sect(pmd))return pfn_valid(pmd_pfn(pmd));ptep = pte_offset_kernel(pmdp, addr);pte = READ_ONCE(*ptep);if (pte_none(pte))return 0;return pfn_valid(pte_pfn(pte));
}
kern_addr_valid用于检测内核虚拟地址是否有效,适用于x86架构和arm64架构。
1.2 __pa
__pa用于将内核虚拟地址转化为物理地址,适用于x86架构和arm64架构。
对于arm64架构:
// v5.4/source/arch/arm64/include/asm/memory.h#define __pa(x) __virt_to_phys((unsigned long)(x))
// v5.4/source/arch/arm64/include/asm/memory.h#define __virt_to_phys(x) __virt_to_phys_nodebug(x)
// v5.4/source/arch/arm64/include/asm/memory.h#define __virt_to_phys_nodebug(x) ({ \phys_addr_t __x = (phys_addr_t)(__tag_reset(x)); \__is_lm_address(__x) ? __lm_to_phys(__x) : __kimg_to_phys(__x); \
})
二、ARM64架构
2.1 AT S1E1R
ARM64架构将内核虚拟地址转化为物理地址主要是采用ARM64架构的 at s1e1r 指令。
at s1e1r
AT S1E1R 是 ARM64 架构中的一条系统指令,用于执行 Stage 1 地址翻译,并模拟从 EL1(Exception Level 1,通常是操作系统内核)读取给定虚拟地址的权限。
执行 Stage 1 地址翻译,并根据翻译结果更新 PAR_EL1(Physical Address Register)寄存器。
指令类型:
64 位系统指令。
操作数:
一个 64 位虚拟地址。
结果存储:
翻译结果(物理地址和状态信息)存储到 PAR_EL1 寄存器中。
PAR_EL1 寄存器:
bit0:Fault 标志位(F bit)。如果为 1,表示翻译失败;如果为 0,表示翻译成功。
2.2 is_kernel_addr_vaild
static bool is_kernel_addr_vaild(unsigned long addr)
{unsigned long flags;u64 par;local_irq_save(flags);asm volatile("at s1e1r, %0" :: "r" (addr));isb();par = read_sysreg(par_el1);local_irq_restore(flags);/** If we now have a valid translation, treat the translation fault as* spurious.*/if (par & SYS_PAR_EL1_F)return false;return true;
}
该函数用于检查给定的内核虚拟地址是否有效。它通过 ARM64 的 AT(Address Translate)指令和 PAR_EL1(Physical Address Register)寄存器来完成地址翻译,并根据翻译结果判断地址的有效性。
代码说明:
(1)保存当前中断状态并禁用中断,确保接下来的操作不会被中断打断。
(2)使用 AT 指令将虚拟地址 addr 翻译为物理地址,并将结果存储到 PAR_EL1 寄存器中。
s1e1r:表示在 EL1 阶段使用 Stage 1 翻译表进行读取操作。
%0:表示输入操作数 addr(虚拟地址)。
(3)插入指令屏障
插入一条指令屏障(Instruction Synchronization Barrier),确保 AT 指令的结果在读取 PAR_EL1 之前完成。
(4)读取 PAR_EL1 寄存器的值
读取 PAR_EL1 寄存器的值,该寄存器保存了 AT 指令的结果。
(5) 恢复中断状态
(6) 检查翻译结果
SYS_PAR_EL1_F:表示 PAR_EL1 寄存器中的 Fault 标志位。如果该位为 1,表示地址翻译失败(如页表项无效或权限不足)。
2.3 va2pa_helper
typedef uintptr_t vaddr_t;
typedef uint64_t paddr_t;#define BIT32(nr) ((uint64_t)1 << (nr)) // 生成 32 位掩码
#define BIT64(nr) ((uint64_t)1 << (nr)) // 生成 64 位掩码#define PAR_F BIT32(0) // PAR 寄存器的 Fault 标志位,表示 PAR 寄存器中的 Fault 标志位(第 0 位)。如果该位为 1,表示地址翻译失败。#define PAR_PA_SHIFT UL(12) // 物理地址在 PAR 寄存器中的偏移量
#define PAR_PA_MASK (BIT64(36) - 1) // 物理地址的掩码(36 位),用于从 PAR 寄存器中提取物理地址。#define DEFINE_REG_READ_FUNC_(reg, type, asmreg) \
static inline type read_##reg(void) \
{ \type val; \\asm volatile("mrs %0, " #asmreg : "=r" (val)); \return val; \
}#define DEFINE_U64_REG_READ_FUNC(reg) \DEFINE_REG_READ_FUNC_(reg, uint64_t, reg)DEFINE_U64_REG_READ_FUNC(par_el1)// 使用 AT S1E1R 指令将虚拟地址 va 翻译为物理地址,并将结果存储到 PAR_EL1 寄存器中。
static inline void write_at_s1e1r(uint64_t va)
{asm volatile ("at S1E1R, %0" : : "r" (va));
}//通过 ARM64 的 AT(Address Translate)指令和 PAR_EL1(Physical Address Register)寄存器来完成地址翻译。
bool va2pa_helper(void *va, paddr_t *pa)
{paddr_t par = 0;paddr_t par_pa_mask = 0;bool ret = false;write_at_s1e1r((vaddr_t)va); // 使用 AT 指令翻译虚拟地址isb(); // 插入指令屏障,确保 AT 指令完成par = read_par_el1(); // 读取 PAR_EL1 寄存器的值par_pa_mask = PAR_PA_MASK;if (par & PAR_F) // 检查 Fault 标志位goto out;// 提取物理地址并合并低 12 位*pa = (par & (par_pa_mask << PAR_PA_SHIFT)) |((vaddr_t)va & (BIT64(PAR_PA_SHIFT) - 1));ret = true;out:return ret;
}
函数逻辑:
(1)使用 AT 指令翻译虚拟地址:
调用 write_at_s1e1r,将虚拟地址 va 翻译为物理地址,并将结果存储到 PAR_EL1 寄存器中。
(2)插入指令屏障:
使用 isb() 确保 AT 指令的结果在读取 PAR_EL1 之前完成。
(3)读取 PAR_EL1 寄存器的值:
调用 read_par_el1,获取地址翻译的结果。
(4)检查 Fault 标志位:
如果 PAR_F 标志位为 1,表示地址翻译失败,直接返回 false。
(5)提取物理地址:
从 PAR_EL1 中提取物理地址的高 36 位(par & (par_pa_mask << PAR_PA_SHIFT))。
将虚拟地址的低 12 位(页内偏移)合并到物理地址中。
(6)返回结果:
如果地址翻译成功,返回 true,并将物理地址存储到 *pa。
如果地址翻译失败,返回 false。
三、demo演示
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
#include <linux/gfp.h>#include <asm/esr.h>
#include <asm/sysreg.h>
#include <asm/system_misc.h>typedef uintptr_t vaddr_t;
typedef uint64_t paddr_t;#define BIT32(nr) ((uint64_t)1 << (nr)) // 生成 32 位掩码
#define BIT64(nr) ((uint64_t)1 << (nr)) // 生成 64 位掩码#define PAR_F BIT32(0) // PAR 寄存器的 Fault 标志位,表示 PAR 寄存器中的 Fault 标志位(第 0 位)。如果该位为 1,表示地址翻译失败。#define PAR_PA_SHIFT UL(12) // 物理地址在 PAR 寄存器中的偏移量
#define PAR_PA_MASK (BIT64(36) - 1) // 物理地址的掩码(36 位),用于从 PAR 寄存器中提取物理地址。#define DEFINE_REG_READ_FUNC_(reg, type, asmreg) \
static inline type read_##reg(void) \
{ \type val; \\asm volatile("mrs %0, " #asmreg : "=r" (val)); \return val; \
}#define DEFINE_U64_REG_READ_FUNC(reg) \DEFINE_REG_READ_FUNC_(reg, uint64_t, reg)DEFINE_U64_REG_READ_FUNC(par_el1)// 使用 AT S1E1R 指令将虚拟地址 va 翻译为物理地址,并将结果存储到 PAR_EL1 寄存器中。
static inline void write_at_s1e1r(uint64_t va)
{asm volatile ("at S1E1R, %0" : : "r" (va));
}//通过 ARM64 的 AT(Address Translate)指令和 PAR_EL1(Physical Address Register)寄存器来完成地址翻译。
bool va2pa_helper(void *va, paddr_t *pa)
{paddr_t par = 0;paddr_t par_pa_mask = 0;bool ret = false;write_at_s1e1r((vaddr_t)va); // 使用 AT 指令翻译虚拟地址isb(); // 插入指令屏障,确保 AT 指令完成par = read_par_el1(); // 读取 PAR_EL1 寄存器的值par_pa_mask = PAR_PA_MASK;if (par & PAR_F) // 检查 Fault 标志位goto out;// 提取物理地址并合并低 12 位*pa = (par & (par_pa_mask << PAR_PA_SHIFT)) |((vaddr_t)va & (BIT64(PAR_PA_SHIFT) - 1));ret = true;out:return ret;
}static bool is_kernel_addr_vaild(unsigned long addr)
{unsigned long flags;u64 par;local_irq_save(flags);asm volatile("at s1e1r, %0" :: "r" (addr));isb();par = read_sysreg(par_el1);local_irq_restore(flags);/** If we now have a valid translation, treat the translation fault as* spurious.*/if (par & SYS_PAR_EL1_F)return false;return true;
}//内核模块初始化函数
static int __init lkm_init(void)
{unsigned long virt_address, phys_address, phys_address2;//调用伙伴系统接口分配 2^2 = 4 个连续的物理页,返回其内核虚拟起始地址virt_address = __get_free_pages(GFP_KERNEL, 2);phys_address = __pa(virt_address);if(is_kernel_addr_vaild(virt_address)){printk("kernel address 0x%lx is valid\n", virt_address);}else{printk("kernel address 0x%lx is not invalid\n", virt_address);goto out;}printk("virtual addr = 0x%lx, phys address = 0x%lx\n", virt_address, phys_address);if(va2pa_helper((void *)virt_address, (paddr_t *)&phys_address2)){printk("virtual address 0x%lx -> physical address 0x%lx\n", virt_address, phys_address2);}else {printk("Failed to translate virtual address to physical address\n");} out:free_pages(virt_address, 2);return 0;
}//内核模块退出函数
static void __exit lkm_exit(void)
{printk("Goodbye\n");
}module_init(lkm_init);
module_exit(lkm_exit);MODULE_LICENSE("GPL");
# insmod va2pa.ko
# dmesg -c
[7816428.962021] kernel address 0xffffff9fe7bd8000 is valid
[7816428.962024] virtual addr = 0xffffff9fe7bd8000, phys address = 0x2067bd8000
[7816428.962025] virtual address 0xffffff9fe7bd8000 -> physical address 0x2067bd8000
可以看到使用 __pa 和 使用 AT 指令将虚拟地址 转化为物理地址结果相同。
参考资料
https://www.cnblogs.com/smilingsusu/p/14600585.html
相关文章:

Linux ARM64 将内核虚拟地址转化为物理地址
文章目录 前言一、通用方案1.1 kern_addr_valid1.2 __pa 二、ARM64架构2.1 AT S1E1R2.2 is_kernel_addr_vaild2.3 va2pa_helper 三、demo演示参考资料 前言 本文介绍一种通用的将内核虚拟地址转化为物理地址的方案以及一种适用于ARM64 将内核虚拟地址转化为物理地址的方案&…...

使用 Visual Studio Code (VS Code) 开发 Python 图形界面程序
安装Python、VS Code Documentation for Visual Studio Code Python Releases for Windows | Python.org 更新pip >python.exe -m pip install --upgrade pip Requirement already satisfied: pip in c:\users\xxx\appdata\local\programs\python\python312\lib\site-pa…...
图像处理篇---基本OpenMV图像处理
文章目录 前言1. 灰度化(Grayscale)2. 二值化(Thresholding)3. 掩膜(Mask)4. 腐蚀(Erosion)5. 膨胀(Dilation)6. 缩放(Scaling)7. 旋转…...
一文讲清springboot所有注解
Spring Boot 注释是提供有关 Spring 应用程序信息的元数据。 基于 Spring 构建,涵盖其所有功能, Spring Boot 因其生产就绪环境而迅速成为开发人员的最爱,它允许开发人员直接专注于逻辑,而无需配置和设置的麻烦。 Spring Boot 是一…...
pytest测试专题 - 1.1 运行pytest
<< 返回目录 1 pytest学习笔记 - 1.1 运行pytest 1.1 运行pyest 在命令行执行pytest --help usage: pytest [options] [file_or_dir] [file_or_dir] [...] ... ...1.1.1 pytest不携带参数 pytest不带参数时,会扫描当前目录下的所有目录、子目录中符合测试用…...

Java多线程——线程池的使用
线程饥饿死锁 在单线程的Executor中,如果任务A将任务B提交给同一个Executor,并且等待任务B的结果,就会引发死锁线程池中所有正在执行任务的线程由于等待其他仍处于工作队列中的任务而阻塞 执行时间较长的任务 执行时间较长的任务不仅会造成…...

NO.15十六届蓝桥杯备战|while循环|六道练习(C++)
while循环 while语法形式 while 语句的语法结构和 if 语句⾮常相似,但不同的是 while 是⽤来实现循环的, if 是⽆法实现循环的。 下⾯是 while 循环的语法形式: //形式1 while ( 表达式 )语句; //形式2 //如果循环体想包含更多的语句&a…...
DeepSeek 从入门到精通学习指南,2025清华大学《DeepSeek从入门到精通》正式发布104页pdf版超全解析
DeepSeek 是一款强大的 AI 搜索引擎,广泛应用于企业级数据检索和分析。无论您是初学者还是有经验的用户,掌握 DeepSeek 的使用都能为您的工作带来极大的便利。本文将从入门到精通,详细介绍如何学习和使用 DeepSeek。 链接: https://pan.baid…...

2025年SEO自动优化工具
随着2025年互联网的快速发展,越来越多的企业和个人意识到,拥有一个排名靠前的网站对于吸引客户、增加流量、提高转化率至关重要。而要想让自己的网站脱颖而出,获得更多曝光,最重要的一项工作就是进行SEO优化。传统的SEO优化方式通…...

KEPServerEX 的接口类型与连接方式的详细说明
目录 一、KEPServerEX 核心架构 二、KEPServerEX 支持的接口类型 三、KEPServerEX 支持的连接类型 1. 通用工业协议 2. 品牌专属协议 3. 行业专用协议 4. 数据库与文件接口 四、配置示例 1. 接口配置(以OPC UA为例) 2. 连接配置(以…...

AGI时代的认知重塑:人类文明的范式转移与思维革命
文章目录 引言:站在文明转型的临界点一、认知危机:当机器开始理解世界1.1 AGI的本质突破:从模式识别到世界建模1.2 人类认知的脆弱性暴露二、认知革命:重构思维的四个维度2.1 元认知升级:从直觉思维到二阶观察2.2 混合智能:人机认知回路的构建2.3 认知安全:防御机器思维…...

OmniManip:以目标为中心的交互基元作为空间约束实现通用机器人操作
25年1月来自北大、北大-智元实验室和智元机器人公司的论文“OmniManip: Towards General Robotic Manipulation via Object-Centric Interaction Primitives as Spatial Constraints”。 开发能够在非结构化环境中进行操作的通用机器人系统是一项重大挑战。虽然视觉-语言模型 …...

论文第二次阅读笔记
摘要学习 存在问题:目前流行的图神经网络仅通过欧几里得几何及其相关的向量空间操作来建模数据,存在局限性 我们通过提出一种数学上有根据的图卷积网络(GCN)的推广,将其扩展到常曲率空间(或其乘积空间),从而填补了这一空白。 一是引入一种统一的形式主义,可以在所有常…...

【Android开发AI实战】选择目标跟踪基于opencv实现——运动跟踪
文章目录 【Android 开发 AI 实战】选择目标跟踪基于 opencv 实现 —— 运动跟踪一、引言二、Android 开发与 AI 的融合趋势三、OpenCV 简介四、运动跟踪原理(一)光流法(二)卡尔曼滤波(三)粒子滤波 五、基于…...

系统漏洞扫描服务:安全风险识别与防护指南
系统安全的关键在于漏洞扫描服务,此服务能迅速发现潜在的安全风险。借助专业的扫描工具和技术,它确保系统稳定运作。以下将简要介绍这一服务的主要特点。 扫描原理 系统漏洞扫描服务依赖两种主要手段:一是通过漏洞数据库进行匹配࿰…...

2.Excel:滨海市重点中学的物理统考考试情况❗(15)
目录 NO12 1.数据透视表 2. 3.sum函数 4.sumifs客观/主观平均分 5.sumifs得分率 6.数字格式修改 NO3/4/5 sumifs某一组数据相加,某一范围,某一范围的具体点向下拖拉,锁定列;向左右,锁定行F4&#x…...
使用 React 16+Webpack 和 pdfjs-dist 或 react-pdf 实现 PDF 文件显示、定位和高亮
写在前面 在本文中,我们将探讨如何使用 React 16Webpack 和 pdfjs-dist 或 react-pdf 库来实现 PDF 文件的显示、定位和高亮功能。这些库提供了强大的工具和 API,使得在 Web 应用中处理 PDF 文件变得更加容易。 项目设置 首先,我们需要创建…...
驱动开发系列35 - Linux Graphics GEM Buffer Object 介绍
一:概述 在 Linux 内核中,DRM(Direct Rendering Manager)模块 是用于管理显示硬件和图形渲染的核心框架。它负责协调用户空间应用程序(例如 X Server、Wayland Compositors、Mesa 等)和 GPU 硬件之间的通信,是 Linux 图形子系统的重要组成部分。 GEM (Graphics Executio…...
Java常见的异常类有哪些?
对应异常: 空指针 → NullPointerException数据库 → SQLException数组越界 → IndexOutOfBoundsException文件丢失 → FileNotFoundExceptionIO问题 → IOException强制转 → ClassCastException方法找不到 → NoSuchMethodException数组类型错 → ArrayStoreExce…...

清华大学新闻与传播学院沈阳团队出品的《DeepSeek:从入门到精通》104页PDF
前言 本机运行DeepSeek R1大模型文章如下: Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)【保姆级万字教程】在Windows计算机部署DeepSeek大模型,给在实验室无外网的同事们用(基于Ollama和OpenWebUI…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...