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


本讲我们设计一个简单的读硬盘实验。通过一定的方法使硬盘第二个扇区的前3个字节依次为1、2、3,最后3个字节依次为3、2、1,中间的506个字节全为0。然后通过读硬盘程序将硬盘第二个扇区的数据读取到内存0x7e00-0x7fff的地方,也就是内存中MBR之后的512个字节。最后通过QEMU+DGB调试的方式来查看内存中0x7e00-0x7fff的数据,是否与硬盘第二个扇区中的数据一致,如果一致说明读硬盘成功。

本讲代码文件共2个:

  • data1.asm
  • boot1.asm

下面我们开始实验。

一、设置硬盘第二个扇区中的数据

data1.asm代码如下:

db 1
db 2
db 3
times 506 db 0
db 3
db 2
db 1

data1.asm就是生成512字节的数据,前3个字节依次是1、2、3,最后3个字节依次为3、2、1,中间的506个字节全为0。

在PowerShell中输入如下命令:

nasm data1.asm -o data1.bin
hexdump data1.bin -C

上述命令是将data1.asm通过汇编器生成了二进制文件data1.bin,然后通过hexdump命令查看data1.bin是否正确。截图如下:

从上面截图可以看到,生成的data.bin文件共512字节,其中前3个字节依次为1、2、3,最后3个字节依次为3、2、1,中间的506个字节全为0。下面将data1.bin文件写入到虚拟硬盘的第二个扇区中。

在PowerShell中输入如下命令:

dd conv=notrunc if=data1.bin of=/media/VMShare/GrapeOS.img seek=1
hexdump /media/VMShare/GrapeOS.img -C

上面dd命令中的参数seek=1意思是在写入GrapeOS.img时,跳过1个写入块,写入块默认大小为512字节,也就将data1.bin写入到虚拟硬盘GrapeOS.img的第二个扇区中。截图如下:

从上面截图中可以看到,虚拟硬盘第二个扇区中的数据达到了我们的实验要求。

二、读硬盘程序

boot1.asm的代码如下:

;定义常量
DISK_BUFFER equ 0x7e00 ;读硬盘临时存放数据用的缓存区,放到boot程序之后。 org 0x7c00 ;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向与cs相同的段 mov esi,1 ;读取硬盘的第2个扇区
mov di,DISK_BUFFER
call func_read_one_sector stop:
hlt
jmp stop ;读取硬盘1个扇区(主硬盘控制器主盘)
;输入参数:esi,ds:di。
;esi LBA扇区号
;ds:di 将数据写入到的内存起始地址
;输出参数:无。
func_read_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,esi
;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端口写入读命令0x20
mov dx,0x1f7
mov al,0x20
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_read:
in ax,dx
mov [di],ax
add di,2
loop .go_on_read
ret times 510-($-$$) db 0
db 0x55,0xaa

上面的代码主要就是读硬盘函数func_read_one_sector,总共分7个步骤,与上讲中的读硬盘操作步骤一致。结合代码注释和之前讲的知识,大家应该是可以看懂的。

下面我们将编译boot1.asm,并将生成的二进制文件写入到虚拟硬盘的第一个扇区。在PowerShell中输入如下命令:

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

截图如下:

在Windows的cmd命令行中启动QEMU调试模式:

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

截图如下:

在PowerShell中启动GDB:

[root@CentOS7 Lesson20]# gdb
(gdb) target remote 192.168.10.102:1234
(gdb) b *0x7c00
(gdb) c
Continuing. Breakpoint 1, 0x00007c00 in ?? ()
(gdb) x /512xb 0x7e00

截图如下:

从截图中可以看到,此时程序停在了断点0x7c00处,此时内存中0x7e00-0x7fff中的数据都是0。

我们输入命令c,让程序继续运行几秒钟,然后Ctrl+C,让程序暂停。此时读硬盘程序应该已经执行完了,我们再来查看一下内存0x7e00-0x7fff中的数据。截图如下:

从截图中可以看到,此时内存中0x7e00-0x7fff的数据和硬盘第二扇区中的数据一致,说明读取成功,实验完毕。


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

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

GrapeOS操作系统交流QQ群:643474045

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

  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. 手把手教你从零写一个简单的 VUE

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

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

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

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

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

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

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

  10. 27、从零写UVC驱动之分析数据传输(设置ubuntu通过串口打印,指定打印到文件,ubuntu切换root用户)

    A. 设置ubuntu让它从串口0输出printk信息a. 设置vmware添加serial port, 使用文件作为串口(在vmware中设置,文件是保存在windows中)b. 启动ubuntu, ...

随机推荐

  1. 在安装SDK8.1和Visual Studio 2017时,提示“已停止工作”

    解决办法:在微软官网下载 .net framework 的最新的开发包(Build apps - Dev Pack),重新安装后问题得到解决. https://dotnet.microsoft.com ...

  2. 复杂的光照与更复杂的阴影实现过程——ShaderCP9

    --20.8.28 这章的内容看了很久,也有很多复杂的内容.中途还有事情耽搁了一会.开学后就继续好好记录努力. 我们在游戏中能看到的让人觉得真实感的来源之一就是真实的光照以及光照所产生的阴影.下面的内 ...

  3. JavaScript 之 数组在内存中的存储方式(连续或不连续)

    最近在纠结一个问题,就是数组这个引用类型在JavaScript 中是不是和其他语言一样开辟了一个连续的内存来存储,但是在JS 中每个元素又可以是不同的类型,这就导致了没办法用一个相同大小的存储,所以数 ...

  4. 1903021126 申文骏 Java 第三周作业 编写代码及运行

    项目 内容 课程班级博客链接 19级信计班(本) 作业要求链接 第三周作业要求 博客名称 1903021126 申文骏 Java 第三周作业 编写代码及运行 要求 每道题要有题目,代码(使用插入代码, ...

  5. Go语言中密码加密校验

    使用go自带的库bcrypt bcrypt是不可逆的加密算法,无法通过解密密文得到明文. bcrypt和其他对称或非对称加密方式不同的是,不是直接解密得到明文,也不是二次加密比较密文,而是把明文和存储 ...

  6. PHP、Navicat安装

    一.PHPStudy小皮面板:https://public.xp.cn/upgrades/phpStudy_64.zip 下载完成后解压后双击 点击立即安装 安装完成 启动MySQL,Nginx(my ...

  7. mysql锁表原因及解决方法

    mysql锁表原因及解决方法   一.导致锁表的原因 1.锁表发生在insert update .delete 中: 2.锁表的原理是 数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住,直到 ...

  8. springboot整合mybatis:查询语句,返回null

    springboot整合mybatis时,查询数据库数据时,返回结果为null; 刚开始以为是数据库没连接上,结果增.改.删的其他语句则执行成功: 但唯有查询语句始终返回null,一条数据一个null ...

  9. C语言初级阶段8——预处理

    C语言初级阶段8--预处理 预定义符号 1.概念:预处理是编译之前做的一些事. 2.常用的预定义符号: 注意:: (1)-(4)的格式占位符都用%是,如:printf("%s",D ...

  10. 更改docker里mysql的字符编码

    进入容器: docker exec -it 容器id/容器名称 bash   cp时容器中的目录写法 容器名称/容器id:容器目录   退出容器使用exit   1 首先去mysql容器中寻找mysq ...