保护模式和内存管理
1 内存管理概览
IA-32的内存管理系统被分成了两部分:分段和分页。分段提供了一种可以将属于不同程序的代码、数据和栈模块相互隔离的机制,以便他们可以在同一个处理器上运行而不相互打扰。而分页提供了实现一种传统的按需调动的虚拟内存机制,在这之中程序运行环境被按需映射到物理内存中。分段机制是必需的,而分页机制是可选的。在系统级架构的保护模式下,处理器通过两个步骤获得一个物理地址:①逻辑地址转化 ②线性地址空间分页
- 物理地址
物理地址就是内存单元的绝对地址,所有的寻址方式变换最后都是要访问内存上的某一个存储单元。在保护模式下,IA-32架构提供了一个4GB大小的物理地址空间,这些地址是处理器可以通过地址总线寻址到的,是平坦的(不分段),从0到FFFFFFFFH连续变化的。
- 逻辑地址
逻辑地址用来在在线性地址空间中选择出某一个线性地址的。一个逻辑地址由一个16位的段选择符和一个32位的段内偏移组成的,通过段选择符可以在全局符号表中选出一个段,再根据段内偏移找到相应的线性地址
- 线性地址
线性地址用来通过寻址找对最终的物理地址。如果没有使用分页机制,那么线性地址就是物理地址;反之,则需要通过一步额外的转换。
通过图3.1来看,他们之间的转化还是比较直观的,流程如下:
- 通过逻辑地址的前16位在GDT中选择一个段描述符,再根据所选中的段以及偏移量取出线性地址空间中的线性地址
- 线性地址通过分页机制(如果有)转换成物理地址空间中具体的物理地址
2 分段机制
本节记录一些分段模型的介绍
2.1 Basic Flat Model
基础平滑模型,这种模型是最简单的内存模型,在这个模型中,操作系统和应用程序能够使用一个连续的、未分段的地址空间。为了实现这样一个基础平滑模型,至少需要创建两个段描述符,一个用来对齐于代码段,另一个用来对齐于数据段。然而这两个段都被映射到一个完整的线性地址空间,也就是说这两个段描述符有相同的基地址0和相同的大小限制4GB。ROM通常在物理地址空间的最顶部,因为处理器是从地址FFFFFFF0H开始运行;RAM一般在地址空间的底部,因为DS数据段的初始基地址在经过重置之后会初始化为0。
2.2 Protected Flat Model
受保护的平滑模型,他除了限制段必须在真实实际存在的物理内存里,其他的地方和基础模型是类似的。这个模型可以变得更加复杂来提供更多的保护,例如通过设置不同的特权等级来隔离代码和数据。
2.3 Multi-Segment Model
多段模型,这个,模型使用了分段机制的全部功能,来为代码、数据结构、程序和任务提供强制的硬件保护。每个程序或者任务都被赋予属于自己的段描述符和自己的段空间,获取段和程序的运行环境由硬件控制。访问检查不仅可以用来防止引用段限制之外的地址,而且还可以防止在某些段中执行不允许的操作,例如试图改写只读片段。
3 逻辑地址和线性地址的转换
3.1 段选择符 Segment Selectors
段选择符是一个16位的段选择器,用来标识一个段标识符,而不直接指向某一个段。它由以下几个部分组成:
- Index(第3位到第15位):从8192个GDT或LDT描述符中选择一个。选择算法是:Index * 8 + base_address
- TI flag(第2位):决定GDT或是LDT,TI = 0 表示GDT
- Requested Privilege Level(第1位和第0位):决定段选择符的权限等级,0为最高等级,3为最低等级
注:GDT的0号条目被用作空选择符,当除了CS和SS的段寄存器选择加载一个空选择符的时候,处理器不会产生异常;但是当使用空选择符去访问内存的时候,则会产生一个异常。空选择符可以用来初始化未使用的段寄存器,使用空选择符加载CS和SS或产生一个通用保护异常,异常号为 #GP。
3.2 段寄存器 Segment Registers
段寄存器的设置目的是减少地质转化时间和编码的复杂性,最多可以容纳6个段选择符。为了使各种类型的程序正确的执行,至少在CS(Code_Segment)、DS(Data_Segment)和SS(Stack_segment)中要加载有效的段选择符。通过将段选择符加载到段寄存器中可以实现对一个段的访问。每个段寄存器都有显示和隐藏两个部分,当段选择符被加载到显示部分时,处理器也会把段选择符指向的段描述符的基地址、段限制、访问控制等信息加载到隐藏部分。缓存在段寄存器中的信息,包括显示部分和隐藏部分允许处理器进行抵制转换,而不需要话费额外的总线周期从断面舒服中读取基地址和段限制。
有两种指令可以加载段寄存器:
- 通过使用MOV、POP、LDS、LES等指令想寄存器中直接加载
- 通过使用隐含的加载指令,比如CALL、JMP等,这些指令会改变CS寄存器中的内容
3.3 段描述符 Segment Descriptors
段描述符是存在于GDT和LDT里面的一种数据结构,他向处理器提供的段的位置、大小以及访问控制和状态信息。段描述符中的比较重要的标志位和区域的意义在下方逐一阐释:
3.3.1 Segment limit field
位于高4字节19 - 16位 + 低4字节15 - 0位。这个域确定了段的大小,处理器根据G位的不同设置,有两种方式解释段限制:
- 如果G = 0,代表limit的单位是1Byte
- 如果G = 1,代表limit的单位是4KByte大小的一个页
3.3.2 Base address fields
位于高4字节的31 - 24,7 - 0位 + 低4字节的31 - 16位。这个域定义了段的开始字节在4GB带下的线性地址空间中的位置
3.3.3 Type field
位于高4字节的11 - 8位。标识了段或者门的类型,并指令了可以对段进行的访问的类型和段的增长方向。
3.3.4 S(describe type) flag
位于高4字节的12位。决定段的类型,S = 0标识系统段,S = 1标识代码或数据段。
3.3.5 DPL(descriptor privilege level) field
位于高4字节的14 - 13位。确定段的特权等级,被用来进行段的访问控制。
3.3.6 P(segment-present) flag
位于高4字节的15位。这个标志位标识了段是否存在与内存中,如果将其设置为0,则表示这个段描述符是无效的。
3.3.7 D/B (default operation size/default stack pointer size and/or upper bound) flag
位于高4字节的22位。根据段描述符是可执行代码段、展开数据段还是堆栈段来执行不同的功能,
4 描述符的分类
当描述符中标志位S为1时,该描述符被标识为一个代码段描述符或者数据段描述符,Type域的最高字节标识这个描述符具体是数据段还是代码段。
当描述符中标志位S为0时,则表示一个系统描述符。