22、进入保护模式


上一节:21、32位x86处理器编程架构
下一节:23、指令的格式及其操作尺寸

01、保护模式要保护的是什么

保护模式下每个程序都有一个特权级(高 0、1、2、3 低),0特权级具有最高的权限,可以读写任意内存位置、读写所有端口、执行特权指令(用来控制处理器的运行模式和工作状态)。
在这里插入图片描述
学习目标:
在这里插入图片描述

02、全局描述符表GDT和寄存器GDTR

在这里插入图片描述
和一个段有关的信息需要8个字节来描述,称为段描述符,集中存放在描述符表中。
在这里插入图片描述
最重要的是全局描述符表(GDT:Global Descriptor Table),需要在进入保护模式前定义。处理器内部有一个GDTR寄存器(48位),这个寄存器保存了GDT的起始线性地址和界线值。
在这里插入图片描述
GDTR寄存器高32位存放GDT线性基地址、低1位存放GDT界限(表内最后一个字节对与表起始处的偏移,即表的大小 减 一),GDT的界限是16位的,即GDT最大为2^16 = 65536字节 = 64K字节,一个描述符8个字节,最多可存放8192个描述符。
在这里插入图片描述
GDT理论上可定义在任何位置,但是在进入保护模式之前,实模式只能访问前1M字节,所以一般定义在1M字节之内,也可以在进入保护模式之后换个位置。

03、创建全局描述符表

指定的GDT起始地址:
在这里插入图片描述
取得32位的GDT物理地址:
在这里插入图片描述
计算GDT所在段的逻辑地址GDT在段内的偏移地址,程序如下:

...
	;计算GDT所在的逻辑段地址 
	mov ax,[cs:gdt_base+0x7c00]			;低16位 
	mov dx,[cs:gdt_base+0x7c00+0x02]	;高16位 
	mov bx,16        
	div bx    							;段地址存在ax中        
	mov ds,ax                           ;令DS指向该段以进行操作
	mov bx,dx                           ;段内起始偏移地址传送到基值寄存器bx
...

04、描述符分类

描述符的作用就是记录某个段的地址信息:
在这里插入图片描述

存储器的段描述符:一般用来藐视一般的代码段、数据段、栈段;
系统描述符:用来描述系统运行和控制相关的内容;
描述符:用来描述一些与程序执行有关的逻辑结构,如过程调用和中断处理的逻辑结构。
在这里插入图片描述
根据描述符的S位和TYPE位的不同,不同描述符的其他位也有不同。
在这里插入图片描述

05、段描述符–段的类型和基地址

存储器的段描述符格式:
在这里插入图片描述
TYPE字段:X位为0表示不可执行,即为数据段,其他三位为E、W、A

  • E(Expand):扩展方向,为0向上扩展、为1向下扩展。
  • W(Writtable):可写属性,为0表示不可写、为1表示可写。
  • A(Accessed):为0表示未被访问,为1表示已被访问,在描述符创建时此位清零(由软件,操作系统负责),每当该段被访问处理器自动将该位置1。

在这里插入图片描述
TYPE字段:X位为1表示可执行、既代码段,其他三位为C(表示特权级)、R、A

  • C:为0表示非依从的代码段,只有特权级相同的程序才能直接转移到这个段内执行;为1表示依从的代码段,特权级低的程序可以直接转移到这个段内执行;此位通常为0。
  • R:为0表示代码段不能读出,为1表示代码段可以读出。这里的R位并非用来限制处理器取指令、执行指令,而是限制程序像访问数据段一样来访问代码段的内容。
  • A(Accessed):为0表示未被访问,为1表示已被访问,在描述符创建时此位清零(由软件,操作系统负责),每当该段被访问处理器自动将该位置1。

在这里插入图片描述
DPLDecriptor Privilege Level)位:特权级位
在这里插入图片描述

06、段描述符–段界限及访问控制位

1、描述符的段界限:
在这里插入图片描述
2、向上扩展的段:段界限为0,段长度为1。段的实时长度为段界限减1。
在这里插入图片描述
3、向下扩展的段:一般用做栈段,也可不用。此时段界限为SP所不允许的最小值,超过段界限时会使得处理器触发异常中断。此时段实时长度0xFFFF(0xFFFFFFFF)减去段界限。
在这里插入图片描述
4、描述符的G(粒度)位:为0表示段界限以字节为单位、为1表示段界限以4K字节为单位。若G位1,则有:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5、描述符的PPresent)位,段存在位。段是一段连续的内存空间,在物理上始终时存在的,但是这段空间及其内部数据是否位当前描述符准备的、是否可以立即通过当前描述符来访问,这就是段的存在性。

一般来说,描述符所指示的段都是存在的,但是当内存空间紧张时,有可能只是建立了描述符,对应的段并没有安排,被认为是不存在的,这是就应当将描述符的P位清零表示段不存在。

