手写操作系统--读写硬盘操作

手写操作系统--读写硬盘操作在划分一下就会出现我们的扇区 每个扇区的大小是固定的 一般来说是 512 个字节

以下图片均来自王道考研视频我们先来看看硬盘的结构:

 这是物理图上的磁盘构造。

 一个盘片被分成一个个的磁道。

 在划分一下就会出现我们的扇区,每个扇区的大小是固定的,一般来说是512个字节。最内侧的扇区面积小,因此数据密度就密。在我们操作磁盘的时候,一般就以扇区为最小单位。

这样许多个盘片组合起来就是一整个磁盘。下图是一个解剖图:

 这些磁头都是连接在同一个磁臂上的。这样就组成了一个柱子形状,我们称之为柱面。有了上图的基础,我们就能用柱面号,盘面号,扇区号来唯一标识一块磁盘块。其实柱面号也可以理解为我们要指定的磁道是哪一个,也就是王道这句话:

 如果想读写一个磁盘大致的操作分为如下几步:

 我们有这些知识就足够我们理解磁盘读写了。

扇区也就是我们操作磁盘的最小单位,一次最少也要对一个扇区读写,最多能达到256个扇区。

想要操作硬盘读写,我们需要对端口进行输入输出,也就是IO端口形式。

这个端口不同于网络协议中的端口,它是外部设备内部的寄存器,是用来提供一个通道给我们操控这个外部设备的。也称之为端口。因此分配给硬盘的寄存器是需要我们查阅的。

硬盘读写是有两种形式:

-CHS模式  也就是/柱面/磁头/磁道  也就是用坐标系来标识一个磁盘块,这个模式比较复杂,一般不用。

在Linux中,硬件外部设备都被抽象成了文件,硬盘也不例外,每个扇区都可以任务是一个文件,因此产生出了另外一种模式 -LBA模式 /逻辑块地址/ 只需要知道想操作哪一块扇区就完事了很方便

LBA模式也有2种,一种是用28位比特来表示一个扇区,一个是48位比特来表示一个扇区,分别成为LBA28,LBA48,我们只用LBA28模式就好了。

下面我们介绍下硬盘控制器的端口:

 一个Primary通道上是可以挂2个硬盘,一个主盘,一个从盘,但是做实验时我们只有一个主盘因此暂时不管从盘的问题。磁盘是很复杂的东西,我们写操作系统小麻雀的时候,用以上的端口完全足够了。下面介绍下这些端口的作用:

0x1F0 是一个16位的端口,用来读写数据的

0x1F1 检测前一个指令的错误(一般不用,出错的时候用)

0x1F2 用于读写扇区的数量

0x1F3 起始扇区的0-7位

0x1F4 起始扇区的8-15位

0x1F5 起始扇区的16-23位

0x1F6 第四位是存的剩下4位(28比特的最后四位),图示如下:

 0x1F7 此端口是用来存储硬盘执行的命令只介绍三个我们用的:

0xEC 硬盘识别

0x20 读扇区

0x30 写扇区

基本上就介绍完了。下面我们开始上代码(我会给出相应详细的注释):

;第一步 ;初始化一些寄存器(数据) mov edi,0x1000 ;读到内存的哪个位置 mov ecx,2 ;起始扇区 mov bl,4 ;扇区数量 call read_disk ;调用读扇区这个函数
;第二步实现read_disk函数 read_disk: mov dx,0x1f2 ;读写扇区数量,参考前面讲的寄存器 mov al,bl ;读取扇区数量放入al寄存器 out dx,al ;往端口写 inc dx ;0x1f3 mov al,cl ;起始扇区的低八位 out dx,al inc dx ;0x1f4 shr ecx,8 ;讲中八位移到低8位的操作 右移操作符 mov al,cl ;起始扇区的中八位 out dx,al inc dx ;0x1f5 shr ecx,8 ;将高八位移到低8位的操作 mov al,cl ;起始扇区的高八位 out dx,al inc dx ;0x1f6 shr ecx,8 and cl,0b1111 ;将高4位置为0 mov al,0b1110_0000 ;0x1f6的device寄存器 参考上图 or al,cl ;合二为一 inc dx ;0x1f7 mov al,0x20 ;读操作 out dx,al xor ecx,ecx ;ecx清0 mov cl,bl ;得到读写扇区的数量 循环变量作用于loop .read: push cx call .waits ;等待数据 call .reads; 读取扇区 pop cx loop .read ret .waits: mov dx,0x1f7 ;使用status寄存器 检索硬盘状态 .check: in al,dx ;往端口读 jmp $+2 ;空指令 jmp $+2 jmp $+2 and al,0b1000_1000 ;将第4位和第八位清0 cmp al,0b0000_1000 ;判断DRQ是否准备好数据 cmp指令影响ZF位 jnz .check ;如果不等于循环检查 直到DRQ为1为止 ret .reads: mov dx,0x1f0 ;读硬盘操作 mov cx,256 ;一次读取一个字 循环变量 .readw: in ax,dx jmp $+2 ;空指令 jmp $+2 jmp $+2 mov [edi],ax ;将读取的数据放到0x1000内存位置 add edi,2 ;每次加2 loop .readw ret

效果图可以参考内核加载器那篇文章,用的就是此套函数将加载器加载到0x1000的内存位置,写硬盘逻辑刚好是相反的,目前还没用到,就没有实现此功能。

今天的文章 手写操作系统--读写硬盘操作分享到此就结束了,感谢您的阅读。
编程小号
上一篇 2025-01-01 21:33
下一篇 2025-01-01 21:30

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/98470.html