虚拟地址如何访问到物理地址

article/2025/9/30 10:29:30

环境:32bit CPU
一、通过二级页表映射的方式访问物理地址
在这里插入图片描述
1、取一级页表的基地址Abase1
2、取虚拟地址的前12bit[31:20]地址O1
3、计算得到新地址Apgd=(Abase1&0xFFFFF000)+O1,此地址是PGD页表上的地址,取此地址中的数据Abase2
4、取虚拟地址的中间8bit[19:12]地址O2
5、计算得到新地址Apte=(Abase2&0xFFFFFF00)+O2,此地址是PTE页表上的地址,取此地址中的数据Abase3
6、取虚拟地址的后12bit[11:0]地址O3
7、计算得到新地址Aphy=(Abase3&0xFFFFF000)+O3,此地址就是实实在在的物理地址
以上的计算和查找过程有MMU模块实现,同时会把映射信息存放在MMU中的TLB中,类似于cache,方便下次快速的查找。
二、疑问
1、一级页表的基地址存放在什么地方?
2、如何找到存放在物理地址的信息?
三、分析问题
1、操作系统有个专门的结构体负责进程的内存使用情况,task_struct里面的mm_struct

struct task_struct {......int on_rq;int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;......struct mm_struct *mm, *active_mm;struct mm_struct {......unsigned long mmap_base;		/* base of mmap area */unsigned long mmap_legacy_base;         /* base of mmap area in bottom-up allocations */unsigned long task_size;		/* size of task vm space */unsigned long highest_vm_end;		/* highest vma end address */pgd_t * pgd;atomic_t mm_users;			/* How many users with user space? */atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */atomic_long_t nr_ptes;			/* PTE page table pages */......

其中pgd保存的就是一级页表的基地址。进程切换时,会把TTBRx寄存器(上图所示)保存起来,把下一个进程的pgd内容写到TTBRx寄存器中。
2、写段程序,找到存放信息的物理地址
2.1、内核态代码
根据上面所描述的页表映射方式,查找到虚拟地址对应的物理地址
需要在内核态下面运行,内核态下可以获取当前进程的PCB task_struct进而获取mm_struct内存管理模块

#include <linux/init_task.h>
unsigned int get_phy_addr(struct mm_struct *mm, unsigned long addr)
{pgd_t *pgd        = NULL;pud_t *pud        = NULL;pmd_t *pmd        = NULL;pte_t *pte        = NULL;unsigned int phy_addr = 0;printk("pgd_base = %p\n",mm->pgd);pgd = pgd_offset(mm, addr);                                  //一级页表项的地址printk("vaddr=[0x%08x] *pgd=%08x\n", addr, pgd_val(*pgd));if (pgd_none(*pgd))goto out;if (pgd_bad(*pgd)) {printk("pgd bad\n");goto out;}pud = pud_offset(pgd, addr);printk("pud=0x%08x,*pud=%08x\n", pud, pud_val(*pud));if (pud_none(*pud))goto out;if (pud_bad(*pud)) {printk("pud bad");goto out;}pmd = pmd_offset(pud, addr);printk("pmd=0x%08x,*pmd=%08x\n", pmd, pmd_val(*pmd));if (pmd_none(*pmd))goto out;if (pmd_bad(*pmd)) {printk("(bad)");goto out;}//二级映射,pmd等于pgd。函数中实现两个功能:1、根据pgd地址查找二级页表基地址;2、二级页表基地址和addr算出二级页表地址pte = pte_offset_map(pmd, addr);     printk("pte=0x%08x, *pte=%08x\n", pte, pte_val(*pte));if(!pte_none(*pte) && pte_present(*pte)) {phy_addr = (pte_val(*pte) & 0xFFFFF000) | (addr & 0xFFF);printk("phy_addr is 0x%x\n", phy_addr);}else{printk("pte is not present\n") ;}pte_unmap(pte);return phy_addr;
out:return -1;
}

2.2、/dev/mem节点说明
知道虚拟地址对应的物理地址,我们就可以借助/dev/mem节点访问对应的物理地址查看是否是虚拟地址存放的数据。
/dev/mem是系统物理内存的映像文件,这里的物理内存是指我们插在内存槽上的内存条吗?当然是,但物理内存不单单指内存条。
物理内存严格来讲应该是指 物理地址空间 ,内存条只是映射到这个地址空间的一部分,其余的还有各种PCI设备,IO端口等。
我们可以从/proc/iomem中看到这个映射:

cat /proc/iomem

在这里插入图片描述
其中 内存分配的物理地址是0x80000000~0x83FFFFFF 64M
事实上,它就是一个活着的Linux系统实时映像,所有的进程task_struct结构体,sock结构体,sk_buff结构体,进程数据等等都在里面的某个位置:
在这里插入图片描述
如果能定位它们在/dev/mem里的位置,我们就能得到系统中这些数据结构的实时值,所谓的调试工具所做的也不过如此。其实我们在调试内核转储文件的时候,vmcore也是一个物理内存映像,和/dev/mem不同的是,它是一具尸体。
无论是活体,还是尸体,均五脏俱全,分析它们的手段是一致。和静态分析vmcore不同的是,/dev/mem是一个动态的内存映像,有时候借助它可以做一些正经的事情。
2.3、应用层获取/dev/mem的映射

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>int main(int argc, char *argv[])
{int i = 0, fd = 0;unsigned int addr = 0, content 	= 0;unsigned int page_size        	= getpagesize();unsigned int taddr        		= 0;unsigned int *map_base        	= NULL;unsigned int offset_in_page 		= 0;printf("page_size=0x%x\n", page_size);fd = open("/dev/mem", O_RDWR|O_SYNC);if (fd == -1) {printf("open /dev/mem error.\n");return -1;}taddr = strtoll(argv[1], NULL, 16);offset_in_page = taddr & (page_size - 1);//map_base = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, taddr & (~(unsigned int)(page_size - 1)));map_base = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, fd, taddr & (~(unsigned int)(page_size - 1)));if (-1 == (int)map_base) {printf("mmap failed!, errno=%d\n", errno);close(fd);return -1;}printf("map_base=0x%x\n", map_base);addr = (unsigned int)(((unsigned char *)map_base) + offset_in_page);printf("addressx:0x%x\n", addr);printf("content 0x%x\n\n", *(unsigned int *)(addr));//*(unsigned int *)(addr) = 0x6f6a6944;close(fd);munmap(map_base, page_size);return 1;
}

2.4、测试程序

测试程序:
int main(int argc, char** argv)
{int fd                        = -1;struct param_s param;char *buf = "Chinaxxxxx.\n";memset(&param, 0x00, sizeof(struct ty_motor_param_s));fd = open("/dev/motor", O_RDWR);if (fd < 0) {printf("open error.\n");return 0;}printf("buf=0x%x", buf);param.addr = buf;ioctl(fd, IOCTL_SET, &param);close(fd);sleep(10);printf("buf=0x%x", buf);return 0;
}

2.5、实验开始
2.5.1、运行2.4程序,通过ioctl运行内核代码,执行2.3程序get_phy_addr函数,获取物理地址。
2.5.2、通过传入获取到的物理地址,运行2.2程序,打印物理地址的信息。
在这里插入图片描述
其中0x83e6573c是获取的物理地址
ARM处理器小端存储数据,因此0x43 0x68 0x69 0x6e 刚好对应着Chinaxxxxx中的Chin的Ascii码值
2.6、扩展
2.6.1、既然知道物理地址了,是不是可以修改物理地址里面的内容?
2.6.2、打开2.3代码的注释 *(unsigned int *)(addr) = 0x6f6a6944;
2.6.3、再操作2.5中的步骤,发现原先的Chinaxxxxx被修改了
在这里插入图片描述

3、遇到的问题
3.1.1、2.3中的代码mmap一直返回-1,错误码一直是1(errno 1 Operation not permitted)
3.1.2、解决方法
在.config文件中设置CONFIG_STRICT_DEVMEM is not set

正如上面描述的,通过获取物理地址修改物理地址里面的数据,这对系统来说就毫无安全可言。因此内核通过CONFIG_STRICT_DEVMEM配置项禁止内存空间实现映射。


http://chatgpt.dhexx.cn/article/lYOMXAhk.shtml

相关文章

总线地址、物理地址、虚拟地址

1、总线地址 地址总线&#xff08;Address Bus&#xff09;是一种计算机总线&#xff0c;是CPU或有DMA能力的单元&#xff0c;用来沟通这些单元想要访问&#xff08;读取/写入&#xff09;计算机内存组件/地方的物理地址。 其实就是CPU能够访问内存的范围。 CPU寻找外部的内…

虚拟地址空间和物理地址空间

1.概念 物理地址&#xff1a;物理地址空间是实在的存在于计算机中的一个实体&#xff0c;在每一台计算机中保持唯一独立性。我们可以称它为物理内存&#xff1b;如在32位的机器上&#xff0c;物理空间的大小理论上可以达到2^32字节(4GB)&#xff0c;但如果实际装了512的内存&a…

Linux虚拟地址空间

目录 父子进程地址相同的变量值不同问题运行结果 Linux下进程虚拟地址空间分布什么是虚拟地址空间&#xff1f;进程直接访问物理内存&#xff08;无虚拟空间&#xff09;再述虚拟地址空间&#xff01;虚拟地址空间结构体是如何区域划分?解答最初的问题延伸问题: 一个pid变量怎…

虚拟地址空间

对于每一个进程都会对应一个虚拟地址空间&#xff0c;对于32位的操作系统&#xff08;其指令的位数最大为32位&#xff0c;因此地址码最多32位&#xff09;&#xff0c;虚拟地址空间的大小为B即0~4GB的虚拟地址空间&#xff0c;其中内核空间为1GB&#xff0c;如下所示&#xff…

逻辑地址、物理地址、虚拟地址

文章目录 物理地址(physical address)虚拟地址(virtual memory)逻辑地址(logical address)线性地址(linear address)或也叫虚拟地址(virtual address)地址转换 物理地址(physical address) 用于内存芯片级的单元寻址&#xff0c;与处理器和CPU连接的地址总线相对应。 虽然可以…

CPU中虚拟地址、逻辑地址(有效地址)、线性地址、物理地址

虚拟地址、逻辑地址&#xff08;有效地址&#xff09;、线性地址、物理地址 1、虚拟地址2、逻辑地址&#xff08;有效地址&#xff09;3、线性地址4、物理地址5、总结 1、虚拟地址 在实模式下&#xff0c;虚拟地址是指由程序产生的由段选择符和段内偏移地址组成的地址。经过CPU…

虚拟地址和物理地址

1、地址概念 物理地址&#xff1a;物理内存就是真实的内存&#xff0c;CPU的地址线可以直接进行寻址的内存空间大小。比如在32位平台下&#xff0c;寻址的范围是2^32也就是4G&#xff0c;并且这是固定的。在实际的应用中&#xff0c;很多的应用程序都比较大&#xff0c;计算机…

Linux操作系统~什么是虚拟地址?深度剖析进程地址空间

目录 1.所以进程的地址空间是什么呢&#xff1f; 2.mm_struct内部有什么&#xff1f; 3.虚拟地址空间与物理内存如何关联 页表 4.为什么设计这样一个进程地址空间&#xff0c;不让程序直接访问内存 Q&#xff1a;为什么子进程修改值以后&#xff0c;地址还是相同&#xf…

初识虚拟地址空间

物理地址和虚拟地址 物理寻址&#xff1a;CPU访问存储器的最原始方法就是直接用物理地址&#xff08;Physical Address, 可简称PA&#xff09;。物理地址是唯一的。 虚拟寻址&#xff1a;CPU通过生成一个虚拟的地址来访问内存&#xff0c;在访问前会把虚拟地址转化为物理地址…

虚拟地址空间,虚拟文件系统

1、虚拟地址空间 1、概念与原因 虚拟地址空间是一个抽象的概念&#xff0c;在IBM中&#xff0c;这样说道&#xff1a;它存在&#xff0c;但你看不见&#xff0c;就是虚拟的。虚拟地址空间就是这样一个东西。&#xff08;注意区分虚拟内存与虚拟地址空间&#xff09; 虚拟地址空…

彻底搞懂虚拟内存,虚拟地址,虚拟地址空间

程序经过编译后&#xff0c;变成了可执行的文件&#xff0c;可执行文件主要包括代码和数据两部分&#xff0c;代码是只读的&#xff0c;数据则是可读可写的。 可执行文件由操作系统加载到内存中&#xff0c;交由CPU去执行&#xff0c;现在问题来了&#xff0c;CPU怎么去访问代…

使用POI导出Excel(并使用公式)

使用POI导出Excel&#xff08;并使用公式&#xff09; 使用java直接生成Excel并填充数据 可以参考POI官方文档&#xff0c;就是对Sheet&#xff0c;row&#xff0c;cell&#xff0c;Formula等操作&#xff0c; https://poi.apache.org/components/index.html 这种方式也可以生成…

poi导出excel日期格式问题

POI导出Excel的时候有时需要日期格式&#xff0c;在筛选时是这样的 private XSSFWorkbook wb null; String dateFormat "yyyy-MM-dd";//或者"yyyy/MM/dd"格式,"yyyy/M/d"这样的格式不会自动补0 public void setCell(int index,Date value,bool…

POI导出Excel详细教程

文章目录 前言一、引入jar包依赖二、创建自定义导出Excel样式类三、创建核心导出工具类四、创建导出对象实体Bean五、具体使用案例5.1.创建SQL脚本和初始化数据5.2.写一个查询所有学生信息接口5.3.查询学生基本信息返回数据格式5.4.导出Excel方法5.5.通过页面导出按钮导出Excel…

Java使用POI导出Excel文件

Java使用POI导出Excel文件 POI概述Apache POI 下载依赖引用关系图如下所示:直接下载Maven下载 POI实例总结 POI概述 HSSF 是 POI 项目的 Excel 97(-2007) 文件格式的纯 Java 实现。XSSF 是 POI 项目的 Excel 2007 OOXML (.xlsx) 文件格式的纯 Java 实现。 HSSF 和 XSSF 提供了读…

Java用POI导出Excel表格中的数据

poi操作Excel 主要通过HSSF,XSSF两种方式。 HSSF只能解析.xls格式的excel文件&#xff0c;XSSF支持.xls与.xlsx两种格式。 功能&#xff1a; 传递一个Excel文件&#xff0c;拿到里面所有的数据&#xff0c;返回一个集合。 Excel中的数据是什么类型&#xff0c;就返回什么类型的…

springboot+poi导出excel

在web开发中经常遇到将数据写入excel并导出的需求&#xff0c;下面整理springbootpoi实现导出excel的实例。 搭建springboot工程&#xff0c;引入依赖&#xff0c;细节不在赘述。 引入poi依赖 <dependency><groupId>org.apache.poi</groupId><artifactId…

POI实现导入导出excel

poi在日常的导入导出中是比较常用到的&#xff0c;最近也总结了下接触到的poi相关的导入导出的一些代码&#xff0c;有问题可以指出&#xff1a; package com.poi;import km.org.apache.poi.hssf.usermodel.*; import km.org.apache.poi.hssf.util.HSSFColor; import km.org.a…

java使用Poi导出excel表格

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) 在之前的一篇文章java操作Excel实战干货中展示了使用poi库读取excel表格的的用法&#xff0c;今天演示另一个常用功能&#xff0c;将数据导出到excel中&#xff…

POI导出Excel文件中文乱码

使用POI组件生产Excel文件时中文乱码&#xff0c;总结后可能错误原因如下&#xff1a; 后台导出Excel文件格式混乱 POI组件可生成.xls和.xlsx两种格式的Excel文件&#xff0c;设置文件格式时应注意与导出的格式相匹配。如果文件格式设置出错&#xff0c;则会出现以下错误&…