Linux 内核虚拟地址到物理地址转换讨论
来源:互联网 发布:数据挖掘算法有哪些 编辑:程序博客网 时间:2024/05/22 23:01
首先我们基于平坦型物理内存,单个node,下面是基于64位ARMv8架构得到,其他架构也有类似结论:首先我们知道在我们成功编译好kernel后会生成一个system.map文件,其给出了内核整个虚拟地址空间情况,比如:
ARM64:整个内核空间起始地址:ffffffc000080000 T _text
代码段起始地址:ffffffc000080160 T stext
异常向量表地址:ffffffc000083000 T vectors
ffffffc0010890b8 B __bss_startffffffc0010890b8 D _edata
ffffffc00191ab58 B mem_mapffffffc00191ab60 B max_mapnr
ffffffc001c7dd28 B __bss_stopffffffc001c7e000 B idmap_pg_dirffffffc001c80000 B swapper_pg_dirffffffc001c82000 B _end
ARM:
c0003000 A swapper_pg_dirc0008000 T _textc0008000 T stextc0008090 t __create_page_tablesc0008168 t __turn_mmu_on_locc0008174 T secondary_startupc00081e0 T __secondary_switchedc00081ec t __secondary_datac00081f8 t __enable_mmuc0008220 t __vet_atagsc0008280 T __exception_text_startc0008280 T _stextc0008280 T asm_do_IRQc0008284 T do_undefinstr
c0caccb8 b suspend_timec0caccc0 b last_transmitc0caccc8 b activity_lockc0caccd0 b klist_remove_lockc0caccd4 B __bss_stopc0caccd4 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 内核虚拟地址到物理地址转换讨论
- Linux 内核 虚拟地址 物理地址 转换
- Linux 内核 虚拟地址 物理地址 转换
- Linux 虚拟地址 物理地址 转换
- Linux内核层虚拟地址和物理地址转换函数
- Linux 内核空间虚拟地址和物理地址相互转换
- linux虚拟地址到物理地址
- MIPS虚拟地址到物理地址转换过程
- #SC2440虚拟地址到物理地址的转换
- 虚拟地址到物理地址的转换
- 虚拟地址到物理地址的转换
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- Linux 从虚拟地址到物理地址
- 编译原理中的first集,follow集和selec集的小解
- Android学习笔记:Bluetooth
- 关于Android开发中有关权限的问题
- activiti 自动部署配置
- sql转psql
- Linux 内核虚拟地址到物理地址转换讨论
- copy
- Web应用从服务器主动推送数据到客户端有哪些方式?
- linux 堆溢出学习之house of spirit(1) malloc maleficarum hos翻译
- servlet实现文件上传
- 日语动词变形
- 函数模板
- 在Qt编写的程序中打开文件夹~Windows Explore
- MyEclipse2014安装插件的几种方式(适用于Eclipse或MyEclipse其他版本)