首页 > 技术文章 > 进入保护模式

mlzrq 2019-01-04 23:50 原文

进入保护模式

进入保护模式

进入保护模式的步骤:

  1. 关闭中断,打开地址线A20GATE,使得CPU可以访问1M以上的内存空间。
  2. 设置CR0寄存器,进入保护模式。
  3. 加载临时GDT
  4. 进入保护模式后,首先执行jmp指令。因为内存寻址方式改变,需要刷新指令流水线

打开A20Gate

1. A20Gate的作用

在实模式下,A20Gate是关闭的,意味着只能使用20根地址线,需要通过打开A20Gate,访问第21根以上的总线。

A20Gate关闭时侯的内存访问:

A20Gate关闭式,只能使用20根总线,所以寻址范围位 0x00000 ~ 0xFFFFF,总共1M的地址范围。

当访问的地址大于这个范围,高位的值将被截取掉,导致超出1M的地址访问会使得CPU回滚到1M内地址范围的现象

例如

当使用 [0xFFFF :0xFFFF ] 内存地址,得到的地址位 0x10FFEF 。但是在实模式下,由于20根总线的限制,最高位的1是无效的,实际的访问地址回绕到 [0x0FFEF]。

A20Gate打开后的内存访问:

打开A20Gate, 可以使用到32位的地址总线,内存地址访问也达到了1<<32 的4G范围。

实际上开启A20Gate,总线的寻址能力达到了4G,但是cpu的内存访问能力因为16位段寄存器,和16位偏移地址的限制,并不能协调工作。

所以需要进入保护模式突破cpu的内存访问限制。

2. 开启A20Gate

开启A20Gate,只要设置io端口0x92的第一位为1就可以了。

;------------------
;打开A20
cli							;禁止CPU级别的中断
in 		al,0x92
or 		al,0000_0010B        	;设置第1位为1
out 	0x92,al

设置CR0寄存器,进入保护模式

CR0寄存器

CR0寄存器是一个32位的寄存器

设置CR0寄存器的最高位为0,最低位为1,则可以进入保护模式。

CR0寄存器的作用

  • 改变段寻址方式,使用段描述符方式寻址。
  • 实模式指令的操作数默认为16位,保护模式指令的操作数默认为32位。

代码:

;------------------
;进入保护模式
mov 	eax,CR0
or 		eax,0x00000001            ;设置第0位为1
mov 	CR0,eax

loader.asm完整代码如下

;Rats OS
;Tab=4
[bits 16]

section loader vstart=LOADER_BASE_ADDR ;指明程序的偏移的基地址

;----------- loader const ------------------
LOADER_BASE_ADDR 		equ 0x9000  ;内存地址0x9000
;---------------------------------------	
	jmp Entry
	
	
;程序核心内容
Entry:
	

	;------------------
	;禁止CPU级别的中断
	cli						    

	;------------------
	;打开A20
	in 		al,0x92
	or 		al,0000_0010B       ;设置第1位为1
	out 	0x92,al
	

	;------------------
	;进入保护模式
	mov 	eax,cr0
	or 		eax,0x00000001      ;设置第0位为1
	mov 	cr0,eax



;程序挂起		
	jmp $			;让CPU挂起,等待指令?

使用bochs调试

在0x7c00打断点,输入c跳转执行

$ pb 0x7c00

$ c

输入显示切换模式命令

$ show mode

输入c继续执行

$ c

可以看到控制他输出:

00017609546: switched from 'real mode' to 'protected mode'

说明系统成功的从实模式切换到保护模式

查看CR0的PE位

$ creg

推荐阅读