自制操作系统系列(二):软盘读取

news/2024/5/21 15:00:59/文章来源:https://blog.csdn.net/github_35735591/article/details/127276107

代码仓库地址:https://github.com/freedom-xiao007/operating-system

简介

在上一篇中,我们使用汇编编写了一个直接显示hello的程序,接下来我们继续探索如果使用汇编读取软盘数据

软盘数据读取准备

在上一篇中,我们使用nasm将程序制作成了img文件,在尝试中,这个就可以视为软盘,使用软盘的读取方式能读取我们这个img文件

文件读取的功能不用自己实现,在BIOS函数中(可以视为系统级的函数库,里面提供了一些通用的函数)有相关的文件读取功能:BIOS INT 13H

其相关的说明如下:

① 13H号功能调用02H号子功能:
读扇区入口参数:

  • AH=02,指明读扇区功能调用
  • AL要读扇区数
  • DL驱动器代号,0和1代表软盘,80H和81H代表硬盘
  • DH所读磁盘磁头号,以软盘来说,只能是0和1
  • CH 10位磁道号的低8位,
  • CL寄存器的第6、第7位存放其高2位CL低5位为要读的第一个扇区的扇区号(注意扇区号从1开始而非从0开始)。高2位表示磁道柱面号的高2位ES:
  • BX指出存放从磁盘所读数据的内存地址出口参数:
  • 读出数据放在ES:BX所指的内存区域中若产生错误,CF置1,AH内为错误代码

更多的细节可以参考:《汇编语言程序设计》第三版的10.2.2和10.3章节,微信读书上有

还需要了解软盘的相关知识,在《30天自制操作系统》中,我们看到其对软盘的描述,如下图:

在这里插入图片描述

我们需要循环读取磁头,柱面,扇区,才能把整个磁盘的数据进行读入

根据两本参考书和相关的资料,我们先把软盘数据读取功能实现,博主能力问题,没有办法步子迈太大

程序整体思路

程序实现的大致思路如下:

  • 1.软盘读取相关的参数定义,也就是:AH、AL、DL、DH、CH、BX、ES
  • 2.循环磁头、柱面、扇区,读取整个软盘数据到内存中
  • 3.为了验证,我们读取内存中的内容,并打印到屏幕上

整体思路有了,我们开始看代码细节

程序细节实现

1.软盘读取的相关的参数定义

我们把软盘读取函数的相关的参数先给定义好,具体的说明如下,代码中已加入相关的注释:

; 定义数据存放的内存开始地址
OffSetOfLoader	equ	0x0820
read_file_ready: ;读软盘准备MOV AH, 02 ;指明读扇区功能调用MOV AL, 1 ;指明要读的扇区数为1MOV DL, 0x00 ;指明要读的驱动为AMOV DH, 0 ;指定读取的磁头0MOV CH, 0 ;柱面0MOV CL, 1 ;读取扇区1(因为目前没有其他文件,就只有扇区1的启动区数据,所以我们这从1开始,不是从2开始);下面三句指定读取到内存地址0x0820处MOV AX, OffSetOfLoaderMOV ES, AXMOV BX, 0 ;数据读取后放到的内存地址

需要注意的是CL,扇区的值。在书中是2,跳过了启动区扇区1的数据,我们这里没有其他的文件,就只有启动区的数据,所以我们从扇区1开始进行加载

2.循环读取软盘数据

我们需要循环扇区、磁头、柱面就行数据的读取,代码如下:

