• 自己动手从零写桌面操作系统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

  • 相关阅读:
    IT基础设施管理
    【C语言】23-结构体类型
    目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】3D视觉
    TD集群内存占用过高
    SSM学习36:编程思想总结(重点)
    c语言入门---预处理
    整数——算法专项刷题(一)
    CSS三栏布局的7种方式代码详解 | 圣杯布局 | 双飞翼布局 | 弹性盒子
    Proactive Privacy-preserving Learning for Retrieval 论文笔记
    mysql的组提交
  • 原文地址:https://www.cnblogs.com/chengyujia/p/17215037.html