首页 > 其他分享 >X86平台:快速入门X86保护模式

X86平台:快速入门X86保护模式

时间:2023-03-01 19:44:14浏览次数:39  
标签:保护模式 X86 地址 描述符 内存 寄存器 入门

        本文于2023/2/26开始写作,在此留念

        自学了李忠老师的《X86汇编语言:从实模式到保护模式》这本书,除了了解到X86汇编语法和汇编程序设计思想之外,更重要的是学到了X86平台的工作原理,尤其是保护模式的工作原理和设计思想。

        在看完书之后,我想试着用简短的语言对保护模式的工作原理和设计思想进行概括和总结,以记录这段时间的自学。


1 X86的内存管理

1.1 背景:多任务、地址空间隔离与分段

        并发是多个程序同时运行的模式,它利用处理器的闲置时间进行任务切换,大大提高了处理器的时间利用率和处理能力。

        86系列处理器必须支持并发,从80286开始,有了16位保护模式,而保护模式实现了地址空间的隔离,到了80486到X86,86系列处理器拓展到32位,有了32位保护模式。

        所以,X86工作在多任务环境。

        单任务环境的整个内存空间都分配给一个程序,所以程序可以随意修改内存。

        但是多任务的内存不能随意被分配,不然任务可能地会修改到不属于自己、其他任务的内存,毕竟没有内存的管理措施。

        所以多任务环境下,每个任务的地址空间都要被处理器申请和记录,任务申请到的内存叫做段,如果任务修改超过段范围的内存,就会被固件检测到并发生“段错误中断”。

        这种地址空间隔离设计叫做分段。

        注意,分段不等于实模式的段寻址,实模式下的段寻址并不知道内存中有多少个段被分配了,实模式的程序要自己去分配和记录自己使用的内存段。

        实模式的分段是单纯的软件模式。

        而保护模式的分段知道有多少段,所有的段都被GDTR寄存器所指示,保护模式下处理器记录所有使用的内存段,并且处理器通过特权级机制,限制了段的访问。

        保护模式的分段是软硬件结合的模式。

1.2 分段的内存管理

1.2.1 全局空间与任务空间

 

1.2.1 地址寄存器

        处理器的任务就是执行指令,而指令存储在内存中,所以处理器不断需要访问内存取指令,而且执行指令中可能还要访问内存地址取出数据。

        所以需要用寄存器保存这样的地址信息,用以重复设置地址线访问内存。

        这里重点在于,寄存器保存地址信息,这样的寄存器,我们暂时称为:地址寄存器。

(这里先不介绍段选择器和段描述符,先用地址寄存器和地址信息,分别代替这些概念)

1.2.2 地址信息、地址信息表DT、地址信息表寄存器DTR

        地址信息,是一个连续内存的首地址,比如程序就是在地址寄存器定位到首地址之后,才能用偏移实现连续地顺序地取指

        运行的程序其实就是一段连续的内存,它的位置只要保存在地址寄存器,就可以进行取指,之后才可以执行取出的指令。

        但是,问题在于整个内存空间中加载了很多道程序,这些程序在内存的不同位置,各自有一个地址信息。

        现在的问题是,地址信息很多,处理器该怎么设计,来管理这么多地址信息?

        一个解决办法是,将程序所有使用的地址信息放在一起,形成内存中的一段数组,这个地址信息数组在X86称作描述符表(DT)。

        这样地址寄存器只需要访问这个数组,就可以取出需要的地址信息,对那段内存进行访问。

        为什么叫描述符表?因为地址信息在X86处理器中是1个四字(64bit)单元,他不叫做地址信息,它叫做描述符(Describer)。

        为什么描述符表不能存在处理器内寄存器中?这其实是索引思想,地址寄存器如果选择不同的地址信息,只需要访问DT。

        X86为了访问DT,需要记录DT的位置,所以适配了一个寄存器DTR,用于记录DTR的位置。

