栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Gos —— 掌控硬盘

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Gos —— 掌控硬盘

文章目录
  • 硬盘控制器端口
  • 常用硬盘操作方法
  • 操纵硬盘
  • 参考文献

写在前面:自制操作系统Gos 第二章第四篇:主要内容是如何操纵外设,如何操纵硬盘

关于硬盘的原理我在Linux —— 文件系统及相关操作命令其实是已经简单讲了一下了,这里就不再赘述了。

在上一篇中我们讲到了CPU和显示器交互的接口其实就是显存。那CPU和硬盘打交道也是同样的道理:硬盘控制器

注:
硬盘控制器是专门驱动外部设备的模块电路,CPU只同它们交互,由它们将信息传递给外部设备

硬盘控制器端口

让硬盘工作,我们需要通过读写硬盘控制器的端口。下面列出了部分的端口,也是我们开发Gos需要用到的端口:

Primary通道端口Secondary通道端口读操作时用途写操作时用途

首先是命令寄存器:Command register

0x1F00x170datadata
0x1F10x171errorfeatures
0x1F20x172sector countsector count
0x1F30x173LBA lowLBA low
0x1F40x174LBA midLBA mid
0x1F50x175LBA highLBA high
0x1F60x176devicedevice
0x1F70x177statuscommand

除此之外是控制寄存器:Control register

0x3F60x376alternate statusdevice control

注:
电脑主板上有两个硬盘串行接口(STAT),每个接口可以插一块硬盘。其中第一个STAT被称之为Primary通道,其连接主盘master;第二个STAT称之为Secondary通道,其连接从盘slave
但是这里要注意一个问题:端口是按照通道给出的
也就是说:一个通道的主、从两块硬盘都用这些端口号。想要操作某通道所对应的某块硬盘,直接单独指定device寄存器的第四位(硬盘标志位)为1就可以了。

其中命令寄存器Command register 用于向硬盘驱动器写入命令或者从硬盘控制器获得硬盘状态
控制寄存器Control register 用于控制硬盘的工作状态。

下面我们具体讲一下这些寄存器的作用:

  • data:负责管理数据。在读硬盘时,硬盘准备好的数据后,硬盘控制器就将其放在内存的缓冲区中,不断读此寄存器便是读出缓冲区中的全部数据;写硬盘时,我们要把数据源源不断地输送到此端口,之后便存入缓冲区,之后再写入相应的扇区。
  • error:当0x171或者0x1F1读硬盘失败的时候才有用,里面会记录着失败的信息。其中尚未读取的扇区在sector count寄存器中。在写硬盘的时候,其则被称之为feature寄存器。
  • sector count:用来指定待读取或待写入的扇区数。硬盘每完成一个扇区,就会将此寄存器的值-1.如果失败,那么其就存储着尚未读取的扇区数
  • LBA:逻辑块地址(Logical block address),一共有两种:第一种时LBA28,用28为来描述一个扇区的地址。可以这次228*512=128GB大小的空间,Gos用LBA28就可以了;第二种是LBA48,顾名思义,其可以支持128PB的空间
  • LBA low:存储28位地址的0~7位
  • LBA middle:存储28位地址的8~15位
  • LBA high:存储28位地址和的16~23位
  • device:0~3位用来存储28位地址的剩下4位,第4位表示是主盘还是从盘,0表示主盘,1代表从盘。第六位表示是否开启LBA,1代表启用。第五位和第七位表示MBS位。
  • status:用来给出给出硬盘的状态信息。第0位表示error位;第三位表示data request,如果此位为1,表示数据准备好了;第6位表示drdy,表示硬盘就绪;第七位是BSY,表示硬盘是否繁忙。

注:
在Gos中,我们主要使用三个命令:
identify:0xEC,即硬盘识别
read sector:0x20,即读扇区
write sector:0x30,即写扇区

下面是device status两个寄存器的示意图:

常用硬盘操作方法

硬盘的指令很多,用法也有很多。有的直接往command寄存器中写,有的则是在feature寄存器中写入参数,可谓是多种多样。但是不管是哪种写法,command寄存器都是最后写。因为其一旦一开始就写,那么整个硬盘就轰隆隆的启动了。

而我们的操作顺序如下:

  1. 先选择通道,往该通道的sector count寄存器 写入待操作的扇区数
  2. 往该通道上的三个LBA寄存器写入扇区起始地址的低24位
  3. 往device寄存器写入剩下四位,之后置第6位为1;设置第4位,选择要操作的硬盘
  4. 往该通道的command寄存器写入操作命令
  5. 读取该通道上的status寄存器,判断硬盘工作是否完成
  6. 如果是读硬盘,进入下一个步骤。否则,完成。
  7. 将硬盘数据读出

注:
我们使用的读取方式是以下两种结合:
无条件传送方式:数据随时随地准备好,直接拿来吧你
查询传送方式:取之前先查一查数据准备好了没有,然后再拿来吧你

操纵硬盘

上硬菜咯!

# 文件 mbr.S 中的内容
; MBR引导程序,从BIOS接过权力,交接给loader内核加载器
;*************************
%include "boot.inc"
SECTION MBR vstart=0x7c00
    ; 初始化显卡控制信息,本质是往显存写入数据
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00
    mov ax,0xb800
    mov gs,ax
