• 自己动手从零写桌面操作系统GrapeOS系列教程——21.汇编语言写硬盘实战


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


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

    在内存中准备一段有特征的512字节数据,地址为0x7e00~0x7fff,其特征是前3个字节依次为456,最后3个字节依次为654。然后将该段内存数据写入到硬盘的第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

  • 相关阅读:
    Redis数据类型(list\set\zset)
    为什么不生效这个up-cell-group里怎么改样式cell也改不了为什么
    CSP-J-2004-花生采摘
    496. 下一个更大元素 I
    django项目实战基于Python实现的飞机票销售系统
    科技赋能无人零售
    计算机毕业设计springboot+vue基本安卓/微信小程序的家装公司管理系统小程序uniapp
    动态内存与智能指针
    七夕趣味玩法,用 MMGeneration 生成心仪的 TA
    C++的文件操作
  • 原文地址:https://www.cnblogs.com/chengyujia/p/17242788.html