您的位置:首页 > 其它

[系列]OS学习-自己写操作系统(3)- 实模式到保护模式的跳转

2017-04-06 19:24 731 查看
这一章比较难,断断续续看了3天,才搞懂“实模式到保护模式的跳转”

自己的一点心得:

1.保护模式非常复杂,涉及方方面面的规则,不要想一次性、完全弄懂,每次只学该学的就好。

2.CR0(0号控制寄存器)的最后1位如果是0,CPU在实模式下运转;如果是1,在保护模式下运转。

3.一定要自己写一遍GDT、段选择符、以及实模式->保护模式跳转,不然是不可能明白的。

首先来谈谈保护模式下最基础的、最重要的——寻址方式,写寻址方式的文章很多很多,就不在赘述

(我前前后后看了10篇文章,好多教材,还是没懂,最后写了跳转代码、编译进镜像,跟着bochs虚拟机一点点调试才最后明白的)

jmp 保护模式的段选择符:目标语句在目标段的偏移量 这条语句代表:跳跃到保护模式下的目标语句。

大致的动作是这样:

CPU拿出段选择符->取段选择符前13位为段描述符在GDT中的索引-->根据GDTR基址寄存器找到GDT表位置-->取得需要的段描述符-->从中拿出32位的真正段基址-->加上一开始给出的偏移量(最一开始jmp语句中给出)-->偏移量+段基地址=获得物理地址(目前没有开启分页机制,不然要再分页一次,才能得到物理地址)

;使用NASM,如有疑问/bug,欢迎指出!
%include "pm.inc"
org 0700h
jmp LABEL_BEGIN

[section .GDT]
;GDT
;	   		   			   		   段基址,      		 界限,  	属性
LABEL_GDT:			Descriptor			0,					0,		0
LABEL_DESC_CODE32:	Descriptor 			0,	   SegCode32Len-1,		DA_C+DA_32;这里的寻址方式似乎又出现了问题
LABEL_DESC_VIDEO:	Descriptor 	  0B8000h,			   0ffffh,		DA_DRW
;GDT结束

GdtLen 	equ $ - LABEL_GDT	;GDT长度定义
GdtPtr 	dw	GdtLen-1		;GDT界限
dd	0				;GDT基址

;GDT选择子
SelectorCode32	equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo	equ LABEL_DESC_VIDEO - LABEL_GDT
;
;end of [section .GDT]

[section .16]	;16位代码段
[BITS 16]		;原始指令,表示运行在16位处理器上
LABEL_BEGIN:
;将所有段寄存器和SP填好,这只是为了程序的完整性
;实际上除CS外的段寄存器,都并不会被用到
MOV AX,CS
MOV DS,AX
MOV SS,AX
MOV ES,AX
MOV SP,100H

;填写GDT中的descriptor
XOR EAX,EAX
MOV AX,CS
SHL EAX,4
ADD EAX,LABEL_SEG_CODE32
;将32位代码段的 起始物理地址的 前16位,写入段描述符的第3/4个字节内
MOV WORD [LABEL_DESC_CODE32+2],EAX;LABEL_DESC_CODE32代表着地址
SHR EAX,16
MOV BYTE [LABEL_SEG_CODE32+4],AL
MOV BYTE [LABEL_SEG_CODE32+7],AH
;将32位代码段的 起始物理地址的 前16位,写入段描述符的第5/8个字节内
;GDT中所有段描述符填写完成

;填写GDT寄存器的基地址
XOR EAX,EAX
MOV AX,CS
SHL EAX,4
ADD EAX,LABEL_GDT	;LABEL_BEGIN也是地址
MOV WORD [GdtPtr+2],EAX	;GdtPtr也是地址
;GdtPtr填写完成,低字节为段界限,高2字节为GDT的起始物理地址(32位)

;装入gdtr寄存器
LGDT [GdtPtr]	;也是地址
;装入完成

;关中断
CLI
;中断关闭完成

;开启A20地址线
IN	AL,92H
OR	AL,00000010B
OUT	92H,AL
;开启成功,内存不再回卷

;置位,即将打开保护模式
MOV EAX,CR0
OR  AX,1
MOV CR0,EAX
;置位完成

;跳转 下面这句话编译后生成的是:jmp 0x0008H:00000000 偏移量是32位,而0x0008H不是基地址,而是段选择符的地址
JMP DWORD SelectorCode32:0;此时SelectorCode32究竟是“SelectorCode32	equ LABEL_DESC_CODE32 - LABEL_GDT”这句话的偏移地址还是“LABEL_DESC_CODE32 - LABEL_GDT”
;上面这句话已经是在保护模式下了,cpu接到这条指令后,将会自动在selectorcode32选择符中提取索引
;找到段描述符,提取段基地址,加上偏移量后进行寻址
;不加 dword时,如果后面偏移量不是0,可能会发生截断(0x95357454H->0x7454H)
;end of [section .16]

[SECTION 32] ;32位代码段
[BITS 32]
LABEL_SEG_CODE32:
MOV AX,SelectorVideo
MOV GS,AX
;将video选择子的地址放入gs中

;显示字
MOV	EDI, (80*11+79)*2	;11行,79列
MOV	AH,0CH		;黑低红字
MOV	AL,'P'
MOV [GS:EDI],AX	;覆写显存
;显示完成
JMP $
SegCode32Len equ $-LABEL_SEG_CODE32
;end of []


对实模式—>保护模式的跳转进行了更加详尽的注释。

其余的部分请大家看于渊老师的《Orange's》一书。

然后是一致/非一致代码段的call/jmp限制(保护模式下不能随意jmp执行的),做了一个思维导图:

如果我们在甲段;想访问乙段(一致段),那么只要乙>=我们,就可以访问:



接下来谈一谈描述符属性:也是很复杂的事情。

找到了一篇很好的文章:段描述符和段选择符解析,通过这文章,暂时明白了段描述符的意义。

新知识:

1.段界限值(20bit=1M),在G=0(不允许分页情况下),代表段最大长1M个字节,即段最大为1MB

在G=1(允许分页下),代表段最大长1M个页(1个页4kb),即段最大4GB

2.系统段描述符一般都在中断/异常描述符表中
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  os 操作系统