嵌入式实时应用开发实战(原书第3版)》——3.3 保护模式架构

本节书摘来自华章计算机《Linux嵌入式实时应用开发实战(原书第3版)》一书中的第3章,第3.3节,作者:(美)Doug Abbott 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.3 保护模式架构

在现代的Intel处理器中,实现保护模式存储器首先出现在80386中。它采用一个整32bit的地址对4GB的范围寻址。访问是受控的,因此一个存储块可能执行只读或读/写操作。
处理器可以工作在4个优先级中的一个,一个运行在最高优先级(0级)的程序可以做任何事情——执行I/O指令、启用或屏蔽中断、改变描述符表。低优先级会阻止程序执行可能有危险的操作。例如,一个字处理应用程序不能被中断标志干扰,因为前者是操作系统的工作。
所以操作系统运行在最高优先级,而应用程序代码通常运行在最低优先级,设备驱动和其他服务运行在中间优先级。但是在实际中,Intel处理器的Linux和多数其他的操作系统只使用优先级0和3。在Linux中,0级叫做内核空间,而3级叫做用户空间。
3.3.1 实模式
要在x86上开始关于保护模式编程的讨论时,回顾一下实地址模式怎么工作的是很有用的。
20世纪70年代末期,Intel在设计8086时,设计者们面临如何只用16bit访问1MB地址空间的难题。那时,人们认为1MB是很大的存储空间。姑且不论好坏,他们的解决方法是,在2个16bit上建立一个20bit(1MB)的地址,分别叫段地址和偏移量。将段地址左移4bit,再加上偏移量就得到了一个20bit的线性地址(图3-4)。


嵌入式实时应用开发实战(原书第3版)》——3.3 保护模式架构_第1张图片

实模式下的x86处理器有4个段寄存器,每次对存储器的引用都会从其中一个寄存器获得段地址。默认情况下,指令执行与代码段(CS)有关,数据引用(例如Mov指令)与数据段(DS)有关,涉及堆栈的指令与堆栈段(SS)有关。外部段用于字符串移动指令和需要外部DS的时候。默认的段选择可以用段前缀指令重置。
一个段最大可以有64KB,是以16字节为边界排列的。小于64KB的程序的存放与位置无关,也易于重定位于1MB地址空间内的任何地方。大于64KB的程序,无论代码或数据,都需要多个段来存放,必须对段寄存器进行操作。
3.3.2 保护模式
保护模式仍然使用段寄存器,但不是直接提供一个段地址,段寄存器(现在叫选择器)中的值变成了段描述符表的一个索引。段描述符描述存储块的一些信息,包括它的基地址和边界(图3-5)。物理存储器中的线性地址是通过对描述符中包含的基地址增加逻辑地址中的偏移量计算得到的。如果结果地址比描述符中指定的边界大,则处理器显示一个存储器保护错误。


<a href=https://yqfile.alicdn.com/8a1db411ae70e3a00f89d54a086c8c08de1ba619.png" >

一个描述符有8个字节,它包含我们需要知道的关于一个存储块的任何信息。

  • 基地址[31:0] 块/段的起始地址。
  • 边界[19:0] 段的长度——以字节为单位(最大1MB)或以4KB的页面为单位的长度。它以bit为单位定义。
  • 类型 一个4bit值,定义该段描述的存储器类型。
  • S 0=该描述符描述的一个系统段。1=该描述符描述一个CS或DS。
  • DPL 描述符优先级——一个2bit的值,定义访问该段需要的最小优先级。
  • P 当前——1=该描述符代表的存储块当前正在存储器中。在分页中使用。
  • G 粒度——0=以字节为最小尺度。1=以4KB页面为最小尺度。

注意,将粒度位设置为1,则单个段描述符可以代表整个4GB的地址空间。
通常的描述符(S位=1)描述代表数据或代码的存储块。Type域是4bit,这是区分CS和DS的最重要的位。CS是可执行的,但DS不能。一个CS可能是可读的。一个DS可能是可写的。任何在Type范围外的,失败的试图访问的操作都会引起一个存储器保护错误,例如,试图执行一个DS。
3.3.3 平面与分段的存储器模型
因为单个的描述符可以描述4GB的地址空间,所以通过使用一个描述符建立你的系统是可行的。这就是平面(Flat)模式寻址,是一个与在多数的8位微控制器中的寻址模式和DOS中的微存储器模式等价的32bit的寻址模式。所有的存储器都可以访问,没有保护。
Linux实际上是做类似的事情。它对操作系统和每个进程使用独立的描述符,所以保护是强制的。但是它将每个描述符的基地址设置为0。因此,偏移量和虚拟地址是一样的。这有效地避免了分段。
3.3.4 分页
分页是允许每个任务都像独立拥有一个非常大的平面地址空间的机制。整个空间以4KB每页为单位进行分割。只有当前正在访问的页面保留在内存里,其他的都在磁盘上。
如图3-6所示,分页增加了一个间接层。从选择器和偏移量得到的32bit的线性地址分成3个域。高10bit作为页目录的索引。页目录入口(PDE)指向一个页表。线性地址中接下来的10bit提供指向表的索引。页表入口(PTE)提供物理地址中一个4KB页面的基地址,该页面叫页帧。原始线性地址中最低的12bit提供页帧的偏移量。每个任务都有由处理器控制寄存器CR3指向自己的页目录。


<a href=https://yqfile.alicdn.com/57cb766fad83ebec52bc9bf7d949d235877c7983.png
" >

在查表过程的任何阶段都可能出现页表或者页帧当前不在物理存储器的情况,这就会引起页面错误。页面错误会让操作系统在磁盘上寻找相应的页面并导入到存储器中一个可用的页面中,然后要求与当前占据存储器的页面进行页面交换。
分页的一个更有优势的地方在于它可以让多个任务或进程很容易地共享代码和数据,只需要简单地将它们各自地址空间的段映射到相同的物理页面即可。
分页是可选的,尽管Linux使用了,但你无需必须使用它。分页是处理器寄存器CR0里的1个位控制的。
页目录和PTE都是4字节长,所以页目录和页表最大有4KB,这也是页帧的大小。高20bit指向页表或页帧的基地址,9~11bit是操作系统自己使用的。这些位可以用于标识一个页面是锁在存储器中的,例如不可交换的。
在其他控制位中,最有意思的是下面的这些:

  • P 当前的。1=该页面在存储器中。如果该位是0,则表示页目录或PTE引起了一个页面错误。注意当P==0时,剩下的入口都是不相关的。
  • A 访问的。1=该页面被读或写过。由处理器置位,但由操作系统清零。通过周期性地清除该位,操作系统可以确定哪些页面有很长时间没有被访问,可以被交换出去。
  • D 改变的。1= 该页面被写过。由处理器置位,但由操作系统清零。如果该页面还没有被写过,则当它被交换出去时,不必将其再写回到磁盘。

你可能感兴趣的:(嵌入式,操作系统)