《实模式到保护模式》chap11 学习笔记(上(大部分))

进入保护模式

在实模式中,用户对于内存单元的访问不受控制。只要将逻辑段地址和偏移地址设置正确,可以访问任何地方的数据。但是在保护模式下。一个用户不能访问其他用户的数据,不能修改操作系统的数据

全局描述符表GDT

在实模式下,任何程序访问,执行都是自由的。但是保护模式下则不然。用来限制这种自由的凭证就是全局描述符表。GDT在进入保护模式之前被定义

程序中用来记录全局描述符表的寄存器是GDTR。该寄存器的组成如下
在这里插入图片描述

线性基地址代表了内存中全局描述符表的起始位置。16位边界地址记录了全局描述符表的大小(总字节数)减去1

由于每一个段描述符大小是8字节,可以计算总描述符最多为(2^16/8)=8192个

之前说GDT在进入保护模式之前被定义,实际上是被定义一部分(因为实模式下只能访问1MB以下的内存)在进入保护模式下允许重新定义GDT

在主引导扇区程序中,GDT的加载位置处于0X00007E00,位于主引导扇区上方,正好对齐的位置。这样做是为了防止覆盖BIOS中断向量表以及主引导扇区需要用到的栈内容(栈是向下增长的)

段描述符的结构如下🌵

一个段描述符大小为64bit

其中:段基地址分布在三块,总长度为32bit。原因:向下兼容16位具有保护模式功能的80286处理器

段界限:限制段的扩展范围。限制访问该段时偏移量的大小(相当于限制这个段的最大大小)对于内存段和栈段,方向(上下)不同

**G:粒度:**解释段界限是以4KB为单位还是字节为单位

S:段描述符类型.0:系统段,1:代码段或者数据段

DPL(descripter prilivge level)特权级。0为最高,3为最低。初始化时,一律设置为0。指的是访问特权级

P:段存在位。有时内存紧张,os会把部分段给替代成别的。这时设置p为0

D/B默认操作数大小:用于指定32位还是16位操作系统,影响包括:栈段中rsp指针大小,代码段中rip大小

TYPE字段:表示各段在程序中的权力,类似于LIUNX上的RWX权限

对于数据段:从前到后四字节分别代表X(execute),E(expand),W(write),A(accessed)

对于代码段:从前到后四字节分别代表X(execute),C(Conform:特权级依从),R(read),A(accessed)

其中accessed位用处在于为操作系统调度策略提供支持(优先换出不常使用的位)

安装段描述符、加载GDTR

初始化GDTR的时候要注意:为了防止用索引为0的记号选择段描述符,第一位段描述符必须为空描述符

之后程序安装段描述符,具体方法是先设置放置GDT表的位置,之后把对应内容放进去即可

以下是设置位置的部分

mov ax,[cs:gdt_base+0x7c00]        ;低16位 
mov dx,[cs:gdt_base+0x7c00+0x02]   ;高16位 
mov bx,16        
div bx            
mov ds,ax                          ;令DS指向该段以进行操作
mov bx,dx                          ;段内起始偏移地址 

以下是放置内容的部分。注意第一个描述符是空的

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

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

;创建#2描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区) 
mov dword [bx+0x10],0x8000ffff     
mov dword [bx+0x14],0x0040920b     

;创建#3描述符,保护模式下的堆栈段描述符
mov dword [bx+0x18],0x00007a00
mov dword [bx+0x1c],0x00409600

对于每一个被放入数据的解释,可以参考GDT表项的结构研究

检测点11.1

这两道题都是对段描述符具体每一位意义的熟悉。很相似,所以就做第一题了

将数字拆开很容易看出:段基地址:FFFFFF00,段界限:FFFFF G:0,D:1,L:0,AVL;0,P:1,DPL:00,S:1,TYPE:1010

关于第21条地址线A20的问题

由于在实模式下只有20根地址线,FFFFF溢出之后变为00000.因此需要设计一种机制,使得32位处理器溢出之后依然保持20根地址线的状态。80386使用端口0X92第二位来控制A20(第21根地址线)使用与否。这里直接打开A20。

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

保护模式下的内存访问

首先,使处理器跳转到32位保护模式的方法是将CR0寄存器的末位置1

CR0~CR8:control register

32位寄存器的六个段寄存器(CS\DS\ES\SS\FS\GS)(后两者为新增)分为两部分。

前16位和8086相同,用来兼容实模式。同时,每个段寄存器还包含一个不可见的部分,称为描述符高速缓存器,用来存放线性基地址、段界限和段属性。不可见的含义是用户不可以读取,只能由处理器读取。它的结构如下🌵
在这里插入图片描述

32位处理器流程如下:引用一个段如下,以下也就是"引用一个段"的含义

  1. 处理器自动将段地址左移四位
  2. 传输上述值到描述符高速缓存器

但是,实模式下只能传送16位逻辑段地址。也就是说,此时段寄存器描述符高速缓存器内容只有低20位有效(左移四位导致16—>20)其余位全为0。

段寄存器(CS\DS\ES\SS\FS\GS)在保护模式下称为段选择器。保护模式下访问内存不是逻辑段地址,而是段描述符在描述符表中的索引号

以下是访问一个段的流程

  1. 段选择子被传送到段选择器,结构如下🌵其中Table_indicator表示的是选择GDT(0)还是LDT(1)
    在这里插入图片描述

例如

00000000000_10_000B

表示索引号为2,访问在GDT表中特权级为0的段

  1. 处理器计算8*索引(每个描述符占8字节)
  2. 将上述值和GDTR中的GDT基地址相加,得到被需要的段位置
  3. 将上述值传送回段描述符高速寄存器
  4. 在这之后的访问内存指令不再访问GDT的描述符,而直接使用当前段寄存器描述符高速缓存器作为基地址

之后的内存位置计算就是寄存器描述符高速缓存器+显式定义的偏移

比如说指令位置就是RIP寄存器+寄存器描述符高速缓存器内的基地址

注意:每个寄存器对应的寄存器描述符高速缓存器不同,要显示指定

清空流水线并串行化处理器

为了防止按照16位操作数和16位地址长度译码的指令进入处理器。需要清空流水线操作。这里的方法是使用远跳转指令hmp或者call

jmp dword 0x0008:flush             ;16位的描述符选择子:32位偏移
                                   ;清流水线并串行化处理器

由于之前已经设置过CR0寄存器,这条指令已经处于保护模式,处理器将用保护模式来解释这条指令。具体而言就是把0008解释为段选择子。

保护模式下的栈

wait till tomorrow!

今天打球好累,快开学了,心情复杂⏰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值