read_file:;调试用,用于查看读取磁盘是否达到了循环次数,call相当于函数调用MOV SI, read_file_msgCALL func_show_msg;前面调用函数时,改变了有关的寄存器,这里重置回来(也可以使用栈,但这个方便点)MOV AH, 02 ;指明读扇区功能调用MOV AL, 1 ;指明要读的扇区数为1MOV BX, 0 ;数据读取后放到的内存地址INT 13H ;调用BIOS文件读取JNC read_file_loopMOV SI, read_file_error_msgJMP show_msg_info
read_file_loop: ;循环读取内容,循环的顺序是扇区->磁头->柱面,不知道这里面是否有什么说法?可以调换吗?;把内存地址后移0x200MOV AX, ESADD AX, 0x0020MOV ES, AXADD CL, 1 ;加1,读取下一个扇区CMP CL, 18 ;如果CL扇区大于软盘总扇区数18,则说明读取完成,不再读取JBE read_file; 上面是扇区的循环,完毕后到磁头的循环,重置扇区,增加磁头到反面1MOV CL, 1ADD DH, 1CMP DH, 2JB read_file;上面都完成后,到柱面的读取循环,重置扇区(前面已重置)和磁头,增加柱面(不知道为啥书中不是80而是10)MOV DH, 0ADD CH, 1CMP CH, 10JB read_file
; 相关的函数定义
func_show_msg:MOV AL,[SI]ADD SI,1CMP AL,0JE func_retMOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOSJMP func_show_msg
func_ret:RET
; 相关的字符定义
read_file_msg:DB "r"DB 0
read_file_error_msg:DB 0x0a , 0x0a ;换行两次DB "read file error!!!"DB 0x0aDB 0

在编写的过程中,问题频发,所以我们这里对循环进行了验证,每次调用BIOS的软盘读取函数,我们就打印一个字符:r

这里我们读取也没有采用书中的重试五次的策略,直接一次到位,读取错误就显示错误即可,感觉方便一点,当然,你们也可以试试加上重试策略

接下来的循环部分,都是参数的书中的代码了,这里就不多说了

3.读取加载到内存中的文件内容,并进行显示

为了验证我们程序的正确性,我们读取内容中的数据,打印到屏幕上,看看是否正确

软盘数据读取到的内容位置是开头我们定义的位置:OffSetOfLoader

而我们的大小就是512,所以我们直接循环512次即可,代码如下:

