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…...
Neo-Launcher数据库架构:数据存储和管理的深度解析
Neo-Launcher数据库架构:数据存储和管理的深度解析 【免费下载链接】Neo-Launcher Neo-Launcher 项目地址: https://gitcode.com/gh_mirrors/ne/Neo-Launcher Neo-Launcher是一款由Neo Collective开发的开源启动器应用,其高效的数据存储和管理系统…...
计算内存(CIM)技术解析与AI硬件加速实践
1. 计算内存(CIM)技术解析:突破传统架构的能效瓶颈 在AI硬件加速领域,计算内存(Compute-in-Memory, CIM)正引发一场架构革命。传统冯诺依曼架构中"内存墙"问题已成为制约AI计算效率的主要瓶颈——…...
IP2366至为芯支持C口双向快充的140W多串锂电池充放电SOC芯片
英集芯IP2366是一款应用于移动电源、电动工具、智能家居、储能电源等方案的多串锂电池充电SOC芯片。支持高达140W的双向同步升降压充放电,充电电流可达5A。支持2至6节锂电池/磷酸铁锂电池串联,集成PD3.1、QC3.0等多种快充协议。内置14bit ADC,…...
高速SerDes设计中BER预测的智能应力输入方法
1. 高速串行链路设计中的BER预测挑战在当今高速数字系统设计中,SerDes(串行器/解串器)技术已成为主流接口方案,数据传输速率已突破10Gbps大关。随着速率提升,信号完整性(SI)问题日益突出,其中误码率(BER)预…...
DeepSeek Clean Code终极阈值(v2.3.1正式版):超出3个指标即触发强制重构——你达标了吗?
更多请点击: https://intelliparadigm.com 第一章:DeepSeek Clean Code终极阈值的演进与哲学内核 DeepSeek Clean Code 的“终极阈值”并非静态指标,而是代码可维护性、语义清晰度与执行确定性三者动态收敛的临界点。它源于对 LLM 推理链中 …...
2026金铲铲之战电脑版模拟器实测:选对模拟器轻松上分
一、实测前提说明作为拥有三年游玩经验的金铲铲之战老弈士,从手机端切换到电脑端游玩后,大屏在阵容运营、棋子对位、选秀博弈上的优势十分突出:手机小屏不仅看不清棋子星级、装备细节,频繁触屏操作还容易误触卖错棋子、放错站位&a…...
QQ音乐加密文件解密终极指南:qmcdump实战深度解析
QQ音乐加密文件解密终极指南:qmcdump实战深度解析 【免费下载链接】qmcdump 一个简单的QQ音乐解码(qmcflac/qmc0/qmc3 转 flac/mp3),仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump 你是否遇到…...
学术合规性危机预警:Perplexity生成内容如何精准适配Chicago第17版?,一文锁定98.7%高校期刊投稿要求
更多请点击: https://intelliparadigm.com 第一章:学术合规性危机预警:Perplexity生成内容如何精准适配Chicago第17版? 随着AI辅助写作工具在人文社科领域的深度渗透,Perplexity等生成式平台输出的引文、脚注与参考文…...
告别SVN提交冲突!手把手教你配置TortoiseSVN 1.10.5的忽略列表与清理功能
告别SVN提交冲突!手把手教你配置TortoiseSVN 1.10.5的忽略列表与清理功能 团队协作开发中,版本控制系统是必不可少的工具。Subversion(SVN)作为一款经典的集中式版本控制系统,至今仍在许多项目中发挥着重要作用。然而&…...
音频变压器关键参数深度解析:Z值与最大电流的工程实践
音频变压器关键参数深度解析:Z值与最大电流的工程实践引言在专业音频系统、高保真音响以及工业信号隔离场景中,音频变压器始终扮演着不可替代的角色。它的核心使命是在保持信号完整性的同时,完成阻抗匹配、地环路隔离和信号平衡转换三大任务。…...