另外当内存空间紧张时,会把很少用的段置换到硬盘中,腾出空间给当前急需要内存的程序使用,此时同样要把段描述符的P位清零。当再次轮到它执行时,再装入内存,将P位置1

P位是由处理器检查的,每当通过描述符访问内存中的段时,如果P位是0,处理器就会产生一个异常中断,通常该中断处理过程是由操作系统提供的,该处理过程的任务是将该段从硬盘换回到内存,并将P位置1。在多用户、多任务的系统中是一种常用的任务调度策略。
在这里插入图片描述
6、描述符的L位(64位代码段标志),为0表示不为64代码段、为1表示是64位代码段。
在这里插入图片描述
7、描述符的D/B位(操作尺寸/栈上部边界),笼统地来说是指示段按照16位还是32位来进行操作。为0表示按照16位、为1表示按照32位。
在这里插入图片描述
8、描述符的AVLAvailable)位(可自由使用的保留位)。通常是由操作系统来用
在这里插入图片描述

07、安装存储器的段描述符

1、处理器规定第一个描述符为空描述符,或者叫做哑描述符,代码如下:

...
	;创建0#描述符,它是空描述符,这是处理器的要求
	mov dword [bx+0x00],0x00
	mov dword [bx+0x04],0x00  
...

2、安装数据段描述符,代码如下:

...
	;创建#1描述符,保护模式下的代码段描述符
	mov dword [bx+0x08],0x8000ffff    
	mov dword [bx+0x0c],0x0040920b
...

在这里插入图片描述

  • 段基地址0x000B8000
  • 段界限0x0FFFF
  • G位:为0,表明段界限以字节为单位,共64K字节
  • P位:为1,表示这个段存在
  • DPL位:为00,表示特权级别为0,最高特权级
  • S位:为1,表示这个段是存储器的段
  • X位:为0,表示这个段是数据段
  • E位:(由于X位为0),E位为0,表示这个段是向上扩展的
  • W位:(由于X位为0),W位为1,表示这个段是可写的
  • A位:为0,表示为被访问过

此描述符在内存中的映像:
在这里插入图片描述
当这个描述符安装完毕之后,处理器的内存布局:
在这里插入图片描述

08、加载全局描述符表寄存器GDTR

GDT是由处理器使用的,用户只是负责创建这个表,处理器通过GDTR来使用GDTGDTR用来保存GDT的位置和大小信息。
在这里插入图片描述
使用lgdt m(m48)指令来加载GDT,在地址m处应该存放的是一个48位的操作数。
在这里插入图片描述
代码如下:

...
	;初始化描述符表寄存器GDTR
	mov word [cs: gdt_size+0x7c00], 15  ;描述符表的界限(总字节数减一)
	
	lgdt [cs: gdt_size+0x7c00]	;lgdt指令不影响任何标志位
...

在这里插入图片描述

09、开启处理器的第21根地址线

8086处理器中只有20根地址线,所以会有地址回绕特性
在这里插入图片描述
80286处理器有24根地址线,通过键盘控制器来控制第20根地址线,具体看8042键盘控制器的0x60号端口的位1输出为0还是为1来控制A20地址线。
在这里插入图片描述
80486处理器开始不实用上述方法控制地址线A20了。使用如下模式:
其中ICH芯片的0x92号端口的位0链接处理器的INIT#(低电平有效)位,既复位按钮。位1连接在一个或门上,位2~位7保留不用。
在这里插入图片描述
在程序中还是做了A20打开的操作,其实不需要,因为处理器默认是将A20打开的。

...
	in al,0x92			;南桥芯片内的端口 
	or al,0000_0010B
	out 0x92,al			;打开A20
...

10、设置寄存器CR0的PE位进入保护模式

CR0寄存器(Control Register:CR),位0PEProtect mode Enable)位,保护模式允许位,位0为1表示进入保护模式。
在这里插入图片描述
在进入保护模式之前要进行关中断操作,因为在保护模式下会有一套别的中断机制,在进入保护模式之前没有设置,所以就需要清中断。

在保护模式下BIOS中断也不能使用,因为它们还是使用CS左移4位加上偏移地址的形式访问内存。

代码如下:

...
	cli				;保护模式下中断机制尚未建立,应 
	                ;禁止中断 
	mov eax,cr0
	or eax,1
	mov cr0,eax		;设置PE位
...

程序上电之后的状态,sreg命令显示GDTR的内容:
在这里插入图片描述
creg命令显示CR0内容:小写为0。
在这里插入图片描述
接着执行程序到断点0x7C00处,执行了BIOSGDTR寄存器状态:此时BIOS创建了描述符表
在这里插入图片描述
此时CR0状态:
在这里插入图片描述
执行程序完成CR0设置:此时CR0PE为1,表示进入保护模式。
在这里插入图片描述

11、描述符高速缓存器和保护模式下的内存访问

段寄存器在32位下扩展了描述符高速缓存器,而且是不可见的,由处理器内部使用。段寄存器叫做段选择器
在这里插入图片描述

  • 在实模式下,段选择器的内容为逻辑段地址;
  • 在保护模式下,段选择器的内容为段选择子,简称选择子

