Linux 内核虚拟地址到物理地址转换讨论

2024-02-17 14:58

本文主要是介绍Linux 内核虚拟地址到物理地址转换讨论,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先我们基于平坦型物理内存,单个node,下面是基于64位ARMv8架构得到,其他架构也有类似结论: 首先我们知道在我们成功编译好kernel后会生成一个system.map文件,其给出了内核整个虚拟地址空间情况,比如:

ARM64: 整个内核空间起始地址: ffffffc000080000 T _text

代码段起始地址: ffffffc000080160 T stext

异常向量表地址: ffffffc000083000 T vectors

ffffffc0010890b8 B __bss_start ffffffc0010890b8 D _edata

ffffffc00191ab58 B mem_map ffffffc00191ab60 B max_mapnr

ffffffc001c7dd28 B __bss_stop ffffffc001c7e000 B idmap_pg_dir ffffffc001c80000 B swapper_pg_dir ffffffc001c82000 B _end

ARM:

c0003000 A swapper_pg_dir c0008000 T _text c0008000 T stext c0008090 t __create_page_tables c0008168 t __turn_mmu_on_loc c0008174 T secondary_startup c00081e0 T __secondary_switched c00081ec t __secondary_data c00081f8 t __enable_mmu c0008220 t __vet_atags c0008280 T __exception_text_start c0008280 T _stext c0008280 T asm_do_IRQ c0008284 T do_undefinstr

c0caccb8 b suspend_time c0caccc0 b last_transmit c0caccc8 b activity_lock c0caccd0 b klist_remove_lock c0caccd4 B __bss_stop c0caccd4 B _end

对于ARM来说,32位和64位明显不同。

 

对整个内核空间代码和数据来说,由于他们是直接映射的,我们这里讨论起来非常简单

对于这些地址,内核通过宏__pa()找到这些虚拟地址对应的物理地址。或者通过__va()找到物理地址对应

的虚拟地址。

arch/arm64/include/asm/memory.h #define __pa(x)   __virt_to_phys((unsigned long)(x)) #define __va(x)   ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) #define virt_to_pfn(x)      __phys_to_pfn(__virt_to_phys(x))

继续看定义:

include/asm-generic/memory-module.h #define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))

#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) #define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT)

#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) #define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + ARCH_PFN_OFFSET)

这里需要注意PAGE_OFFSET和PHYS_OFFSET定义,前者是整个内核空间开始的虚拟地址,一般跟体系结构相关,

如经典32为X86和ARM为0xC0000000,即3GB处。对于64位来说,一般为0xFFFFFFC000000000 而PHYS_OFFSET则为物理内存起始地址,一般来说,这个偏移跟芯片设计相关,这个偏移表示了访问DDR最低的地址线。

比如说,如果PHYS_OFFSET为1GB,DDR大小为2GB,那么有效访问DDR空间的地址必须是

0x40000000--0xC0000000之间。

在我们上面给出的system.map中的虚拟地址可以看到, 内核虚拟地址起始地址起始为0xFFFFFFC000000000,这个由内核定义的PAGE_OFFSET给出。 而内核真正开始的使用的地址为0xffffffc000080000这里有个偏移量,大小为128个页(4KB)。总大小为512kB字节。

在本实验上测试,得到PHYS_OFFSET为0x8800000,即136MB开始处。

可以看到,一个内核中的虚拟地址,即0xFFFFFFC000000000以上的地址,如果寻找其物理地址,使用__pa()宏非常简单,

比如上面的mem_map的虚拟地址为0xffffffc00191ab58,其减去起始虚拟地址0xFFFFFFC000000000后为0x0191ab58,

然后根据物理地址偏移情况,得到真正的物理地址:0x0191ab58 + PAGE_OFFSET = 0x0191ab58 + 0x8800000

= 0xA11AB58 可以看到,mem_map的物理地址为0xA11AB58。 那么对于这个物理地址,对应的页帧号为多少呢?即PFN为多少,这时需要使用上面的__phys_to_pfn(). 可以看到,直接进行右移即可。例如对于上面的mem_map来说,其页帧为0xA11A。

那么对于一个PFN,其对应的物理page描述符是多少呢?这时需要使用宏__pfn_to_page(),注意这里使用的 ARCH_PFN_OFFSET,其就是偏移PHYS_OFFSET对应的页帧号,上面为0x8800000则对应页帧为0x8800,则上面mem_map对应的页帧号 为0xA11A -  0x8800 = 0x191A ,然后再根据mem_map数组,即 mem_map[0x191A]为mem_map的页描述符。

 

 

这篇关于Linux 内核虚拟地址到物理地址转换讨论的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/718115

相关文章

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

Linux安装MySQL的教程

《Linux安装MySQL的教程》:本文主要介绍Linux安装MySQL的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux安装mysql1.Mysql官网2.我的存放路径3.解压mysql文件到当前目录4.重命名一下5.创建mysql用户组和用户并修

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Linux系统之dns域名解析全过程

《Linux系统之dns域名解析全过程》:本文主要介绍Linux系统之dns域名解析全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、dns域名解析介绍1、DNS核心概念1.1 区域 zone1.2 记录 record二、DNS服务的配置1、正向解析的配置