当前位置: 首页 > news >正文

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. 灰度化&#xff08;Grayscale&#xff09;2. 二值化&#xff08;Thresholding&#xff09;3. 掩膜&#xff08;Mask&#xff09;4. 腐蚀&#xff08;Erosion&#xff09;5. 膨胀&#xff08;Dilation&#xff09;6. 缩放&#xff08;Scaling&#xff09;7. 旋转…...

一文讲清springboot所有注解

Spring Boot 注释是提供有关 Spring 应用程序信息的元数据。 基于 Spring 构建&#xff0c;涵盖其所有功能&#xff0c; Spring Boot 因其生产就绪环境而迅速成为开发人员的最爱&#xff0c;它允许开发人员直接专注于逻辑&#xff0c;而无需配置和设置的麻烦。 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不带参数时&#xff0c;会扫描当前目录下的所有目录、子目录中符合测试用…...

Java多线程——线程池的使用

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

NO.15十六届蓝桥杯备战|while循环|六道练习(C++)

while循环 while语法形式 while 语句的语法结构和 if 语句⾮常相似&#xff0c;但不同的是 while 是⽤来实现循环的&#xff0c; if 是⽆法实现循环的。 下⾯是 while 循环的语法形式&#xff1a; //形式1 while ( 表达式 )语句; //形式2 //如果循环体想包含更多的语句&a…...

DeepSeek 从入门到精通学习指南,2025清华大学《DeepSeek从入门到精通》正式发布104页pdf版超全解析

DeepSeek 是一款强大的 AI 搜索引擎&#xff0c;广泛应用于企业级数据检索和分析。无论您是初学者还是有经验的用户&#xff0c;掌握 DeepSeek 的使用都能为您的工作带来极大的便利。本文将从入门到精通&#xff0c;详细介绍如何学习和使用 DeepSeek。 链接: https://pan.baid…...

2025年SEO自动优化工具

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

KEPServerEX 的接口类型与连接方式的详细说明

目录 一、KEPServerEX 核心架构 二、KEPServerEX 支持的接口类型 三、KEPServerEX 支持的连接类型 1. 通用工业协议 2. 品牌专属协议 3. 行业专用协议 4. 数据库与文件接口 四、配置示例 1. 接口配置&#xff08;以OPC UA为例&#xff09; 2. 连接配置&#xff08;以…...

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 简介四、运动跟踪原理&#xff08;一&#xff09;光流法&#xff08;二&#xff09;卡尔曼滤波&#xff08;三&#xff09;粒子滤波 五、基于…...

系统漏洞扫描服务:安全风险识别与防护指南

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

2.Excel:滨海市重点中学的物理统考考试情况❗(15)

目录 NO12​ 1.数据透视表​ 2. 3.sum函数 4.sumifs客观/主观平均分​ 5.sumifs得分率​ 6.数字格式修改​ NO3/4/5​ sumifs某一组数据相加&#xff0c;某一范围&#xff0c;某一范围的具体点向下拖拉&#xff0c;锁定列&#xff1b;向左右&#xff0c;锁定行F4&#x…...

使用 React 16+Webpack 和 pdfjs-dist 或 react-pdf 实现 PDF 文件显示、定位和高亮

写在前面 在本文中&#xff0c;我们将探讨如何使用 React 16Webpack 和 pdfjs-dist 或 react-pdf 库来实现 PDF 文件的显示、定位和高亮功能。这些库提供了强大的工具和 API&#xff0c;使得在 Web 应用中处理 PDF 文件变得更加容易。 项目设置 首先&#xff0c;我们需要创建…...

驱动开发系列35 - Linux Graphics GEM Buffer Object 介绍

一:概述 在 Linux 内核中,DRM(Direct Rendering Manager)模块 是用于管理显示硬件和图形渲染的核心框架。它负责协调用户空间应用程序(例如 X Server、Wayland Compositors、Mesa 等)和 GPU 硬件之间的通信,是 Linux 图形子系统的重要组成部分。 GEM (Graphics Executio…...

Java常见的异常类有哪些?

对应异常&#xff1a; 空指针 → NullPointerException数据库 → SQLException数组越界 → IndexOutOfBoundsException文件丢失 → FileNotFoundExceptionIO问题 → IOException强制转 → ClassCastException方法找不到 → NoSuchMethodException数组类型错 → ArrayStoreExce…...

清华大学新闻与传播学院沈阳团队出品的《DeepSeek:从入门到精通》104页PDF

前言 本机运行DeepSeek R1大模型文章如下&#xff1a; Windows电脑本地部署运行DeepSeek R1大模型&#xff08;基于Ollama和Chatbox&#xff09;【保姆级万字教程】在Windows计算机部署DeepSeek大模型&#xff0c;给在实验室无外网的同事们用&#xff08;基于Ollama和OpenWebUI…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...

相关类相关的可视化图像总结

目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系&#xff0c;可直观判断线性相关、非线性相关或无相关关系&#xff0c;点的分布密…...