4 读入10个柱面

趁热打铁,我们继续学习下面的内容。C0-H0-S18扇区的下一扇区,是磁盘反面的C0-H1-S1,这次也从0xa400读入吧。按顺序读到C0-H1-S18后,接着读下一个柱面C1-H0-S1。我们保持这个势头,一直读到C9-H1-S18好了。现在我们就来看一看projects/03_day下的harib00d内容。

本次添加的部分

;读磁盘

        MOV      AX,0x0820
        MOV      ES, AX
        MOV      CH,0              ; 柱面0
        MOV      DH,0              ; 磁头0
        MOV      CL,2              ; 扇区2
readloop:
        MOV      SI,0              ; 记录失败次数的寄存器
retry:
        MOV      AH,0x02          ; AH=0x02 : 读入磁盘
        MOV      AL,1              ; 1个扇区
        MOV      BX,0
        MOV      DL,0x00          ; A驱动器
        INT      0x13              ; 调用磁盘BIOS
        JNC      next              ; 没出错时跳转到next
        ADD      SI,1              ; SI加1
        CMP      SI,5              ; 比较SI与5
        JAE      error             ; SI >= 5时,跳转到error
        MOV      AH,0x00
        MOV      DL,0x00          ; A驱动器
        INT      0x13              ; 重置驱动器
        JMP      retry

next:
        MOV      AX, ES             ; 把内存地址后移0x200
        ADD      AX,0x0020
        MOV      ES, AX             ; 因为没有ADD ES,0x020指令,所以这里稍微绕个弯
        ADD      CL,1              ; CL加1
        CMP      CL,18             ; 比较CL与18
        JBE      readloop         ; 如果CL <= 18,则跳转至readloop
        MOV      CL,1
        ADD      DH,1
        CMP      DH,2
        JB       readloop         ; 如果DH < 2,则跳转到readloop
        MOV      DH,0
        ADD      CH,1
        CMP      CH, CYLS
        JB       readloop         ; 如果CH < CYLS,则跳转到readloop

首先还是说说新出现的指令JB。这也是条件跳转指令,是“jump if below”的缩写。翻译过来就是:“如果小于的话,就跳转。”还有一个新指令,就是在程序开头使用的EQU指令。这相当于C语言的#define命令,用来声明常数。“CYLS EQU 10”意思是“CYLS = 10”。EQU是“equal”的缩写。只将它定义成常数是因为以后我们可能修改这个数字。现在我们先随意定义成10个柱面,以后再对它进行调整(CYLS代表cylinders)。

现在启动区程序已经写得差不多了。如果算上系统加载时自动装载的启动扇区,那现在我们已经能够把软盘最初的10× 2× 18× 512=184320 byte=180KB内容完整无误地装载到内存里了。如果运行“make install”,把程序安装到磁盘上,然后用它来启动电脑的话,我们会发现装载过程还是挺花时间的。这证明我们的程序运行正常。画面显示依然没什么变化,但这个程序已经用从软盘读取的数据填满了内存0x08200~0x34fff的地方。