第2章 从软驱中读取1个扇区到内存

决定存放程序的内存地址

在MBR中,我们需要读取软驱上的程序到内存中。在什么内存上才存放这些程序呢?

  1. 不能复制到1M以上的内存,因为A20地址线还没打开,没进入保护模式,不能寻址到1M以上的内存。

  2. 不能复制到0x0上的内存,因为BIOS的中断向量在0x0上,而我们又需要int 13h读取磁盘。

在PC机中探测系统物理内存(E820内存探测法),可知我们可用的内存有

起始地址 结束地址 长度
9F7FF 638KB
100000 3FEEFFFF 1021MB

BIOS把512字节的MBR读取到0x7c00,我把软驱上的程序复制到内存0x7e00上,大约能复制607KB的程序。

  • 软驱上的第0扇区(逻辑扇区号)(MBR)已经复制到0x7c00 上。
  • 软驱上的第1扇区~1200扇区(逻辑扇区号)复制到0x7e00上。

BIOS中读取软驱的中断命令

BIOS磁盘存取功能 《IBM-PC汇编语言程序设计 第2版》p479 《IBM-PC汇编语言程序设计 第5版》p330

INT 13H

输入参数:

AH 要执行的操作:读、写、检验、格式化。AH = 2表示读磁盘扇区

AL 扇区数

CH 柱面/磁道(0为起始号)

CL 起始扇区号(1为起始号,物理扇区号跟逻辑扇区号不一样)

DH 磁头号,软盘只有两个磁盘,0或1

DL 驱动器号

驱动器 软驱A 软驱B 硬盘1 硬盘2

驱动器号 0H 1H 80H 81H

EX:BX 数据缓冲区地址

读取软驱的函数

在我的虚拟机中,软驱A是1.44MB格式的软驱,一共1440KB字节,共2880个扇区。地址表示为 T/H/S

T 磁道号 track、cylinder 一共有80个磁道

H 磁头号 head 一共有2个磁头

S 扇区号 sector 每个磁道、每个磁头上有18个扇区

我把读取扇区的代码变成一个汇编函数rd_sect,要使用汇编指令call,必须先设置栈地址(设置esp),否则会出错。栈地址(esp)暂时设置为0x7c00。

下面是rd_sect函数

#函数名:rd_sect
#功能:读取软驱A上的1个扇区
#参数1:  ES:BX    读取数据存放的目的地址
#参数2:  SI        指定逻辑扇区号    

rd_sect:
    pushw   %ax
    pushw   %dx
    pushw   %cx
    pushw   %bx

    movw    %si,    %ax
    movb    $18,    %bl
    divb    %bl            # al <-- (ax)/(bl) 的商
                           # ah <-- (ax)/(bl)的余数
    incb    %ah            # 因为软驱的物理起始扇区号从1开始,而逻辑扇区号从0开始,所以要增1
    movb    %ah,    %cl        # 起始扇区号,(int 13H ah=02h 中断的参数)
    xorb    %ah,    %ah
    movb    $2,        %bl
    divb    %bl
    movb    %ah,    %dh        # 磁头号,(int 13H ah=02h 中断的参数)
    movb    %al,    %ch        # 磁道号,(int 13H ah=02h 中断的参数)    
    popw    %bx

re_rd: 
    movb    $0x2,   %ah        # 读磁盘中断
    movb    $1,        %al     # 读取1个扇区
    movb    $0x0,   %dl        # 读取软驱A
    int $0x13
    jc re_rd

    popw    %cx
    popw    %dx
    popw    %ax

    ret

Leave a Reply

Your email address will not be published. Required fields are marked *