段选择子(Segment Select:SS
在这里插入图片描述

  • 位15~3:描述符索引,2^13 = 8192,刚好是描述符的最大个数。
  • 位2TI位(Table Indicator:TI):表指示器,为0表示要选择的描述符在GDT中、为1表示在LDT中。
  • 位1~0RPL位,特权级位,此时置为00即可。

在这里插入图片描述
程序中要选择的段描述符索引号为1,即第2个描述符
在这里插入图片描述
使用段选择子的过程:
在这里插入图片描述

  • 1、将段选择子传送到段选择器
  • 2、一旦改变了段选择器,处理器就是用这个段选择子乘以8它得到描述符表中的偏移量(因为一个描述符占8个字节,索引号就要乘以8);
  • 3、由于TI位为0,即使用GDT,于是从GDTR中取出GDT的线性基地址;
  • 4、将2和3两步中的地址相加得到目标描述符的线性地址(若没有分页则此时也可为物理地址);
  • 5、处理器使用4中的线性地址访问内存取出这个描述符;
  • 6、然后将5中的内容传送到1中哪个段选择器描述符高速缓存器中,之后处理器就使用描述符高速缓存器中的线性基地址 加上 段内偏移来访问内存。

代码如下:

...
	mov cx,00000000000_10_000B	;加载数据段选择子(0x10)
	mov ds,cx
...

上述代码执行之后,每当有访问内存的指令时,就不再访问GDT中的描述符、也不再使用DS中的段选择子,而是直接使用段选择器中的描述符高速缓存中的线性基地址(不需要左移4位了)加上指令中给出的偏移量来访问内存。

显示字符的代码如下:

...
	;以下在屏幕上显示"Protect mode OK." 
	mov byte [0x00],'P'  
	mov byte [0x02],'r'
	mov byte [0x04],'o'
	mov byte [0x06],'t'
	mov byte [0x08],'e'
	mov byte [0x0a],'c'
	mov byte [0x0c],'t'
	mov byte [0x0e],' '
	mov byte [0x10],'m'
	mov byte [0x12],'o'
	mov byte [0x14],'d'
	mov byte [0x16],'e'
	mov byte [0x18],' '
	mov byte [0x1a],'O'
	mov byte [0x1c],'K'
	
	hlt		;已经禁止中断,将不会被唤醒
...

在这里插入图片描述

12、调试器中观察实模式和保护模式的内存访问

在这里插入图片描述

  • 1、在32位处理器的实模式下,只能向段选择器传送16位的逻辑段地址;
  • 2、处理器将16位的逻辑段地址左移4位(乘以16),左边加0扩展到32位,传送到段描述符高速缓存器中
  • 3、以后就使用段描述符高速缓存器中基地址来访问内存
  • 4、就是说在实模式下:段寄存器描述符高速缓存器的内容只有低20位是有效的,高12位全部为0,处理器仍然只能访问1M字节内存。

例如:用BX所指示的偏移地址加上0x2000左移4位来访问内存。
在这里插入图片描述
例如:若第21根地址线A20是打开的,则访问的是0x00100000地址,否则访问地是0x00000地址。
在这里插入图片描述
处理器加电复位之后处理器的状态:
在这里插入图片描述
其中第二行的都是段描述符高速缓存器的状态:段地类型、基地址、段界限、读写状态、是否访问过,dh(描述符的高32位)、dl(描述符的高低32位)是描述符的信息。

处理器加电复位之后进入实模式,段描述符高速缓存中的段基地址是段选择器左移4位得到,比如CS寄存器:
在这里插入图片描述
CS段选择器的内容是0xF000,然而CS段描述符高速缓存中的段基地址是0xFFFF0000,并不是0xF000左移4位得到的。因为在处理器加电复位之后,所有寄存器都会被预制成特定的内容,段选择器段描述符高速缓存器是分别预制的,一开始两者之间不存在依赖关系,但是从现在开始一单改变了段选择器的内容,将同时改变段描述符高速缓存器中的基地址部分。

在实模式下,处理器使用CS高速缓存器里的基地址 加上 指令指针寄存器IP来取指令,CS高速缓存器里的基地址是0xFFFF0000,指令指针寄存器IP的当前值为:
在这里插入图片描述
IP的当前值为0xFFF0,则两者想加为0xFFFFFFF0,这就是第一条即将执行的指令的物理地址。

一旦我们执行第一条指令jmpf 0x0000:e05b,则处理器会使用指令中给出的逻辑段地址0xF000来替换CS段选择器的内容,同时用它乘以16用来替换段描述符高速缓存器中的基地址部分:
在这里插入图片描述
之后可以一直打断点,单步执行来调试程序,查看相关寄存器的内容。

使用info gdt命令查看GDT中的内容:
在这里插入图片描述
上一节:21、32位x86处理器编程架构
下一节:23、指令的格式及其操作尺寸

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值