1.2.3 理论上的访存过程

        现在看看X86处理器的结构,首先地址寄存器需要选择一条地址信息,所以需要访问DT的一个条目,这时地址寄存器请求DTR关于DT的对应条目,之后DTR将对应的地址信息交给地址寄存器。

        地址寄存器,请求DTR获取DT的一个地址信息,就可以实现程序的切换。

        目前,你已经初步的理解了X86保护模式的内存访问,但是真实的X86保护模式的内存访问要更加复杂。

1.3 X86平台下的内存管理设计

1.3.1 背景:多任务环境不允许随意访问内存

        X86平台不是单道程序环境,内存中存在多道程序,这就是多任务环境。

1.2.1 多任务、全局空间和局部空间

        在多任务环境下,X86提供了两个表来访问内存,分别是全局描述符表GDT和任务描述符表LDT,它们分别由GDTR和LDTR寄存器来表示。

        在1.1中,我们知道DTR是描述符表,也就是存储地址信息的数组,这里也是一样,GDT和LDT都分别存储着一组内存的描述符(内存的地址信息)。

        不过区别是有的,X86这样的设计是因为X86支持多任务。

 

1.2.2 描述符、描述符表

        这里的X86平台主要指保护模式,即主引导程序设置CR0的PE位为1并根据内核头部信息创建地址信息表之后。

        首先是地址信息,在X86平台中不叫做地址信息,而是描述符(Descripter),描述符有很多种,比如段描述符、门描述符等,它们除了描述内存的地址信息,还描述其他的东西,比如这段内存的尺寸、特权级、粒度、类型、方向等。

        不深究的话,可以理解为:主要是地址信息,其次是描述了这段内存的尺寸、特权级、类型、粒度、方向。

        基于段寻址的内存管理设计叫做: 分段。

        而1.1所说的地址寄存器,在X86叫做段选择器,它是用来选择DTR指向的DT的对应的地址信息条目的,所以叫做段选择器。

        段选择器的选择内容不是具体的表项,而是段选择子,但是意义是一样的,最终是要选择一个段描述符。

        段选择子的格式咱们不进行深究,只需要知道它可以请求DTR选择DT中对应的地址信息。

        DTR在X86分为GDTR和LDTR,这里面不得不提一个东西叫做多任务和不同任务的特权级,但是这些后面再提,现在只需要知道它们都有各自的LDT就好。

        另外,GDT是所有程序公用的描述符表,而LDT每个任务只有一个,而且每个任务只能看到自己的LDT,但是所有程序都能看到GDT,因为GDT只有一个,所以GDTR一般不会改变,这样GDT内的描述符就是所有任务公用的。

       一般GDT是由主引导扇区程序和内核所创建的,因为内存都有特权级,所以用户是不能跳转到GDT大部分的内存取指,也不能从GDT中定义的内存访问内核的数据。

1.3 X86的内存(段)特权级设计

        X86平台的特权级分为0、1、2、3,其中数值越大,特权级越低。

        特权级最大的问题,不是特权级的数值比较,而是哪些特权级、什么时候需要比较。

        也就是,特权级最重要的是,特权级的条件。

        GDT的数据不能随便访问是因为,GDT中的描述符大多数都是内核和各种驱动的描述符,这些描述符的特权级都是0,是最大的特权级,所以应用程序只能访问一些门描述符或者依从的描述符。

        特权级机制实现了任务之间的隔离。

        门描述符有着自己的格式,这个格式比较复杂不进行介绍,但是它的内容可以介绍。

        应用程序是不能直接访问硬件的,因为

        多任务系统涉及到任务切换,任务切换这个需要切换当前处理器指向的LDT和TSS,TSS是当前处理器的现场信息,它记录处理器的各个寄存器的值。

        关于TSS我们也先不深究,只需要知道,任务切换就是用TSS保存当前现场的信息,并切换LDT,并还原TSS中的现场信息。

        这里面有一个东西作为中间者,叫做TCBL,是TCB的链表,而TCB是将LDT、TSS、0/1/2/3特权级栈和其他任务描述信息的一种结构体。

标签:保护模式,X86,地址,描述符,内存,寄存器,入门
From: https://www.cnblogs.com/lovecodingforever/p/17157668.html

相关文章