赞
踩
[原创] 操作系统DIY - 进入保护模式
预备知识:
涉及工具:
NASM,一个文本编辑器(我用的是ConText + NASM语法高亮),QEMU/VMWARE虚拟机
前言:
近期确实很忙,论坛里有一位朋友写的代码进入不了保护模式;我最初也是对保护模式相当敬畏,因为32位比16位要“复杂”的多;当时一直不敢下手,偶尔的尝试有如蜻蜓点水,但最终以失败告终。在学校的图书馆里几乎找不到386保护模式汇编的资料,更不用说CPU相关的书了;不知道看了多少可怜的教材后,终于凑出了一点起眼的代码,不过还是失败了。我最终是通过一个Bona Fide 的实例教程解决了问题:实例程序在我的开发过程中起到了很重要的作用。
由于时间原因,这篇文章将主要以代码来说明,因为我的确没太多的时间再去介绍“实模式”,“保护模式”,GDT,IDT,A20等等等等相关的名词、概念及规范;这些东西在我的网站里已经收罗了:http://www.xemean.net/resource/ ,其中有中文也有英文的,有的甚至是图文并茂,网络上也有不少的例子,但在这里强烈建议的一本电子教程是:《80X86保护模式教程》 ,这本书详细地介绍了如何对 80X86 CPU进行编程,包括进入保护模式,保护模式的中断,多任务等等。另外,值得一提的是:由杨季文等人编著的,清华大学出版社出版的《80x86汇编语言程序设计教程》也是一本不错的书。
此文适合于有一定基础,但又不能实现保护模式切换的朋友。
本文将以我上次写的“启动你的计算机”的代码为基础,演示进入保护模式,但程序还是在引导区内工作。
姑且不理会保护模式下“复杂”的内存管理,多任务,中断,实际上进入保护只要:
mov eax,cr0 ; 控制寄存器CR0 -> EAX
or eax,1 ; 最低位置1,即PE位
mov cr0,eax ; 写回CR0
I386兼容CPU使用CR0这个寄存器来“控制”或者说决定CPU的工作状态,命名为“控制寄存器中”,其中CR0的最低位叫PE位,中文翻译应该是“保护模式允许”位,如果对CR0的PE位置1,则CPU就工作在保护模式下。不幸的是,我们并不能直接对CR0进行操作,但是却可以通过通用寄存器对其修改,上面便是开启保护模式大门的实例。当然,只有上面的代码你可能永远也进不了保护模式。
保护模式与实模式有一个区别在于,段寄存器不再保存实际的内存地址,CPU已经有32位寻址的能力,也就是能访问4G的内存,似乎用32位的EIP就可以访问4G了,但Intel并没有想得那么简单,段寄存器在内存管理方面还有很大的作用。另外,之所以叫保护模式,是因为CPU还能不同应用层的代码进行保护,这在16位实模式是做不到的。因此引入了GDT,及描述符的概念。(这就得请各位看官参看一些资料了)
CPU中有一个高速的寄存器用来保存GDT表在内存中的位置以及GDT表的大小:GDT的大小用16位来表示,GDT的物理地址用32位来表示(以保证GDT能在4G内存的任意位置),因此GDT高速寄存器(GDTR)占48位,已经不能用一个32位的寄存器来表示了,因此要在内存中表示出GDTR内容,书上说这叫“伪描述符”,GDTR由下面的指令装载:
lgdt [__GDTR]
其中__GDTR是GDT伪描述符的地址,一口气,我们作如下数据定义:
ALIGN 4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GDT 伪描述符
; 参考保护模式相关文档以获得关于GDT伪描述
; 符更详细的资料
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__GDTR:
dw GDT_END - GDT-1 ; GDT表的长度,由编译器计算
dd GDT ; GDT物理地址,由编译器计算
;<- END OF __GDTR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GDT entry
; 参考保护模式相关文档以获得关于GDT的更
; 详细的资料
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ALIGN 8 ; 对齐,以保护CPU访问GDT的速度
GDT:
; 第一个GDT作为保留项,以0填充
; reserved GDT
dd 0
dd 0
osCodeSel equ $-GDT ; 内核用的代码段选择子
oscode:
dw 0xffff
dw 0
db 0
db 10011010b ; 0x9A ,可读/可执行 代码段
db 11011111b ;
db 0
osDataSel equ $-GDT ; 内核用的数据段选择子
osdata:
dw 0xffff
dw 0
db 0
db 10010010b ; 0x92 ,可读/写 数据段
db 11011111b ;
db 0
GDT_END: ;<- END OF GDT
完成如上的定义之后,就可以着手进入保护模式了,过程大致为:
如果跳转成功,则CPU就可以工作在保护模式下。保护模式并不像实模式下有很多BIOS中断可用,这就意味着我们必须自己写键盘、显卡等等驱动,计算机的几乎所有资源都由内核来管理,当然,也由你来实现各种设备的驱动。
为了显示我们的程序已经成功地工作在保护模式下,我们必须在32位模式时在屏幕上写点什么东西,直接写显存吧!演示程序对显存进行操作,结果是屏幕的第三行第1列显示了一个洋红色的字母P。
源码编译:nasmw -f bin boot.asm -o boot.bin
用WinImage写入软盘镜像,然后用Qemu或VMware启动。注:不知道什么原因,这段代码并不能在Bochs下工作。
拍照以示留念:
程序源码如下:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。