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


在上一讲中我们学习了用汇编语言读硬盘,本讲我们来学习用汇编语言写硬盘。同样也是设计一个简单的实验,实验内容为:

在内存中准备一段有特征的512字节数据,地址为0x7e00~0x7fff,其特征是前3个字节依次为4、5、6,最后3个字节依次为6、5、4。然后将该段内存数据写入到硬盘的第2个扇区,并查看虚拟硬盘第2个扇区的数据是否与内存中0x7e00~0x7fff的数据一致,如果一致则说明写硬盘成功。

本讲代码文件只有一个boot2.asm

boot2.asm代码如下:

;定义常量
DISK_BUFFER equ 0x7e00 ;临时存放数据用的缓存区,放到boot程序之后。0x7e00~0x7fff。 org 0x7c00 ;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向与cs相同的段 mov bx,DISK_BUFFER
;向缓存区前3个字节依次写入4、5、6。
mov byte [bx+0],4
mov byte [bx+1],5
mov byte [bx+2],6
;向缓存区最后3个字节依次写入6、5、4。
mov byte [bx+509],6
mov byte [bx+510],5
mov byte [bx+511],4 mov si,DISK_BUFFER
mov edi,1 ;写入硬盘的第2个扇区
call func_write_one_sector stop:
hlt
jmp stop ;将内存中的512个字节写入到硬盘的一个指定扇区中(主硬盘控制器主盘)
;输入参数:ds:si,edi。
;ds:si 数据源内存地址
;edi LBA扇区号
;输出参数:无。
func_write_one_sector:
;第1步:检查硬盘控制器状态
mov dx,0x1f7
.not_ready1:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0xc0 ;第7位为1表示硬盘忙,第6位为1表示硬盘控制器已准备好,正在等待指令。
cmp al,0x40 ;当第7位为0,且第6位为1,则进入下一个步。
jne .not_ready1 ;若未准备好,则继续判断。
;第2步:设置要写入的扇区数
mov dx,0x1f2
mov al,1
out dx,al ;写入1个扇区
;第3步:将LBA地址存入0x1f3~0x1f6
mov eax,edi
;LBA地址7~0位写入端口0x1f3
mov dx,0x1f3
out dx,al
;LBA地址15~8位写入端口写入0x1f4
shr eax,8
mov dx,0x1f4
out dx,al
;LBA地址23~16位写入端口0x1f5
shr eax,8
mov dx,0x1f5
out dx,al
;第4步:设置device端口
shr eax,8
and al,0x0f ;LBA第24~27位
or al,0xe0 ;设置7~4位为1110,表示LBA模式,主盘
mov dx,0x1f6
out dx,al
;第5步:向0x1f7端口写入写命令0x30
mov dx,0x1f7
mov al,0x30
out dx,al
;第6步:检测硬盘状态
.not_ready2:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0x88 ;第7位为1表示硬盘忙,第3位为1表示硬盘控制器已准备好数据传输。
cmp al,0x08 ;当第7位为0,且第3位为1,进入下一步。
jne .not_ready2 ;若未准备好,则继续判断。
;第7步:向0x1f0端口写数据
mov cx,256 ;每次写入2字节,一个扇区需要写256次。
mov dx,0x1f0
.go_on_write:
mov ax,[si]
out dx,ax
add si,2
loop .go_on_write
ret times 510-($-$$) db 0
db 0x55,0xaa

之前我们介绍过读硬盘操作和写硬盘操作都是7个步骤,其中只有第5步和第7步不同,其它步骤完全相同,大家可以和上一讲中的代码对比看一下。

下面我们将boot2.asm编译并写入到虚拟硬盘的第一个扇区:

nasm boot2.asm -o boot2.bin
dd conv=notrunc if=boot2.bin of=/media/VMShare/GrapeOS.img

此时用hexdum命令查看一下虚拟硬盘第二个扇区当前的数据,截图如下:

从上面的截图可以看到,此时虚拟硬盘第二个扇区前3个字节依次为1、2、3,最后3个字节依次为3、2、1。

下面我们以调试模式运行QEMU:

qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img -S -s

通过GDB连接到QEMU,直接输入GDB命令c,让程序运行几秒钟,然后Ctrl+C,让程序暂停。此时写硬盘程序应该已经运行完了。此时查看一下内存0x7e00~0x7fff的数据:

(gdb) x /512xb 0x7e00

从上面截图可以看到,在内存0x7e00~0x7fff的数据中,前3个字节依次为4、5、6,最后3个字节依次为6、5、4,其余全是0。如果程序运行正确的话,此时硬盘第二扇区中的数据与此相同。

下面我们退出GDB,并关闭QEMU。然后用hexdum命令再查看一下虚拟硬盘第二个扇区的数据,截图如下:

从上面截图中可以看到,硬盘第二扇区的数据与内存中0x7e00~0x7fff的数据一致,说明写入成功,实验完毕。


本讲视频版地址:https://www.bilibili.com/video/BV1Hk4y187Bw/

配套的代码与资料在:https://gitee.com/jackchengyujia/grapeos-course

GrapeOS操作系统交流QQ群:643474045

自己动手从零写桌面操作系统GrapeOS系列教程——21.汇编语言写硬盘实战的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. Zedboard学习(一):移植Ubuntu桌面操作系统 标签: ubuntu移植zedboardFPGA 2017-07-04 21:53 26人阅读

    环境准备: 首先,需要的肯定是Ubuntu操作系统.可以在自己的电脑上安装物理机,也可以是虚拟机下运行的.我的是在Vmware下运行的Ubuntu14.04 32位操作系统. 由于zedboard上的 ...

  8. 我是如何学习写一个操作系统(二):操作系统的启动之Bootloader

    前言 今天本来的任务看书和把之前写的FragileOS整理一下,但是到现在还在摸鱼,书也只看一点.后来整理了一下写这个系列的思路,原本的目的是对操作系统原理性的学习和对之前写的一个玩具型操作系统的回顾 ...

  9. 自己动手写Vector【Cherno C++教程】

    动手写一个Vector 本文是对<最好的C++教程>的动手写数据结构部分的一个整理,主要包含91p动手写Array数组和92p动手写Vector数组的内容. 自己动手来写这些数据结构是学习 ...

  10. 红旗 Linux 桌面操作系统11来了:支持国产自主CPU,全新UI风格设计,兼容面广...

    链接:https://reurl.cc/g8ke9X 红旗Linux桌面操作系统11将于1月10日开放预览版的下载,新版本具有良好的硬件兼容,支持多款国产自主CPU品牌,同时还具有丰富的外设支持及海量 ...

随机推荐

  1. nginx 工作流程

    NGINX 把http请求处理流程划分为11个阶段,逻辑细分,以模块为单位进行处理.各个阶段可以包含多个http模块,每个阶段以流水线的形式处理请求.这样的分层处理模式与计算机网络的7层模式类似,每个 ...

  2. wx小程序 组件无法使用全局样式 (app.wxss)

    解决方法: 在组件中加上options选项 Component({ options: { addGlobalClass: true } })

  3. vscode python配置pip源

    更换到国内清华园 C盘-User-用户名-新建"pip"文件夹-新建"pip.ini"文件 pip.ini 文件中内容: [global]index-url = ...

  4. mysql重新设置列的自增初始值

    alter table xxx auto_increment = 100; 因为设置了列的自增之后,若删除过一些行,下次再新增时还会从已删除的id算起自增,为了让数据看起来连续,可以重新设置自增起始值 ...

  5. 前端本地 Nginx 反向代理

    一.问题引入 本地开发遇到线上bug,debug得stash代码切换分支,同时需切换开发环境与生产环境服务,npm run serve 或 npm start 费时 二.webpack-dev-ser ...

  6. pyqt学习

  7. layui相关问题总结

    1.layui table回显选中 1) radio: done:function(res, curr, count){ for(var i = 0; i < res.data.length; ...

  8. sar与ksar使用显示监控数据

    一.Ksar: 1)下载ksar地址:https://github.com/vlsi/ksar/releases/tag/v5.2.4-snapshot.10-gf068072 2)启动:java - ...

  9. getElementsByClassName()获取不到值

    在这种方式下,虽然使用了getElementsByClassName方法,但是并不能获得到值.从执行顺序上来说,在HTML还没有执行的时候JS就已经开始执行了,所以获得的值不能够获得到.因此,如果遇到 ...

  10. POJ3723 Conscription 题解

    start: 2021-08-04 16:56:50 题目链接: http://poj.org/problem?id=3723 题目内容: Description Windy has a countr ...