show_mem_file: ;打印显示刚才加载的文件内容MOV AX, OffSetOfLoaderMOV ES, AXMOV DI, 0
show_mem_byte: ;整个数据也就512,所以循环512次即可MOV AL, BYTE [ES:DI]CMP DI, 512JE loader_endADD DI, 1MOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOS	JMP show_mem_byte
loader_end: ;启动程序加载完成MOV AL,0x0aMOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOSMOV SI,msg
···这样我们就基本完成,运行看下效果:```sh
; 编译
PS E:\code\other\self\operating-system> D:\software\NASM\nasm.exe .\myOS.asm -o .\myOS.img:运行
PS E:\code\other\self\operating-system>  D:\software\qemu\qemu-system-x86_64.exe -L . -m 64 -fda .\myOS.img
WARNING: Image format was not specified for '.\myOS.img' and probing guessed raw.Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.Specify the 'raw' format explicitly to remove the restrictions.(qemu:19348): Gtk-WARNING **: 09:01:44.555: Could not load a pixbuf from icon theme.
This may indicate that pixbuf loaders or the mime database could not be found.

结果如下图:

在这里插入图片描述

完整代码

所有的代码如下:

; cherry-os
ORG 0x7c00 ;指定程序装载的位置;下面用于描述FAT12格式的软盘
JMP entry
DB 0x90
DB "CHRRYIPL" ;启动区的名称可以是任意的字符串,但长度必须是8字节
DW 512; 每一个扇区的大小,必须是512字节
DB 1 ;簇的大小(必须为1个扇区)
DW 1 ;FAT的起始位置(一般从第一个扇区开始)
DB 2 ;FAT的个数 必须是2
DW 224;根目录的大小 一般是224项
DW 2880; 该磁盘的大小 必须是2880扇区
DB 0xf0;磁盘的种类 必须是0xf0
DW 9;FAT的长度 必须是9扇区
DW 18;1个磁道(track) 有几个扇区 必须是18
DW 2; 磁头个数 必须是2
DD 0; 不使用分区,必须是0
DD 2880; 重写一次磁盘大小
DB 0,0,0x29 ;扩展引导标记 固定0x29
DD 0xffffffff ;卷列序号
DB "CHERRY-OS  " ;磁盘的名称(11个字节)
DB "FAT12   " ;磁盘的格式名称(8字节)
TIMES 18 DB 0; 先空出18字节 这里与原文写法不同OffSetOfLoader	equ	0x0820;程序核心
entry:MOV AX,0  ;初始化寄存器MOV SS,AXMOV SP,0x7c00MOV DS,AXMOV ES,AX
read_file_ready: ;读软盘准备MOV AH, 02 ;指明读扇区功能调用MOV AL, 1 ;指明要读的扇区数为1MOV DL, 0x00 ;指明要读的驱动为AMOV DH, 0 ;指定读取的磁头0MOV CH, 0 ;柱面0MOV CL, 1 ;读取扇区1(因为目前没有其他文件,就只有扇区1的启动区数据,所以我们这从1开始,不是从2开始);下面三句指定读取到内存地址0x0820处MOV AX, OffSetOfLoaderMOV ES, AXMOV BX, 0 ;数据读取后放到的内存地址
read_file:;调试用,用于查看读取磁盘是否达到了循环次数,call相当于函数调用MOV SI, read_file_msgCALL func_show_msg;前面调用函数时,改变了有关的寄存器,这里重置回来(也可以使用栈,但这个方便点)MOV AH, 02 ;指明读扇区功能调用MOV AL, 1 ;指明要读的扇区数为1MOV BX, 0 ;数据读取后放到的内存地址INT 13H ;调用BIOS文件读取JNC read_file_loopMOV SI, read_file_error_msgJMP show_msg_info
read_file_loop: ;循环读取内容,循环的顺序是扇区->磁头->柱面,不知道这里面是否有什么说法?可以调换吗?;把内存地址后移0x200MOV AX, ESADD AX, 0x0020MOV ES, AXADD CL, 1 ;加1,读取下一个扇区CMP CL, 18 ;如果CL扇区大于软盘总扇区数18,则说明读取完成,不再读取JBE read_file; 上面是扇区的循环,完毕后到磁头的循环,重置扇区,增加磁头到反面1MOV CL, 1ADD DH, 1CMP DH, 2JB read_file;上面都完成后,到柱面的读取循环,重置扇区(前面已重置)和磁头,增加柱面(不知道为啥书中不是80而是10)MOV DH, 0ADD CH, 1CMP CH, 10JB read_file
show_mem_file: ;打印显示刚才加载的文件内容MOV AX, OffSetOfLoaderMOV ES, AXMOV DI, 0
show_mem_byte: ;整个数据也就512,所以循环512次即可MOV AL, BYTE [ES:DI]CMP DI, 512JE loader_endADD DI, 1MOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOS	JMP show_mem_byte
loader_end: ;启动程序加载完成MOV AL,0x0aMOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOSMOV SI,msg
show_msg_info: ;加载完成,成功显示MOV AL,[SI]ADD SI,1CMP AL,0JE finMOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOSJMP show_msg_info
fin:HLT ;CPU停止,等待指令JMP fin ;无限循环
func_show_msg:MOV AL,[SI]ADD SI,1CMP AL,0JE func_retMOV AH,0x0e ;显示一个文字MOV BX,15 ;指定字符的颜色INT 0x10 ;调用显卡BIOSJMP func_show_msg
func_ret:RET
read_file_msg:DB "r"DB 0
read_file_error_msg:DB 0x0a , 0x0a ;换行两次DB "read file error!!!"DB 0x0aDB 0
show_mem_info_msg:DB 0x0a , 0x0a ;换行两次DB "start show mem file!!!"DB 0x0aDB 0
msg:DB 0x0a , 0x0a ;换行两次DB "hello, my OS, boot loader end"DB 0x0aDB 0boot_flag: ;启动区标识TIMES 0x1fe-($-$$) DB 0 ;填写0x00,直到0x001feDB 0x55, 0xaa

总结

看书感觉挺简单,动手起来困难重重啊。虽然完全使用书中的功能和内容可以跑,但自己动手改造和使用其他工具实现起来就有各种问题,但又不能不去做,就像抄作业,学渣就只抄,原理搞不懂,学霸抄了还理解了原理,题目一变考试也不慌。

这几天真是额头发烫,还好各种翻书和查阅资料,把这部分按照自己的理解给完成了

可能各位在实现的过程也会遇到其他的问题,可以翻翻下面三本书(微信读书上都有)和查阅资料:

  • 《三十天自制操作系统》
  • 《汇编程序语言设计》
  • 《一个64位操作系统的设计与实现》

上面两本书的相关代码也可以去看看,参考参考,链接点击书名即可

博主的相关实现也可以参考,但没有像他们一样根据天数进行划分,只能回退相关的代码版本查看

  • https://github.com/freedom-xiao007/operating-system

参考链接

  • Windows/Linux 制作ISO文件
  • Can NASM generate a file with machine code hexdump + asm source?
  • 汇编语言指令大全 X86和X87汇编指令大全(带注释)
  • 「30天制作操作系统系列」1~4天从汇编到C语言
  • [从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记 ](https://blog.51cto.com/u_15127595/381017OS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_22359.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让运维化繁为简,云原生可观测平台 Alibaba Cloud Lens 正式发布

9 月 28 日,阿里云正式推出云产品可观测平台 Alibaba Cloud Lens(Lens 透镜,意为洞察细微变化),从成本、性能、安全、数据保护、稳定性、访问分析六个维度,为用户提供对存储类、网络类、数据库类等云产品的…

还在埋头敲代码?不妨学学设计模式,必能让你工作事半功倍

设计模式在开发中占很重要的地位;在大型项目中使用好设计模式往往会取得事半功倍的效果;下面就介绍下几种在开发中常用到的设计模式 装饰者模式(Decorator Pattern) 装饰者模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的…

中断系统:外部中断

中断系统:外部中断 实现功能 按下独立按键Key3,LED流水灯向右;按下Key4,LED流水灯向左。 单片机型号:STC89C52 硬件原理 中断系统就是当系统在进行一项工作时,需要终止这项工作,转而去执行另一…

Springboot复习

本笔记来自b站尚硅谷 文章目录SpringbootHelloWorld原理Value获取值和ConfigurationProperties获取值比较PropertySource 和 ImportResourceprofile自动配置原理整合日志指定配置全面接管SpringMVC启动流程自定义starterdev-toolsyml提示指标监控Springboot HelloWorld原理 配置…

Python函数练习题:通讯录管理程序实战案例

嗨害大家好鸭!我是小熊猫❤ 好久没有整实战案例类文章辽 今天就来整一整~ 功能简介 实现一个通讯录管理程序,使用函数来实现程序,采用模块化的程序设计方法: 划分通讯录程序的功能模块,使用函数实现相应的功能首先…

数据湖-hudi概述

前言 数据湖是目前比较热的一个概念,许多企业都在构建或者计划构建自己的数据湖。 数据湖是一个集中式存储库,允许您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对数据进行结构化处理),并运…

nginx80转443

多了一个server,做了一个301的跳转 server { listen 80; server_name www.web1.com web1.com; (这里是可写别名的,第二个是别名) return 301 https://www.web1.com$request_uri; (当别人访问80,让它转到…

智能网联-浅谈基于PKI的车联网应用服务安全

智能网联-浅谈基于PKI的车联网应用服务安全 面对车联网快速发展趋势,信息安全是一项必要的防护措施。车端应用数字证书可认证合法身份,保障数据加密通信,防止信息的泄露与攻击。基于PKI的车联网应用服务安全认证体系框架,从国家层…

Java多线程的创建与Thread类的方法及使用

Java多线程的创建与Thread类的方法及使用🍎一.Thread类的属性与方法🍇1.1什么是线程🍇1.2Thread类的基础常见的构造方法🍇1.3Thread的常见属性🍇1.4Thread类常用的基础方法🍎二.Java线程的创建&#x1f347…

6步搭建一个飞机大战游戏

摘要:本文以华为云软件开发平台DevCloud为例,展示飞机大战游戏开发的DevOps实践流程。DevOps实践 DevOps实践是一种开发、测试运维一体化的模式,其实践的外在表现一般包括了如代码仓库、构建、测试、发布、配置、监控等工具形成的一个完整的…

引擎之旅 Chapter.3 文件系统

文章目录引言在此之前...Unicode和ASCIIC风格字符串的操作函数集合字符串操作字符串类型转换Part1:操作文件名和文件路径Part2:单个文件的读写文件打开的模式TFile的定义Part3:异步文件I/O异步I/O线程文件类中的异步方法引言 为什么会将文件…

数据中台开源解决方案(一)

数据中台商业的解决方案有很多,开源框架种类繁多,每一个模块都有很多开源的套件。以查询引擎为例,可以使用的开源工具有MySQL、Redis、Impala、MongoDB、PgSQL等。可以根据实际业务需要,选择合适的开源套件。 可供选择的解决方案太多,重点推荐开源解决方案,框架图如下图所…

【RCJ-2 AC220V 0.015A静态冲击继电器】

系列型号 RCJ-2/48VDC冲击继电器 RCJ-2/110VDC冲击继电器 RCJ-2/220VDC冲击继电器 RCJ-2/100VAC冲击继电器 RCJ-2/127VAC冲击继电器 RCJ-2/220VAC冲击继电器 RCJ-3/220VAC冲击继电器 RCJ-3/127VAC冲击继电器 RCJ-3/100VAC冲击继电器 RCJ-3/220VDC冲击继电器 RCJ-3/110VDC冲击继…

【论文笔记】CIKM‘22 & Amazon | (Navip) 推荐系统中图神经网络的去偏邻域聚合

目录1. Introduction2. Related Work2.1 基于GNN的推荐2.2 逆倾向评分IPS3. 模型3.1 Navip4. 实验结果本文是亚马逊在CIKM 2022的一篇工作 论文地址:https://arxiv.org/pdf/2208.08847.pdf 问题 图形神经网络(GNN)对于曝光偏差的脆弱性导致模型偏差,产生…

09-Pytorch中的序列化容器

目录 1.梯度消失和梯度爆炸 1.1 梯度消失 1.2 梯度爆炸 1.3 解决梯度消失或梯度爆炸的经验 2.nn.Sequential 3.nn.BatchNorm1d 4.nn.Dropout 1.梯度消失和梯度爆炸 在使用pytorch中的序列化容器之前,我们先来了解一下常见的梯度消失和梯度爆炸的问题。 1.1 …

②、HTML 元素学习

HTML 元素 HTML 文档由 HTML 元素定义。 HTML 元素 *开始标签常被称为起始标签(opening tag),结束标签常称为闭合标签(closing tag)。 HTML 元素语法 HTML 元素以开始标签起始HTML 元素以结束标签终止元素的内容是开始…

Class02

Class02 1.自动类型值转换 隐式类型转换 显式类型转换 隐式类型转换(自动类型转换) 隐式类型转换是小范围向大范围转换 实际上小范围包含在大范围内 整数类型的默认类型为int 浮点数类型的默认类型为double 显式类型转换(强制类型转换&am…

linux 预读机制 (linux4.14)

一、基本概念 设计背景 文件一般是顺序访问的,访问[A, B]范围的数据后,接下来很可能访问[B1, BN]数据。由于访问磁盘、flash等存储器件比较耗时,在访问 [A, B]的时候,如果提前把[B1, BN]数据从存储器件读取到ram中,那…

TTN服务器LoRaWAN网关配置流程

在LoRaWAN物联网网络中,LoRaWAN网关起到了绝对核心的作用,它在整个网络中像是一座桥梁建立起网络服务器与终端节点的通信,下面我们将简单介绍如何使用E890-470LG11网关实现TTN服务器与终端节点的通信。 首先,在LoRaWAN通信中&…

亿佰特LoRaWAN入网TTN并订阅MQTT消息

一、LoRaWAN节点入网 1.注册并登录TTN账号。 2.添加网关。Gateway EUI可自定义。 3.切换到亿百特网关配置网页(http://192.168.10.1/),配置网关。 4.切抱TTN网页,创建app,Application ID可任意取,只要不重复就行&…