快捷搜索:  汽车  科技

深入理解bootloader(操作系统开发之)

深入理解bootloader(操作系统开发之)1flush: 2movdword[0xb8000 160 0] 'P' 3movdword[0xb8000 160 1] 0x2f 4 5 jmp $;在这停止,cpu进入睡眠模式 6hlt 7 8times4096-($-$$)db0 ;对齐内存这回截个图: 1... 2out0x92 al 3 4cli 5 6set_PE: 7moveax cr0 8oreax 1 9movcr0 eax 10 11entry_to_protection_mode: 12jmpdword0x8:flush 13... 14ddgdt_head 15 16[bits32] 17;这里已经是32位模式了,nasm就会编译成32位的代码 18flush:此时我们要验证保护模式是否真正开启,需要向显存写入信息,但是这次我们不需要再偏移地址了,直接0xb8000就行: 1

深入理解bootloader(操作系统开发之)(1)

深入理解bootloader(操作系统开发之)(2)

上一节我们已经掌握了进入保护模式的关键,这一节我们来具体实现他。

我们之前向屏幕输出都是通过设置中断实现,比较麻烦,这次我们换个方法,向显存输出信息,显存地址(CGA)是0xB8000~0xBFFFF,我们只需要用其中一段就行,显示功能不会用太多。使用方法很简单,两个显存地址分别存储字符和字符的前景,写入后就可以看到效果了:

1[bits16] 2;后面保护模式的代码就是32位了,先写着 3org0x70000 4 5START: 6;这次一定要初始化 设置堆栈段和栈指针 7movax cs 8movds ax 9moves ax 10movss ax 11movsp 0 12 13point: 14;清屏是个好习惯 15movax 0x2 16int0x10 17 18movax 0xb800 19moves ax 20movdi 0 21movbyte[es:di 0] 'L' 22movbyte[es:di 1] 0xcf 23movbyte[es:di 2] 'o' 24movbyte[es:di 3] 0xcf 25movbyte[es:di 4] 'a' 26movbyte[es:di 5] 0xcf 27movbyte[es:di 6] 'd' 28movbyte[es:di 7] 0xcf 29movbyte[es:di 8] 'i' 30movbyte[es:di 9] 0xcf 31movbyte[es:di 10] 'n' 32movbyte[es:di 11] 0xcf 33movbyte[es:di 12] 'g' 34movbyte[es:di 13] 0xcf

截图太麻烦了,我拿我的人格担保,一定可以显示出Loading,效果和之前是一样的。只是有人会发现,这样打印字符串太不舒服了。是的,有更好的办法,但是现在要先解决保护模式,保护模式进入也需要通过字符输出来确认是否成功,但是进入保护模式后,我们就不能使用BIOS中断来输出字符了,所以这里先简单介绍操作显存。

我们现在来初始化GDT并加载他,根据上一节初探保护模式,我们得知,我们需要填写表相应位的值来初始化,填写完后还要用GDTR加载:

1load_GDTR: 2;保存GDT地址到GDTR 3lgdt[gdt] 4 5gdt_head: 6dd0x0000000 7dd0x0000000 8 9 dw 0x000ffff ;段限制:0-15位 10 dw 0x0000000;段基地址:0-15位 11 db 0x0000000;段基地址:16-23位 12db10011010b;段描述符的第6字节属性(代码段可读写) 13 db 11001111b ;段描述符的第7字节属性:16-19位 14 db 0x0000000;段描述符的最后一个字节是段基地址的第二部分:24-31位 15 16 dw 0x000ffff ;段限制:0-15位 17 dw 0x0000000;段基地址:0-15位 18 db 0x0000000;段基地址:16-23位 19db10010010b;段描述符的第6字节属性(数据段可读写) 20 db 11001111b ;段描述符的第7字节属性:limit(位16-19) 21 db 0x0000000;段描述符的最后一个字节是段基地址的第二部分:24-31位 22 23gdt: 24dwgdt-gdt_head-1 25ddgdt_head

数字后缀b表示二进制。关于GDT的填写,注释已经写得很详细了,可以参考上一篇文章Intel的全局描述符示意图来理解。此时已经完成了GDT的初始化,接下来打开A20地址线。

读端口用in指令,写端口用out指令。有个规定就是在92h端口,如果al的二进制第二位是1则打开,反之关闭:

1... 2lgdt[gdt] 3 4enable_A20: 5inal 0x92 6oral 10b;一般直接写2 7out0x92 al 8 9cli 10 11gdt_head: 12...

然后就是设置PE位,跳转到保护模式:

1... 2out0x92 al 3 4cli 5 6set_PE: 7moveax cr0 8oreax 1 9movcr0 eax 10 11entry_to_protection_mode: 12jmpdword0x8:flush 13... 14ddgdt_head 15 16[bits32] 17;这里已经是32位模式了,nasm就会编译成32位的代码 18flush:

此时我们要验证保护模式是否真正开启,需要向显存写入信息,但是这次我们不需要再偏移地址了,直接0xb8000就行:

1flush: 2movdword[0xb8000 160 0] 'P' 3movdword[0xb8000 160 1] 0x2f 4 5 jmp $;在这停止,cpu进入睡眠模式 6hlt 7 8times4096-($-$$)db0 ;对齐内存

这回截个图:

深入理解bootloader(操作系统开发之)(3)

进入保护模式之后,很多事情就方便做了。今天先这样。

关注"GuEes"公众号,了解更多消息!

猜您喜欢: