硬盘和显卡的访问与控制(二)——《x86汇编语言:从实模式到保护模式》读书笔记02 (4)

要理解这段,先看下面的示意图(参照原书图8-11画的)
inc dx ;0x1f6
mov al,0xe0 ;LBA28模式,主盘
or al,ah ;LBA地址27~24
out dx,al

端口0x1F6各位的含义

mov al,0xe0 表示选择LBA模式,选择主硬盘
注意,在调用这个过程的时候,DI:SI=起始逻辑扇区号,DI的低四位是有效的,高四位应该为0,其实这里我觉得应该加一句,
mov al,0xe0 这句后面加一句 and ah,0x0f
目的是把DI的高四位清零,万一调用者忘记清零了,这样做可以防止意外发生。

inc dx ;0x1f7 mov al,0x20 ;读命令 out dx,al

当把起始LBA扇区号设置好后,就可以发出读命令了。上面的代码表示向端口0x1F7写入0x20,请求读硬盘。
接下来等待读请求完成。端口0x1F7既是命令端口,也是状态端口。部分状态位的含义如图:

端口0x1f7

.waits: in al,dx ;读端口的值 and al,0x88 ;提取出bit3和bit7 cmp al,0x08 ;bit3==1且bit7==0说明准备好了 jnz .waits ;否则继续检查

一旦硬盘准备好了,就可以读取数据了。0x1F0是硬盘接口的数据端口,是16位的。可以连续从这个端口读取数据。
mov cx,256
in ax,dx
这两句话就表示读取了一个字的数据(16位)到AX中

mov cx,256 ;总共要读取的字数 mov dx,0x1f0 .readw: in ax,dx mov [bx],ax ;读取的数据放在数据段,偏移地址由BX指定 add bx,2 loop .readw

现在我们再回到那部分代码,就很容易理解了。

xor di,di ;di清零 (因为我们传入逻辑扇区号是100,不超过16 bits) mov si,app_lba_start ;程序在硬盘上的起始逻辑扇区号 xor bx,bx ;加载到DS:0x0000处 call read_hard_disk_0

执行到这里,内存大概如下图所示:

硬盘和显卡的访问与控制(二)——《x86汇编语言:从实模式到保护模式》读书笔记02

;以下判断整个程序有多大 mov dx,[2] ;曾经把dx写成了ds,花了二十分钟排错 mov ax,[0] mov bx,512 ;512字节每扇区 div bx cmp dx,0 jnz @1 ;未除尽,因此结果比实际扇区数少1 dec ax ;已经读了一个扇区,扇区总数减1 @1: cmp ax,0 ;考虑实际长度小于等于512个字节的情况 jz direct ;读取剩余的扇区 push ds ;以下要用到并改变DS寄存器 mov cx,ax ;循环次数(剩余扇区数) @2: mov ax,ds add ax,0x20 ;得到下一个以512字节为边界的段地址 mov ds,ax xor bx,bx ;每次读时,偏移地址始终为0x0000 inc si ;下一个逻辑扇区 call read_hard_disk_0 loop @2 ;循环读,直到读完整个功能程序 pop ds ;恢复数据段基址到用户程序头部段

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwsszg.html