【无标题】

本文介绍了如何在用户态通过/proc/[pid]/pagemap节点来获取虚拟地址对应的物理地址。首先,解释了从虚拟地址到物理地址的转换过程,涉及到页帧号和低12位的计算。然后,提供了在用户态读取pagemap文件的步骤,包括计算offset、读取pte和转换为物理地址的细节。最后,通过示例代码展示了内存分配前后的pte变化,验证了内存分配的过程。
摘要由CSDN通过智能技术生成

1、将虚拟地址传入到内核态,借助内核态中mm_struct结构体的pgd页表基地址成员,经过查页表的方式最终获取到物理地址。这种方法虽然很直观,但是一会内核态,一会用户态,操作起来相对表麻烦。虚拟地址如何访问到物理地址_sydyh43的博客-CSDN博客_虚拟地址计算物理地址但是有一点可以明确的,转换出来,获取到的是页帧号(即页对齐),最后加上虚拟地址的低N位(32bit的系统是低12位)得到最终的物理地址。

2、内核开发者会把很多基于内核的操作挪到用户态实现。借助用户态众多的系统接口实现与之前在内核态一样的功能。虚拟地址转换成物理地址就是这么一个例子。

通过

man proc

查看到其中有一项/pro/[pid]/pagemap,可以看出54~0就是对应着物理地址的页帧号,再加上虚拟地址的低12位,就是虚拟地址对应的物理地址。

3、 在用户态,读取/proc/[pid]/pagemap这个节点的数据,获取物理内存的页帧号。

3.1、进程下有很多虚拟地址,pagemap文件相当于存放物理地址的一张表格,需要根据虚拟地址获取到在这张表格的下标,这个下标对应的表格,存放的就是这个虚拟地址对应的物理地址等信息。

#ifdef _ENV_IS_64_
#define PAGEMAP_SIZE    sizeof(unsigned long)
#else
#define PAGEMAP_SIZE    sizeof(unsigned long long)
#endif

/*
*    1、需要把addr转换成页帧,即下标
*    2、每个下标存放数据的空间是PAGESIZE,需要乘以PAGEMAP_SIZE
*    3、unsigned long的sizeof由CPU环境决定。32bit是4, 64bit是8
*/
size_t offset = (addr/4096) * PAGEMAP_SIZE;	

3.2、获取pagemap中的数值后,最终转换成实际的物理地址

/*
*    1、获取pte后,&上地55bit都是高的数值
*    2、左右12bit,加上低12bit的偏移量,获得最终的物理地址
*/
read(fd, &pte, PAGEMAP_SIZE);
phy_addr = ((pte & ((((unsigned long)1) << 55) - 1)) << 12) + addr%4096;

3.3、此刻,我们来验证一下bit63的数值变化,感知下用户态malloc一段内存空间后,暂没有分配内存空间,而是当使用到的时候才会分配实际的物理内存。

有些平台使用的时候,proc目录下没有pagemap的节点,需要打开对应(fs/proc/base.c)的宏CONFIG_PROC_PAGE_MONITOR

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define _ENV_IS_32_

#ifdef _ENV_IS_64_
#define PAGEMAP_SIZE    sizeof(unsigned long)
#else
#define PAGEMAP_SIZE    sizeof(unsigned long long)
#endif

int main(int argc, char **argv)	
{	
	int fd 		 = 0;
	pid_t pid	 = 0;
	char bit_val = 0;
	unsigned long addr = 0;
	unsigned long phy_addr = 0;
#ifdef _ENV_IS_64_
	unsigned long pte;
#else
	unsigned long long pte;
#endif
	size_t offset = 0;
	char procbuf[64] = {0};

	pid = getpid();	
	sprintf(procbuf, "/proc/%d/pagemap", pid);
	addr = (unsigned long)malloc(100);
	if (!addr) {
		printf("malloc error.\n");
		return -1;
	}
	fd = open(procbuf, O_RDONLY);
	offset = (addr/4096) * PAGEMAP_SIZE;
	lseek(fd, offset, SEEK_SET);
	read(fd, &pte, PAGEMAP_SIZE);
	phy_addr = (pte & 0x7FFFFFFFFFFFFF)*4096 + addr%4096;		//(((1) << 55) - 1)
	bit_val = !!(pte & 0x8000000000000000);					//((1) << 63)
	printf("\nbef: pte=0x%llx, phy addr:%x, in ram:%d\n", pte, phy_addr, bit_val);

	memset((char *)addr, 0x00, 100);
	lseek(fd, offset, SEEK_SET);
	read(fd, &pte, PAGEMAP_SIZE);
	phy_addr = (pte & 0x7FFFFFFFFFFFFF)*4096 + addr%4096;
	bit_val = !!(pte & 0x8000000000000000);
	printf("aft: pte=0x%llx, phy addr:%x, in ram:%d\n", pte, phy_addr, bit_val);	
	
	close(fd);
	
	return 0;	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值