当前位置: 代码迷 >> 综合 >> [保护模式]非PAE模式
  详细解决方案

[保护模式]非PAE模式

热度:12   发布时间:2023-12-21 20:18:36.0

文章目录

    • 非PAE 非物理地址扩展
      • 线性地址 有效地址 物理地址
      • CR3
      • PDE/PTE
      • 物理页的属性
    • 通过线性地址访问PDT和PTT
      • 指向PDT的线性地址 0xC0300000
        • 总结
      • 指向PTT的线性地址 0xC0000000/C0001000
        • 总结
      • 访问PDT与PTT公式总结

非PAE 非物理地址扩展

线性地址 有效地址 物理地址

如下指令:

mov eax,dword ptr ds:[0x12345678]

这个地址如果想访问成功,首先取决于段机制,看当前的环境能否通过段权限检查以及是否超过limit限制等等。其次,取决于页机制。

  • 其中,0x12345678是有效地址
  • ds.base+0x12345678是线性地址
  • 线性地址也不是真正的地址,还有一个地址被称为物理地址

CPU会通过这个线性地址作为一个目录,去索引物理地址。问题在于A进程有一个地址0x12345678,B进程也有一个地址0x12345678。那么CPU通过什么去分别找到这两个相同内存地址的不同的物理地址呢?答案是页目录基址。

CR3

每个进程都有一个CR3寄存器,保存页目录基址。这个基址是物理地址。CR3指向一个物理页,一共4096字节,如图:

在这里插入图片描述

PDE/PTE

在这里插入图片描述

  • CR3寄存器保存的物理地址指向页目录表PDT,里面的每一个成员叫PDE。页目录表大小为4KB,每个成员为4个字节。
  • 每一个PDE又指向页表PTT,里面的每一个成员叫PTE。页表大小为4KB,每个成员为4个字节。
  • 每一个PTE都指向物理页,每个物理页大小为4096个字节
  • PDE与PTE都是4个字节(32位),前20位是物理地址,后12位是属性
  • PTE可以没有物理页,也可以指向物理页,但只能对应一个物理页
  • 多个PTE可以指向同一个物理页
  • 每一个线性地址都会经过一个PDE和PTE最终指向一个物理页,这个物理页能不能读写取决于经过的PDT和PTE的后12位

物理页的属性

在这里插入图片描述

  • 物理页的属性由PDE和PTE共同决定
  • P:是否有效
  • R/W:是否可读可写,0代表只读,1代表可读可写
  • U/S:U/S=0 物理页只允许特权用户访问;U/S=1 物理页普通用户也能访问。高2G以上的内存只有内核才能访问的原因是U/S位设置的问题,如果将内核的某个页设置为1,就可以在R3进行访问了
  • A:是否被访问过,访问过设置为1。即使只访问一个字节也会导致PDE和PTE置1
  • D:是否被写过;0没有被写过,1被写过
  • PS:只对PDE有意义,PS==PageSize的意思。当PS==1的时候PDE直接指向物理页,无PTE,低22位是页内偏移。此时,线性地址只能拆成两段:大小为4MB,俗称大页
  • 9-11位:当P位为0时,CPU会产生缺页异常,此时这两位标识了该线性地址是否有效,也标识了该线性地址对应的物理内存所在

通过线性地址访问PDT和PTT

指向PDT的线性地址 0xC0300000

现在问题来了,如果我们想访问0这个地址,那么就必须找到PDT和PTT,而CR3里面保存的PDT是物理地址,提供给CPU使用的,代码只能访问线性地址。

如何解决这个问题呢?有一个线性地址,指向的是PDT,这个地址就是0xC0300000,下面对这个地址进行拆分

0xC0300000
#二进制为:
1100 0000 0011 0000 0000 0000 0000 0000
#拆成10:10:12
1100 0000 00------>0x300*4=C00
11 0000 0000------>0x300*4=C00
0000 0000 0000

将这个线性地址拆分之后,找到的对应的物理页就是CR3保存的页目录PDT基址所在的物理页。那就意味着我们可以直接通过这个线性地址去修改PDT。

**结论:**C0300000存储的值就是PDT,如果我们要访问第N个PDE,那么有如下公式:

0xC0300000+N*4

总结

  1. 通过0xC0300000找到的物理页就是页目录表
  2. 这个物理页既是页目录表本身也是页表
  3. 页目录表是一张特殊的页表,每一项PTE指向的不是普通的物理页,而是指向其他的页表

指向PTT的线性地址 0xC0000000/C0001000

也就是说通过0xC0300000这个线性地址可以任意修改页目录表,但如果我们要设置某个线性地址PDE和PTE那么还要能够访问PTT,如何访问呢?

答案是通过这两个线性地址:0xC0000000/C0001000。

通过拆分可以知道,访问0xC0000000这个地址就等于是访问第一个PTT表;访问C0001000这个地址就等于是访问第二个PTT表。两个地址之间相差0x1000。如果想访问第三个PTT表的话以此类推。

总结

  1. 页表被映射到了从0xC0000000到0xC03FFFFF的4M空间
  2. 在这1024个表中有一张特殊的表:页目录表
  3. 页目录表被映射到了0xC0300000开始处的4K地址空间

在这里插入图片描述

访问PDT与PTT公式总结

PDI:页目录表索引

PTI:页表索引

访问页目录表的公式:0xC0300000+PDI*4

访问页表的公式:0xC0000000+PDI*4096+PTI*4
与PTT公式总结

PDI:页目录表索引

PTI:页表索引

访问页目录表的公式:0xC0300000+PDI*4

访问页表的公式:0xC0000000+PDI*4096+PTI*4