保护模式
为什么要有保护模式
实模式是有很大弊端的,首先,直接操作物理内存,这样的话每次只能运行一个程序,并且不安全;另外,内存最大使用到1M,限制太大。
保护模式下,程序不能直接访问物理地址,程序的虚拟地址需要被转换为物理地址后再去访问,地址转换是由处理器和操作系统协作完成的,处理器在硬件上提供地址转换部件,操作系统提供转换过程中需要的页表。
保护模式的寄存器扩展
除段寄存器外,通用寄存器,指令指针寄存器,标志寄存器等都从16位升到了32位,因为段寄存器保留原来的16位也够用。
模式转换
bits伪指令用于指定处理器的运行模式,这一点是编译器和处理器约定的,操作数大小翻转前缀0x66和寻址方式反转前缀0x67用于将当前运行模式下的操作数大小和寻址方式转换成另一种模式。
内存寻址
地址转换
内存控制单元(MMU) 通过一种称为分段单元的硬件电路把一个逻辑地址转换成线性地址,接着,通过第二个称为分页单元的硬件电路把线性地址转换成物理地址。
1 | graph LR |
全局描述符表
最初的操作系统是无法对内存段做访问限制,有了这样的需求以后,CPU厂商决定采用段描述符来实现相关的功能,在硬件一级上添加GDTR和LDTR来支持全局描述符表和局部描述符表,并由硬件负责周边的安全检测。当初的CPU厂商也并不是凭空制造出了这样一个概念,是与操作系统厂商共同协商后才有了一套硬件方面的支持。
如今x86架构的OS,大都都把分段视为是兼容性的考虑(类似于对实模式的处理),在系统初始化阶段象征性地初始化GDT,之后的运行就没分段啥事儿了。地址空间的保护模型都来自分页,像ARM体系结构就不支持分段,仅靠MMU进行保护。
内存分页
为什么要分页
分段的内存碎片太大,是计算中发展过程中尝试过的方案,现在的方案是内存分页,通过某种方式,将虚拟地址映射到物理地址,映射的关系是通过一张表实现的,也就是页表。
分页机制
分页机制的思想是:通过映射,可以使连续的线性地址与物理地址相关联,逻辑上连续的线性地址对应的物理地址可以不连续。
分页的作用
- 将线性地址转换为物理地址
- 用大小相同的页替换大小不同的段
一级页表
我们把一页的大小定义为4K,那么4G就有1M个页,在32位的保护模式下,地址都是32位二进制表示的,用20位二进制定位页表,剩余的12位表示4K里面的偏移。
分页机制打开前要将页表地址加载到控制寄存器CR3中,这个过程是打开页表之前,所以存储的是物理实际地址,每个页表项对应一个物理页,通过页表项就可以访问到实际的物理地址。由于这个过程是固定的,CPU中集成了这个硬件模块,即MMU中的页部件。
二级页表
为什么要二级页表
每个进程1M个页表,每个4字节,进程多了占用的内存还是很多的。
一般进程使用的内存是远低于全部虚拟内存的。二级模式只为进程实际使用的那些虚拟内存区分配页表,既提升了效率,也减少了内存的使用量。
页目录项结构
页表项结构
REF
- 深入理解Linux内核
- x86保护模式