第11章:进入保护模式

描述符格式:

高32位
31 242322212019161514131211 87 0
段基地址 24-31(8bit)GD/BLAVL段界限(19-16 = 4bit = 1个16位)pDPLSTYPE段基地址 23-16(8bit)
低32位:
3116150
段基地址 15-0段界限15-0
  1. G(粒度):

    0=1 byte

    1= 4k byte

  2. D/B (操作数大小)

    0=16bit

    1=32bit

  3. L:64bit处理器用的

  4. AVL(空闲)

  5. P 段是否存在内存中

    0 = 不存在

    1 = 存在

  6. DPL 描述符的特权级别 : 指定访问该段需具有的最低特权级别

    保护模式执行的代码特权级别都是 0

  7. S: 段的类型

    0=系统段

    1=代码or数据段

  8. type: 代码段or数据段的的类型


分析例子:

 mov dword [bx+0x08],0x7c0001ff ;低位
 mov dword [bx+0x0c],0x00409800	;高位
     

0x00409800
0x7c0001ff
  1. 线性地址

    高位(前1个字节+最后1个字节)+低位(前2个字节) = 0x00007c00

  2. 段界限 (20bit = 4+16 bit)

    • 4bit恰好是1个16进制数

    高位第4个16进制数(0) + 低位最后2个字节(01ff) = 0x001ff

  3. 剩下 高位第3个(3)、第5个(9)、第6个(4)16进制数,每个位置对应看就行了


80486: 南桥的处理器接口的端口0x92:第0位INIT_NOW用于初始化处理器,此端口=1,处理器复位,计算机重启,第1位控制A20,


2种模式的切换开关:CR0是 控制寄存器(Control register),并且第1位(位0)是保护模式允许位置(Protection Enable), =1则处理器进入保护模式,

32bit处理器下的段寄存器变成了段选择器(存描述符在table中的偏移位置),且cpu内部对应了一个用户不可见的描述符高速缓存寄存器, 并且新增了2个额外的段寄存器Fs,Gs(注意:仍是16位)

32bit处理器实模式下,引用一个段,处理器自动将段地址左移4位,传送到描述符高速缓存器中,(32bit下向段寄存器传送16bit的逻辑段地址处理器不看做是描述符选择子)

保护模式访问内存的方式(段选择子的组成
  • 传送到段寄存器的不是逻辑段地址而是在描述符表(局部或者全局)中的索引号(偏移地址)

    1. TL指出在GDT(=0)还是LDT(=1)中
    2. RPL:自己的特权级别
15321 0
描述符索引(偏移地址)TIRPL
在设置CR0的位0后进入保护模式的问题
  • 处理器进入16位保护模式

    操作数默认大小由描述符D位决定,此时段寄存器的描述符高速缓存器仍是实模式(低20有效,高12为0)内容,所以D位 = 0,此时处于16bit保护模式下

  1. 描述符高速缓存器低20位有效,高12位为0,应刷新段寄存器的内容
  2. 流水线中待执行的都是按照16bit操作数或者32bit编译后的字节,因为对地址的解释不同,可能导致执行结果不正确

通过jmp刷新段寄存器和段寄存器描述符高速缓冲器,因为无条件转移,流水线被清空

JMP执行时:将GDT()中描述符加载到cs寄存器描述符高速缓存器,偏移量送到EIP中


;实模式下
mov ax,cs
mov ss,ax
mov sp,0x7c00

mov ax,[cs:gdt_base+0x7c00]
mov dx,[cs:gdt_base+0x7c00+0x02]
mov bx,16
div bx
mov ds,ax   ;商
mov bx,dx   ;bx=偏移地址

;将ds:bx设置成 gdt的起始地址
mov dword [bx+0x00],0x00
mov dword [bx+0x04],0x00

;code段描述符
mov dword [bx+0x08],0x7c0001ff
mov dword [bx+0x0c],0x00409800

;data段设置成显存 0xb800
mov dword [bx+0x10],0x8000ffff
mov dword [bx+0x14],0x0040920b

;栈段
mov dword [bx+0x18],0x00007a00
mov dword [bx+0x1c],0x00409600

;将gdt的线性及地址和大小加载到gdtR寄存器中
mov word [cs:gdt_size+0x7c00],31 ;gdt的大小=描述符个数*8-1

;lgdt指令:
lgdt [cs:gdt_size+0x7c00];gdt加载完毕

in al,0x92
or al,0000_0010B    ;打开A20.因为要兼容所以A20一直设置成0,现在打开,因为要进入保护模式
out 0x92,al

cli ;清除IF位置,禁止中断
;此时仍然处于实模式
mov eax,cr0 ;将控制寄存器的内容读入到eax中
or eax,1    ;打开pe位置(保护模式的位置)
mov cr0,eax
;进入保护模式,但是还未清空流水线
jmp dword 0x0008:flush ;通过无条件转移指令来清空流水线

bits 32;接下来的按照32bit来编译
flush:
    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'
;填写段选择子来选择位于gdt中的栈段
    mov cx,00000000000_11_000B
    mov ss,cx ;修改ss段寄存器,向其中填写段选择子
    mov esp,0x7c00

    mov ebp,esp
    push byte '.'

    sub ebp,4
    cmp ebp,esp
    jnz ghalt   ;ebp!=esp则cpu暂停
    pop eax     ;ebp=esp 将值pop到eax中
    mov [0x1e],al ;al的值写到ds:0x1e,因为ds=0xb800所以显示到屏幕上了
ghalt:
    hlt

gdt_size    dw 0
gdt_base    dd 0x00007e00
times 510-($-$$) db 0
db 0x55,0xaa

Bochs调试:

  1. r:显示所有的通用寄存器
  2. sreg:段寄存器
  3. creg:控制寄存器内容: PE=1 进入保护模式
  4. lgdt加载gdt到gdtr后,用info gdt查看gdt

来源:《X86实模式到保护模式》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值