操作系统学习初步-软驱介绍及BIOS调用示例

操作系统学习初步-软驱介绍及BIOS调用示例

软驱

1.4M的软盘两面均可记录信息,称为面0和面1。两面各有一个磁头可以记录和读取信息,两个磁头分别称为磁头0和磁头1。每面有80个同心圆磁道,从外向里称为磁道0…磁道79 。每个片面均分成18个扇面。扇面把磁道分成了更小的单元,每一小块称为一个扇区,一个扇区是512字节,面0磁道0有18个扇区,序号1…18,面1磁道0为19…36,然后磁道1开始排序。全盘容量为 5121880*2=1474560字节。

引用的图片

磁盘中断:INT 0x13
AH 0x0重置;0x2读盘;0x3写盘;0x4校验;0x5寻道
AL 读取对象占的扇区数(只能同时处理连续的扇区,意思是不能跨越磁道、磁头)
ES:BX 读出的数据存储在什么地方?
CH 磁道号(柱面号)
CL 从第几个扇区开始读
DH 磁头号(0或1)
DL 驱动器号,一般情形软驱是A盘,为0
FLAGS.CF 0,正确,AH == 0;1,错误,AH == 错误码

以下是一段读取软驱内容到指定物理内存的汇编代码。
该程序只能读取一张软盘。
程序参数:驱动器号,一般为0;需要读取的位置(指定内容在磁盘中的偏移,不是哪个扇区);读取内容的字节数;目标物理内存。
本段程序为GNU AS,AT&T语法格式。需要注意的是标识符大小写敏感的。

.macro FloppyRead  driver,ReadPosition,ReadSize,Dest
 
     JMP _FloppyReadEntry
     
_FLOPPY_VARS:
     # 变量
     head      :.byte  0        #磁头号
     cylinder :.byte  0        #柱面号
     sector    :.byte  1        #扇区号
     once      :.byte  1        #一次连续读取的扇区数
     sectors  :.word 1        #需要读取的扇区数目
     PhyAddr:.long   \Dest
     Okay     :.ascii "Read Success!"
 
_FloppyReadEntry:
     # 求读取位置所在柱面扇区磁头信息
     movl $\ReadPosition,%eax                      #读取位置/512获得扇区数目
     movl $512,%ecx
     xorl   %edx,%edx      # 真的要小心,这条指令不能少,不然结果不确定。EDX=0
     divl   %ecx                         
     addl  $1,%eax  #余数为0时,读取位置还是要定位到下一扇区,譬如512,第一扇区为0..511,512 in sector2
     
     GET_HEAD:
     movl  $36,%ecx                                        # 正反2面共36个簇
     xorl   %edx,%edx                                    # edx清0
     divl    %ecx
     movb %al,cylinder
     cmp   $18,%edx                     # 余数为扇区数>18,磁头为1,扇区为(余数-18)
     JNA   GET_SECTOR
     subl $18,%edx
     movb $1,head
     GET_SECTOR:
     movb %dl,sector
 
     # 求取需要读取的扇区数
     movl $\ReadSize,%eax
     xorl %edx,%edx
     movl $512,%ecx
     divl   %ecx
     addl $1,%eax
     movw %ax,sectors
 
     # 把 SI作为计数器,统计已经读取的扇区
     movw $0,%si
     
_Retry:
     # 求一次读入的扇区数
     movb $19,%al
     subb  sector,%al
     movb %al,once
 
     # 把将要读取的扇区数加已经读完的扇区数相加和总数比较
     movw %si,%bx
     addb once,%bl
     cmpw  sectors,%bx
     # 如果%bx<=sectors,直接进行读取
     jbe  _CallBios
     # 如果超过了,把ONCE减去超过的数量,得到需要读取的数量
     movw once ,%ax
     subw  sectors,%bx # 得到多余的数量 21-4=17
     subw  %bx,%ax
     movb  %al,once
 
_CallBios:
     movw $0,%ax
     movw %ax,%es
     movw PhyAddr,%BX
     movb head,%DH   #磁头
     movb $\driver,%DL    #驱动器
     movb cylinder,%CH    #柱面
     movb sector,%CL   #扇区
     movb $0x02,%AH
     movb once,%AL   #读入扇区数量
     INT    0x13
     nop
     jc  _CallBios
 
_Next:
     add once,%si
     cmp sectors,%si
     #如果大于等于需要读取的扇区数,跳转到结束
     jAE _READ_FINISH
_GO_ON:
     # 将写入地址修改
     movl $512,%eax
     mull  once
     addl PhyAddr,%eax
     movl %eax,PhyAddr
 
     # 起始扇区重置1
     #movb $1,sector
 
     # 更换磁头
     movb head,%al
     not   %al
     and $1,%al
     movb %al,head
     #如果磁头由1->0,磁道加1
     cmp $0,%al
     jne  _Retry
     add $1,cylinder  #如果cylinder>80,则需要更换磁盘
     jmp _Retry
     
_READ_FINISH:
     nop
 
     movw $Okay,%bp            /* ES:BP=字符串地址  */
     movw $13,%cx             /*字符串长度 */
     movw $0x1301,%ax     /*AH=0x13,AL=0x01  */
     movw $0xC,%bx     /*Page=0(BH=0)Black ground and red font(BL=0x0C,highlight)*/
     movb $15,%dh              /* Line  */
     movb $0,%dl             /* col */
     int  0x10
 
nop
.endm

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/adacore/article/details/82861752