linux向物理地址写入数据的一种措施,linux 物理地址和虚拟地址之间的转换

一、 与页相关的数据结构及宏的定义

分页机制是硬件对分页的支持,这是虚拟内存管理的硬件基础。要想使这种硬件机制充分发挥其功能,必须有相应软件的支持,我们来看一下Linux所定义的一些主要数据结构,其分布在include/asm-i386/目录下的page.h,pgtable.h及pgtable-2level.h三个文件中。

1. 表项的定义

如上所述,PGD、PMD及PT表的表项都占4个字节,因此,把它们定义为无符号长整数,分别叫做pgd_t、pmd_t及pte_t(pte 即Page table Entry),在page.h中定义如下:

typedef struct { unsignedlong pte_low; } pte_t;

typedef struct { unsignedlong pmd; } pmd_t;

typedef struct { unsigned long pgd; }pgd_t;

typedefstruct { unsigned long pgprot; } pgprot_t;

可以看出,Linux没有把这几个类型直接定义长整数而是定义为一个结构,这是为了让gcc在编译时进行更严格的类型检查。另外,还定义了几个宏来访问这些结构的成分,这也是一种面向对象思想的体现:

#definepte_val(x)      ((x).pte_low)

#define pmd_val(x)     ((x).pmd)

#define pgd_val(x)      ((x).pgd)

从图2.13可以看出,对这些表项应该定义成位段,但内核并没有这样定义,而是定义了一个页面保护结构pgprot_t和一些宏:

typedefstruct { unsigned long pgprot; } pgprot_t;

#definepgprot_val(x)   ((x).pgprot)

字段pgprot的值与图2.13表项的低12位相对应,其中的9位对应0~9位,在pgtalbe.h中定义了对应的宏:

#define _PAGE_PRESENT   0×001

#define _PAGE_RW        0×002

#define _PAGE_USER      0×004

#define _PAGE_PWT       0×008

#define _PAGE_PCD       0×010

#define _PAGE_ACCESSED  0×020

#define _PAGE_DIRTY     0×040

#define _PAGE_PSE       0×080  /* 4 MB (or 2MB) page, Pentium+, if present.. */

#define _PAGE_GLOBAL    0×100  /* Global TLB entry PPro+ */

在你阅读源代码的过程中你能体会到,把标志位定义为宏而不是位段更有利于编码。

另外,页目录表及页表在pgtable.h中定义如下:

externpgd_t swapper_pg_dir[1024];

externunsigned long pg0[1024];

swapper_pg_dir为临时页目录表,是在内核编译的过程中被静态初始化的。pg0为初始化过程中使用的一临时页表。

2.线性地址域的定义

(1)页偏移量的位数

#define PAGE_SHIFT      12

#define PAGE_SIZE       (1UL << PAGE_SHIFT)

#define PTRS_PER_PTE    1024

#define PAGE_MASK       (~(PAGE_SIZE-1))

其中PAGE_SHIFT宏定义了页偏移量的位数为12,因此页大小PAGE_SIZE为212=4096字节; PTRS_PER_PTE为页表的项数;最后PAGE_MASK值定义为0xfffff000,用以屏蔽掉偏移量域的所有位(12位)。

(2)PGDIR_SHIFT

#define PGDIR_SHIFT     22

#define PTRS_PER_PGD    1024

#define PGDIR_SIZE      (1UL << PGDIR_SHIFT)

#define PGDIR_MASK      (~(PGDIR_SIZE-1))

PGDIR_SHIFT是页表所能映射区域线性地址的位数,它的值为22(12位的偏移量加上10位的页表);PTRS_PER_PGD为页目录目录项数;PGDIR_SIZE为页目录的大小,为222,即4MB;PGDIR_MASK为0xffc00000,用于屏蔽偏移量位与页表域的所有位。

(3)PMD_SHIFT

#definePMD_SHIFT       22

#definePTRS_PER_PMD    1

PMD_SHIFT为中间目录表映射的地址位数,其值也为22,但是对于两级页表结构,让其目录项个数为1,这就使得中间目录在指针序列中的位置被保存,以便同样的代码在32位系统和64位系统下都能使用。后面的讨论我们不再提及中间目录。

3  对页目录及页表的处理

在page.h,pgtable.h及pgtable-2level.h三个文件中还定义有大量的宏,用以对页目录、页表及表项的处理,我们在此介绍一些主要的宏和函数。

3.1.表项值的确定

staticinline int pgd_none(pgd_t pgd)          { return 0; }

staticinline int pgd_present(pgd_t pgd)       { return 1; }

#definepte_present(x)  ((x).pte_low &(_PAGE_PRESENT | _PAGE_PROTNONE))

pgd_none()函数直接返回0,表示尚未为这个页目录建立映射,所以页目录项为空。pgd_present()函数直接返回1,表示映射虽然还没有建立,但页目录所映射的页表肯定存在于内存(即页表必须一直在内存)。

pte_present宏的值为1或0,表示P标志位。如果页表项不为0,但标志位为0,则表示映射已经建立,但所映射的物理页面不在内存。

3.2. 清相应表的表项:

#definepgd_clear(xp)                          do { } while (0)

#definepte_clear(xp)   do { set_pte(xp,__pte(0)); } while (0)

pgd_clear宏实际上什么也不做,定义它可能是为了保持编程风格的一致。pte_clear就是把0写到页表表项中。

3.3.对页表表项标志值进行操作的宏。

这些宏的代码在pgtable.h文件中,表2.2给出宏名及其功能。

表2.2 对页表表项标志值进行操作的宏及其功能

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值