自己动手从零写桌面操作系统GrapeOS系列教程——13.向MBR中写入程序
学习操作系统原理最好的方法是自己写一个简单的操作系统。
前面铺垫了这么久,今天终于开始写程序了。本讲将介绍3个逐步深入但非常简单的程序,一方面是让大家熟悉开发流程,另一方面是顺便解决前面遇到的CPU占用率高的问题。
一、mbr1.asm回顾
mbr1.asm的代码之前我们介绍过,这里我们回顾一下代码和演示步骤。
mbr1.asm代码如下:
;生成一个空的MBR
times 510 db 0 ;前510个字节全为0
db 0x55,0xaa ;最后两个字节是0x55和0xaa。
下面我们来演示:
1.启动并登录CentOS
在VirtualBox中启动CentOS虚拟机,并用PowerShell登录到CentOS虚拟机。
2.创建空虚拟硬盘
如果没有虚拟硬盘或想重新创建一个空的虚拟硬盘,执行下面这条语句:
dd if=/dev/zero of=/media/VMShare/GrapeOS.img bs=1M count=4
截图如下:
在上面截图中,用hexdump命令查看生成的虚拟硬盘文件GrapeOS.img,可以看到每个字节都是0,符合预期。
3.汇编mbr1.asm
nasm mbr1.asm -o mbr1.bin
截图如下:
在上面截图中,用hexdump命令查看生成的mbr1.bin,共512个字节,前510个字节都是0,最后两个字节是0x55和0xaa,符合预期。
4.将mbr1.bin写入到虚拟硬盘中
dd conv=notrunc if=mbr1.bin of=/media/VMShare/GrapeOS.img
截图如下:
在上面截图中,我们同样用hexdump命令验证,看到的确是将mbr.bin写入到虚拟硬盘的第一个扇区中了。
5.启动QEMU
在Windows的cmd命令行中运行如下命令:
qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img
从截图上可以看到,运行结果和之前的一样。回顾到此为止,下面来解决CPU占用率高的问题。
二、CPU占用率高的原因
前面我们介绍过,在QEMU+GDB调试中,反编译16位代码是有问题的,下面来介绍另一种反编译方法。nasm汇编器自带了一个反汇编工具叫ndisasm,下面我们来反汇编mbr1.bin。
ndisasm mbr1.bin
截图如下:
从截图中可以看到两个0字节正好是一条汇编指令“add [bx+si],al”,最后的2个字节0x55和0xaa也正好是指令“push bp”和“stosb”。但这些都不是我们要写的程序,只是这些二进制数正好是某条机器指令。从BIOS跳转到0x7c00地址后,无论此处是什么样的二进制数,CPU都会把它当作指令一条一条的执行。当执行完这512字节,会继续执行后面内存中的数据。而后面内存中的数据是不确定的,CPU就会乱执行半天,而且也没有意义,这就是程序跑飞了。下面我们先来解决程序跑飞的问题。
三、mbr2.asm阻止程序跑飞
1.程序讲解
mbr2.asm代码如下:
jmp $ ;$表示当前行的地址
times 510-($-$$) db 0 ;$$表示段开始的地址,$-$$表示当前行前面的代码占用的字节数。
db 0x55,0xaa
在Linux命令行中执行如下命令:
nasm mbr2.asm -o mbr2.bin
hexdump mbr2.bin -C
ndisasm mbr2.bin
从上面截图中可以看到“jmp $”生成的机器码是“0xeb,0xfe”,其中0xeb是操作码,0xfe是操作数。这条指令中的操作数是当作有符号数处理的,0xfe换算成十进制数是“-2”(负2)。而这条指令共2个字节,当CPU读取完这条指令后寄存器ip的值会加2,执行完这条指令后,寄存器ip的值会加负2。这样的话CPU就会不断的重复执行这条指令,程序就不会跑飞了。
2.程序演示
下面我们将mbr2.bin写入到虚拟硬盘的第一个扇区。
dd conv=notrunc if=mbr2.bin of=/media/VMShare/GrapeOS.img
hexdump /media/VMShare/GrapeOS.img -C
然后用调试模式观察一下。
qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img -S -s
前面我们介绍过,这里GDB是按32位反汇编的,16位反汇编是有问题的。但有些汇编代码在16位和32位下生成的机器码是一样的,比如这里的jmp $
。所以这里的反汇编也可以适当参考一下。从上面截图上可以看到,每次单步运行后,程序地址仍然停留在0x7c00。这就是通过死循环来防止程序跑飞的办法。
下面我们来删除断点,让程序正常运行。
首先来查看断点:
(gdb) i b
删除断点:
(gdb) d 断点编号
然后让程序继续运行:
(gdb) c
截图如下:
mbr2.asm虽然解决了程序跑飞的问题,但CPU占用率仍然高,笔记本风扇还是呼呼的转。下面我们来彻底解决这个问题。
四、mbr3.asm彻底解决CPU占用率高的问题
mbr3.asm的代码如下:
stop:
hlt ;使CPU暂停运行,直到有中断发生。(降低CPU使用率)
jmp stop
times 510-($-$$) db 0
db 0x55,0xaa
上述代码主要用了一个hlt
指令,让CPU暂停,如果有中断发生,会执行下一行jmp stop
,然后又执行hlt
。这样不仅防止了程序跑飞,而且降低了CPU使用率。
有了前面的基础,我们这次编译运行一气呵成。
在Linux命令行中执行:
nasm mbr3.asm -o mbr3.bin
dd conv=notrunc if=mbr3.bin of=/media/VMShare/GrapeOS.img
在Windows命令行中执行:
qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img
截图如下:
从上图任务管理器中可以看到,QEMU的CPU占用率已经降下来了。
本讲视频版地址:https://www.bilibili.com/video/BV1io4y1i7GP/
本教程代码和资料:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系统QQ群:643474045
博客主页:http://www.cnblogs.com/chengyujia/
欢迎转载,但请保留作者和本文链接,谢谢!
欢迎在下面的评论区与我交流。