上一篇文章中了解了PDE和PTE,这一篇就来了解一下PDE和PTE的属性。
物理页的属性
一上来看这张图,肯定是一脸懵逼的。先从行开始看,第一行是关于CR3寄存器的,这部分留到控制寄存器的章节再分析。接下来三行是不同类型PDE的,最后两行是PTE的。其中PDE和PTE有很多属性是重合的。而物理页的属性,就是有PDE和PTE共同决定的。计算方法是将相同属性位的值进行与运算。
物理页的属性 = PDE属性 & PTE属性
P位
首先来看P(Present)位:存在位。PDE与PTE的P位均位1时,物理页有效;其余情况,物理页不存在。这也解释了为什么PDE的第三行和PTE的第二行可以直接忽略。
在上一篇文章中,有一个关于0地址赋值的实验。0地址之所以不能赋值是因为它的PTE的P位为0,在我们修改了PTE的P位,并给它挂上一个物理页后,0地址遍可以赋值了。
R/W位
- R/W = 0 只读
- R/W = 1 可读可写
R/W很好理解,控制写的权限呗,这个位有何用呢?来看一个小实验。
1 |
|
来看这个代码,很明显,执行会是失败的,因为用char*定义的字符串,是会存储在常量区,而不是堆栈中了,又因为常量区的值是不允许修改的,因此
1 | *str = 'a'; |
这条语句会执行失败并报错。
那为什么常量区的内容就不可修改呢?其实,说白了,就是常量区挂着的物理页的R/W属性为0,因此只能读,不可写,既然知道了原因,我们只要修改了常量区所在物理页的属性,将R/W位置1即可。
通过printf语句先打印出所在常量区的线性地址,接着拆分跟进PDE和PTE中(具体步骤省略)
可以发现,PTE的R/W位值为0,因此将其修改为1写入,随后运行程序发现,可以成功修改字符串首地址出的字符!
P/S位
P/S(PageSize)位,只对PDE有意义,位于PDE的第7位。
- PS = 1 PDE直接指向物理页,无PTE,低22位为页内偏移。线性地址只能拆成两段(10-22):页的大小为2的22次方,也就是4MB,俗称“大页”,大页比较少,一般出现在高2G中
- PS = 0 就是我们比较熟悉的10-10-12分页,页的大小为4KB
U/S位
U/S(User/System)位,位于PDE/PTE的第2位。
U/S = 0:特权用户
U/S = 1:普通用户
三环程序是不能读写高2G内存的,原因在于高2G内存对应的物理页U/S位被置0了,也就是说只有特权用户才能读写高2G的内存。所以,当普通用户想要读取高2G内存时,就可以把U/S置1,这样就可以访问高2G内存了。
当然,理论如此,不过除了U/S位外,影响高2G内存读写的还有PCD位和PWT位,这部分内容也要到控制寄存器部分才能讲,所以第二种3环程序读写高2G实验(第一种是通过门提权),就要放到后面实现了,这里只要先记住,U/S位是影响访问读写权限的。
与R/W的区别
这里需要注意一下U/S位与R/W位的区别,U/S位的读写控制是根据用户的级别,而R/W位的控制是直接控制读写,不管你是不是特权用户。
A位
A(Accessed)位于PDE/PTE的第5位:表示该物理页是否被访问(读或者写)过,访问过置1,即使只访问一个字节也会导致PDE,PTE置1。
D位
D(Dirty),脏位,是否被写过。0表示没有被写过,1表示被写过
总结
以上是关于PDE/PTE部分属性的含义,还有一部分位没有涉及到,例如G位,PWT位,PCD位,这些需要讲到控制寄存器和TLB相关概念时再细讲。