;*************************
; 清屏利用0x06号功能,上卷全部行,进行清屏
; int 0x10  功能号:0x60    功能描述:上卷窗口
; 输入:
; AH 功能号: 0x06
; AL = 上卷的行数(0代表全部)
; BH = 上卷的行属性
; (CL,CH) = 窗口左上角(x,y) 的位置
; (DL,DH) = 窗口右下角(x,y)的位置
; 无返回值!
    mov ax,0600h
    mov bx,0700h
    mov cx,0        ;左上角(0,0)
    mov dx,0x184f   ;右下角(80,25)
                    ;VAG文本模式中,一行只能容纳80个字符,总共25行
                    ;下标从0开始,所以0x18=24,0x4f=79
    int 10h
;*************************
    ;输出字符串:hello,Gos!
    mov byte [gs:0x00],'h'
    mov byte [gs:0x01],0x0F     ;黑底亮白不闪烁

    mov byte [gs:0x02],'e'
    mov byte [gs:0x03],0x0F

    mov byte [gs:0x04],'l'
    mov byte [gs:0x05],0x0F

    mov byte [gs:0x06],'l'
    mov byte [gs:0x07],0x0F

    mov byte [gs:0x08],'o'
    mov byte [gs:0x09],0x0F

    mov byte [gs:0x0a],','
    mov byte [gs:0x0b],0x0F

    mov byte [gs:0x0c],'G'
    mov byte [gs:0x0d],0x0F

    mov byte [gs:0x0e],'o'
    mov byte [gs:0x0f],0x0F

    mov byte [gs:0x10],'s'
    mov byte [gs:0x11],0x0F

    mov byte [gs:0x12],'!'
    mov byte [gs:0x13],0x0F
;*************************
;初始化磁盘信息
    mov eax,LOADER_START_SECTOR     ;起始扇区LBA地址
    mov bx,LOADER_base_ADDR         ;写入的地址
    mov cx,1                        ;待读入的扇区数
    call read_disk_m_16             ;调用读取程序起始部分的函数

    jmp LOADER_base_ADDR
;*************************
;读取磁盘的n个扇区
read_disk_m_16:
                                    ;eax=LBA扇区号
                                    ;bx=将数据写入的内存地址
                                    ;cx=读入的扇区数
    mov esi,eax                     ;备份eax
    mov di,cx                       ;备份cx
;读写硬盘
                                    ;1.设置要读取的扇区数量
    mov dx,0x1f2
    mov al,cl
    out dx,al                       ;读取的扇区数
    mov eax,esi                     ;恢复eax

                                    ;2.将LBA地址存入0x1f3~0x1f6
                                    ;LBA地址7~0位写入端口0x1f3
    mov dx,0x1f3
    out dx,al

                                    ;LBA地址15~8位写入端口0x1f4
    mov cl,8
    shr eax,cl
    mov dx,0x1f4
    out dx,al

                                    ;LBA地址23~16位写入端口0x1f5
    shr eax,cl
    mov dx,0x1f5
    out dx,al

    shr eax,cl
    and al,0x0f                     ;LBA第24~27位
    or al,0xe0                      ;设置7~4位为1110,表示LBA模式
    mov dx,0x1f6
    out dx,al

                                    ;3.向0x1f7端口写入读命令,0x20
    mov dx,0x1f7
    mov al,0x20
    out dx,al

                                    ;4.检测硬盘状态
.not_ready:
    nop                             ;同一端口,写时表示写入命令字,读时表示读入硬盘状态
    in al,dx                        ;
    and al,0x88                     ;第3位为1表示硬盘控制器已经准备号数据传输了
                                    ;第7位为1表示硬盘忙
    cmp al,0x08                     
    jnz .not_ready                  ;若未准备号,继续等

                                    ;5.从0x1f0端口读数据
    mov ax,di
    mov dx,256                      ;一个扇区512字节,1字=2字节,所以时256
    mul dx
    mov cx,ax
    mov dx,0x1f0

.go_on_read:
    in ax,dx
    mov [bx],ax
    add bx,2
    loop .go_on_read
    ret

times 510-($-$$) db 0
db 0x55,0xaa

可以看到,我们在这里包含了一个头文件boot.inc,这个文件中的内容很简单,只是定义了两个常量:

# boot.inc 文件中的内容
LOADER_base_ADDR equ 0x900
LOADER_START_SECTOR equ 0x2     ;第二扇区

之后,我们开始编译这个文件:

# -I 指定头文件搜索路径
# boot.inc 文件在同级目录include下
nasm -I ../include/ mbr.bin mbr.S

编译成功之后,会在目录中生成mbr.bin文件:

之后,我们使用dd工具将其写入我们之前创建好的磁盘hd60.img中:

# 记得换成自己的路径
sudo dd if=./mbr.bin of=/bochs/bo_tmp/bin/hd60M.img bs=512 count=1 conv=notrunc

然后,我们转到bochs的bin目录下,使用以下命令开启bochs:

sudo ./bochs -f boch.conf


进入到如下的界面了,默认选项是6,我们直接回车就好了:

之后,在bochs模拟的机器上便会打印出:hello Gos!(虽然这个和操纵硬盘没有关系,硬盘操纵是为了我们之后进入保护模式做铺垫用的)

参考文献
[1] 操作系统真相还原		3.6 让MBR使用硬盘
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/297927.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号