PAE Paging

PAE Paging与32-Bit Paging的区别

PAE Paging与32-Bit Paging的不同点在于PAE Paging可将32-Bit的线性地址转换成最高52位的物理地址,不过受到线性地址宽度的限制,最高可访问的线性地址空间还是4G。还有就是PAE Paging使用4个PDPTE寄存器进行地址转换,CR3寄存器保存这4个PDPTE寄存器的物理地址。这样在地址转换时可以使用更多的地址转换结构,而不是像32-Bit Paging那样都是从CR3开始的一组地址转换结构。


开启PAE Paging的条件

首先要通过CPUID指令来查询CPU是否支持PAE Paging,如果CPUID.01H:EDX.PAE [bit 6] = 1表示CPU支持PAE Paging,否则不支持。其次是CPUID.80000008H:EAX[7:0]表示最高的物理地址宽度,这里MAXPHYADDR最高可达52位,如果MAXPHYADDR<52那么,转换后的物理地址中52:MAXPHYADDR都是0。

当CR0.PG = 1, CR4.PAE = 1, and IA32_EFER.LME = 0时开启PAE Paging。同样这个设置顺序是有要求的,不能够随意设置,否则会触发#GP异常。


PDPTE寄存器

开启PAE Paging之后,地址转换的顶层结构来源于CPU内部使用4个寄存器,这4个寄存器分别是PDPTE0、PDPTE1、PDPTE2和PDPTE3,每一个寄存器对应1G的地址空间。

开启PAE Paging之后,CR3中保存这叫做“page-directory-pointer table”的物理地址,page-directory-pointer table一共有4项,每一项是一个64位的单元,叫做PDPTE。在特定的时候,CPU会从CR3指定的物理地址中将page-directory-pointer table的4项加载到4个PDPTE寄存器中。

下图是开启PAE Paging之后CR3的结构:


通过CR3来计算page-directory-pointer table的地址:

  • 31:5位来源于CR3的31:5位
  • 4:0位是0

CPU中的PDPTE寄存器内容不是一成不变的,如下的时候CPU把CR3保存的物理地址中的内容加载到PDPTE寄存器:

  • 开启PAE Paging后,CR0和CR4中与分页有关的位被修改的时候。
  • CR3改变的时候。
  • 任务切换改变CR3的时候。

下图是PDPTE的结构:


加载PDPTE的过程中如果发现PDPTE.P = 0或者任何保留位被设置了就会触发#GP异常,并且不会加载PDPTE。


地址转换

PAE Paging可以将32位的线性地址转换成4-KByte或者2-MByte的页,这主要取决于PDE.PS,如果PDE.PS=1则使用2-MByte的页,否则使用4-KByte的页。PAE Paging与32-Bit Paging不同的是地址转换结构,如PDE,PTE等都是64位的。

2-MByte Page

下图是Intel手册中使用PAE将线性地址转换成2-MByte页的过程:


PDE的结构:


2-MByte Page的情况下从线性地址转换到物理地址的过程:

  1. 通过线性地址的31:30位来选择PDPTE寄存器:
  2. 通过PDPTE寄存器来计算PDE的地址:
    • PDE的51:12位来自于PDPTE的51:12位
    • 11:3位来自于线性地址的29:21位
    • 2:0位是0
  3. 通过PDE计算实际的物理地址:
    • 物理地址的51:21位来自于PDE的51:21位
    • 20:0位来自于线性地址的20:0位

4-KByte Page

下图是Intel手册中使用PAE将线性地址转换成4-KByte的转换过程:


采用4-KByte分页的时候,PDE与2-MByte分页时候结构是不同的,下图是Intel手册中采用4-KByte时PDE和PTE的结构:


4-KByte Page情况下从线性地址转换成物理地址的过程:

  1. 通过线性地址的31:30位来选择PDPTE寄存器:
  2. 通过PDPTE寄存器来计算PDE的地址:
    • PDE的51:12位来自于PDPTE的51:12位
    • 11:3位来自于线性地址的29:21位
    • 2:0位是0
  3. 通过PDE来计算PTE的地址:
    • PTE的51:12位来自于PDE的51:12位
    • 11:3位来自于线性地址的20:12位
    • 2:0位是0
  4. 通过PTE计算物理地址:
    • 物理地址的51:12位来自于PTE的51:12位
    • 11:0位来自于线性地址的11:0位


例子

这里的例子是根据《x86/x64体系结构探索及编程》配套的代码编写的,首先调用pae_enable来开启PAE:

pae_enable:
    movl $1, %eax
    cpuid
    btl $6, %edx
    jnc pae_enable_done
    movl %cr4, %eax
    bts $PAE_BIT, %eax
    movl %eax, %cr4
pae_enable_done:
    ret
然后调用init_pae32_paging来预先设置地址转换结构:

init_pae32_paging:
    movl $PDPT_BASE, %esi
    call clear_4k_page
    movl $0x201000, %esi
    call clear_4k_page
    movl $0x202000, %esi
    call clear_4k_page

    # PDPTE[0]
    movl $PDPT_BASE, %esi
    movl $0x201001, (%esi)
    movl $0x00, 4(%esi)
    # PDE[0] 0x00 ~ 0x1fffff (2M)
    # PDE[1] 0x200000 ~ 0x3fffff (2M)
    # PDE[2] 0x400000 ~ 0x400fff (4K)
    movl $0x201000, %esi
    movl $0x00, %eax
    movl $0x00000087, (%esi, %eax, 8)
    movl $0x00, 4(%esi, %eax, 8)
    inc %eax
    movl $0x00200087, (%esi, %eax, 8)
    movl $0x00, 4(%esi, %eax, 8)
    inc %eax
    movl $0x00202007, (%esi, %eax, 8)
    movl $0x00, 4(%esi, %eax, 8)
    # PTE[0] 0x400000 ~ 0x400fff (4K)
    movl $0x202000, %esi
    movl $0x00400001, (%esi)
    movl xd_bit, %eax
    movl %eax, 4(%esi)
    ret
这里设置的分页结构很简单:

开启分页之后使用dump_pae_paging将几个线性地址转换成物理地址的过程打印出来:

    # enable sse
    movl %cr4, %eax
    btsl $9, %eax
    movl %eax, %cr4

    call pae_enable
    call xd_enable
    call init_pae32_paging
    
    movl $PDPT_BASE, %eax
    movl %eax, %cr3

    movl %cr0, %eax
    bts $31, %eax
    movl %eax, %cr0

    movl $msg1, %esi
    call puts
    call println
    call println

    movl $msg2, %esi
    call puts
    call println
    movl $0x200000, %esi
    call dump_pae_page
    call println

    movl $msg3, %esi
    call puts
    call println
    movl $0x400000, %esi
    call dump_pae_page
    call println

    movl $msg4, %esi
    call puts
    call println
    movl $0x401000, %esi
    call dump_pae_page
    call println

    movl $msg5, %esi
    call puts
    call println
    movl $0x600000, %esi
    call dump_pae_page
    call println

    movl $msg6, %esi
    call puts
    call println
    movl $0x40000000, %esi
    call dump_pae_page

    jmp .
代码执行的结果:


参考

《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide》

《x86/x64体系探索及编程》


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值