学习操作系统原理最好的方法是自己写一个简单的操作系统。


前面铺垫了这么久,今天终于开始写程序了。本讲将介绍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

自己动手从零写桌面操作系统GrapeOS系列教程——13.向MBR中写入程序的更多相关文章

  1. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

  2. 操作系统开发系列—12.g.在内核中设置键盘中断

    8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...

  3. 别人写的一个Bootstrap系列教程

    http://www.cnblogs.com/lansy/category/659061.html

  4. 一个人写的操作系统 - Sparrow OS

    一个人写的操作系统 - Sparrow OS 自己写一个操作系统,这是在过去的几年里我一直为之努力的目标,现在终于完成了. 缘起 自己动手写操作系统的动机最初来自于学习Linux遇到的困难. 我是一个 ...

  5. 自制 os 极简教程1:写一个操作系统有多难

    为什么叫极简教程呢?听我慢慢说 不知道正在阅读本文的你,是否是因为想自己动手写一个操作系统.我觉得可能每个程序员都有个操作系统梦,或许是想亲自动手写出来一个,或许是想彻底吃透操作系统的知识.不论是为了 ...

  6. 【操作系统】关于Linux桌面操作系统

    以前是Win+Ubuntu+黑苹果,周末想体验一下deepin,于是简单安装了一下,安装过程很简单,这里不再描述.安装之后,第一次打开系统,确实很惊艳,赏心悦目的操作系统. 之前用Ubuntu时候,C ...

  7. 盘点|2021年最受欢迎Linux桌面操作系统前十名

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 阿里云开源镜像站利用云服务上的优势,提供快速.稳定的镜像分发服务.和免费的CDN加速服务.更新频率高,基本上一天一更新,对于Centos/Ubun ...

  8. 手把手教你从零写一个简单的 VUE

    本系列是一个教程,下面贴下目录~1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 今天给大家带来的是实现一个简单的类似 VUE 一样的前端框架,VUE 框架现在应 ...

  9. 《一步一步写嵌入式操作系统》读书笔记1—Skyeye介绍、安装和HelloWorld

    2013-11-14 最近在看<一步一步写嵌入式操作系统>,感觉此书甚好,许多地方讲得很清楚.可操作性强,计划边读边实践边写笔记,希望能够逐步熟悉嵌入式操作系统底层的东西,最终剪裁出一套实 ...

  10. Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)

    我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...

随机推荐

  1. Qt ui 文件转换为python代码文件

    python -m PyQt5.uic.pyuic -o ui_xxx.py xxx.ui

  2. JS通用公共函数

    function formatTime(time) { if (typeof time !== 'number' || time < 0) { return time } var hour = ...

  3. 【已解决】Jenkins构建成功但发送邮件失败,报错“Not sending mail to unregistered user xxx@xxx.com because your SCM claimed this was associated with a user ID ‘xxx which your security realm does not recognize; ”

    问题描述:构建成后,但发送邮件失败,具体报错截图如下: 原因:用户在jenkins中名称与发送邮件汇总设置不一样且没有勾选"Allow sending to unregistered use ...

  4. 尝试改善科研V2

    参考链接: https://fulequn.github.io/2022/09/26/Article202209261/ https://www.xljsci.com/ https://apps.an ...

  5. jsp第十周

    数据库test 中建个表 stu(stuid 主键 自动增长 ,用户名,密码,年龄) 1.设计一个注册页面,实现用户注册功能2.设计一个登陆页面,实现用户名密码登陆3.两个页面可以互相超链接 Base ...

  6. Spring Boot 中处理跨域

    HTML 5中新增的跨域资源访问(Cross-Origin Resource Sharing)特性可以让我们在开发后端系统的时候决定资源是否允许被跨域访问.所谓跨域指的是域名不同或者端口不同或者协议不 ...

  7. SpringBoot - Lombok使用详解1(基本介绍、安装配置、var和val)

    我们创建 POJO 类时,经常需要先写属性,然后手写或者自动生成 get 和 set 方法,然后还要重写 toString 方法....一系列操作下来,这个 POJO 类便会产生太多的样板式代码. 这 ...

  8. 正确理解RestFul 接口

    一.REST# REST,即Representational State Transfer的缩写,翻译过来就是"表现层状态转化".不得不承认,我在刚开始看到这个名词的时候是一脸懵逼 ...

  9. 点击按钮触发div颜色改变的几种写法

    目录 JavaScript 行内事件 onclick绑定 关于选取元素 关于改变颜色 addEventListener jQuery 获取元素 绑定事件 设置样式 css() 添加class Vue ...

  10. How to Install VMware Tools on CentOS 6.5

    yum install perl gcc make kernel-headers kernel-devel -y [root@centos6 vmware-tools-distrib]# ./vmwa ...