linux 内核参数 pte,Linux下通过线性地址得到页表项pte(X86和龙芯2F下)

在Linux中,内核的页面映射机制分为三层,页面目录和页面表中间设有一个“中间目录”。中间目录是为了对64位CPU兼容而设计的。在内核代码中,页面目录称为PGD,中间目录称为PMD,页面表成为PT, PT中的表项称为PTE, 是“page table entry的缩写”。

一个进程的线性地址从高位到低位划分为4个段,各占若干位,分别作用为目录PGD中的下标,中间目录PMD的下标、页面表的下标以及物理页面内的位移。因此,给定一个线性地址,利用其前面三个段,就可以得到这个线性地址对应的pte。本文将分别阐述如何在X86以及龙芯2f下通过线性地址来得到对应的pte。

我们都知道,每一个进程都有一个task_struct结构,这个结构也就是我们通常所说的PCB。linux内核提供一个指针current,该指针指向当前进程的task_struct结构。通过current指针我们能得到当前进程的mm_struct结构。mm_struct结构是进程整个用户空间的一个抽象。通过进程的mm_struct我们就可以得到进程的pgd,然后按照线性地址的组成,我们就可以一步一步的得到线性地址对应的pte。

我的实验是基于这么一个框架完成的:写一个模块,模块注册一个设备,我们可以通过write系统调用向这个设备中写一个线性地址,模块会通过printk打印出对应的pte。

让我们现来分析下从32位的x86下如何得到线性地址的pte。在32为的x86下,线性地址为32bit,PGD位段大小为10,也就是说线性地址前10位表示目录项在页面目录中的下标,通过这个下标就能得到对应的目录项。因为i386结构物理上是二层映射,所以linux把PMD的位段大小设为0,也就是把PMD给mask掉了。目录项逻辑上指向一个大小为1的中间目录PMD,但是物理上直接指向相应的页面表(PT),i386的内存管理单元并不知道PMD的存在。PT的位段大小也为10,以PT位段为下标就能得到相应的表项PTE。

在实际的操作中,内核提供了一些函数来简化这些取位的操作,函数将在代码中做简单的介绍。这里主要介绍取pte的方法和思路,对模块实现的细节也不做解释。

X86下实现该模块的代码如下:

#include

#include

#include

#include

#include

#include

//#include

#include

#include

MODULE_LICENSE("Dual BSD/GPL");

/*这个函数的目的是把一个字符串类型的线性地址转化成整型,可以忽略这个函数的实现过程*/

int convert_vaddr(char *buff, int count){

//该函数的输入是一个字符串和字符串长度,如"8048000, 8",输出是一个int型整数,如0x8048000

//具体形式在下面给出

}

/*模块的主要函数,该函数输入一个线性地址,然后将该地址对应的pte打印出来*/

int event_write(struct file *filp, char __user *buff, size_t count,

loff_t *f_ops){

struct mm_struct *mm;

pgd_t *pgd;

pmd_t *pmd;

pud_t *pud;

pte_t *pte;

char buff_k[count];

int vaddr;

unsigned long pa;

if(copy_from_user(buff_k,buff,count)) //将线性地址从用户空间拷贝到内核空间

return -EFAULT;

if((vaddr = convert_vaddr(buff_k,count))==-EINVAL) //将字符串类型的线性地址转换成int型

return -EINVAL;

mm = current->mm; //获得当前进程的mm_struct

pgd = pgd_offset(mm, vaddr); //pgd_offset函数通过mm_struct和线性地址得到该地址对应的页面目录项

pud = pud_offset(pgd,vaddr); //pud是page uper directory,是pgd和pmd之间的一层映射,在i386的两级映射中不起作用

pmd = pmd_offset(pud,vaddr); //这里使用pud_offset和pmd_offset仅讲pgd的值类型转换后传承下来。

pte = pte_offset_kernel(pmd, vaddr); //pte_offset_kernel 根据线性地址和pmd,找到该线性地址对应的页表项。

pa = pte_val(*pte) ; //得到pte的内容

printk("current process's pte is:%x\n",pa);

printk("tex_d41d8cd98f00b204e9800998ecf8427e.giftex_d41d8cd98f00b204e9800998ecf8427e.giftex_d41d8cd98f00b204e9800998ecf8427e.gif

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值