读取磁盘:CHS方式

读取磁盘:CHS方式

BIOS读取磁盘

读取磁盘也是调用BIOS:

中断命令: INT 13H

读取扇区的入口参数为

AH = 02H 功能参数,读取扇区

AL = 扇区数

CH = 柱面

CL = 扇区

DH = 磁头

DL = 驱动器号,00H~7FH:软盘驱动器号;80H~0FFH:硬盘驱动器号

ES:BX = 缓冲区的地址

出口参数

扫描二维码关注公众号,回复: 4781673 查看本文章

CF = 0: 操作成功,AH = 00H,AL = 传输的扇区数

否则,AH = 状态代码

定义磁盘读取函数

1. 读取一个扇区

; ------------------------------------------------------------------------
; 读取一个扇区函数:ReadDisk0
; ------------------------------------------------------------------------
; 参数:ES:BX 缓冲区地址,CH柱面,DH磁头,CL扇区
; ------------------------------------------------------------------------
ReadDisk0:
    MOV SI,0                ;初始化读取失败次数,用于循环计数
    
    ;为了防止读取错误,循环读取5次
    ;调用BIOS读取一个扇区
    ReadFiveLoop:
            MOV AH,0x02             ;BIOS中断参数:读扇区
            MOV AL,1                ;BIOS中断参数:读取扇区数
            MOV BX,0
            MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
            INT 0x13                ;调用BIOS中断操作磁盘:读取扇区
            JNC ReadEnd             ;条件跳转,操作成功进位标志=0。则跳转执行ReadNextSector
    
            inc si              ;循环读取次数递增+1
            CMP SI,5                ;判断是否已经读取超过5次
            JAE LoadError           ;上面cmp判断(>=)结果为true则跳转到DisplayError
    
            MOV AH,0x00             ;BIOS中断参数:磁盘系统复位
            MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
            INT 0x13                ;调用BIOS中断操作磁盘:磁盘系统复位
            JMP ReadFiveLoop
    ;扇区读取完成
    ReadEnd:
            RET

2. 读取多个扇区

读取时要根据 扇区<磁头<柱面 的方式来读取。继续添加代码,读取18个扇区:(即完整的读取了一个柱面)。

代码如下:

3. 读取多个柱面

继续添加代码,读取10个柱面。

然后调用函数

    ;读取磁盘初始化
        MOV AX,DISC_ADDR/0x10   ;设置磁盘读取的缓冲区基本地址为ES=0x820。[ES:BX]=ES*0x10+BX
        MOV ES,AX               ;BIOS中断参数:ES:BX=缓冲区的地址

        MOV CH,0                ;设置柱面为0
        MOV DH,0                ;设置磁头为0
        MOV CL,2                ;设置扇区为2

    ReadSectorLoop:
        CALL ReadDisk0;         ;读取一个扇区

转换LBA到CHS方式读取

; ==============================================
; 读取磁盘:Func_readCHS2LBA
; 参数:
; ebx 扇区逻辑号
; cx 读入的扇区数,8位
; es 读取到内存单元的地址
; ==============================================
.reset
    MOV AH,0x00             ;BIOS中断参数:磁盘系统复位
    MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
    INT 0x13                ;调用BIOS中断操作磁盘:磁盘系统复位
    ret
    
.readdisk
                ;初始化读取失败次数,用于循环计数
    push cx
    MOV cx,5    
    
    ;为了防止读取错误,循环读取5次
    ;调用BIOS读取一个扇区
    ReadFiveLoop:
            MOV AH,0x02             ;BIOS中断参数:读扇区
            MOV AL,1                ;BIOS中断参数:读取扇区数
            MOV BX,0
            MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
            INT 0x13                ;调用BIOS中断操作磁盘:读取扇区
            JNC .readok             ;条件跳转,操作成功进位标志=0。则跳转执行ReadNextSector
    
            inc si              ;循环读取次数递增+1
            CMP SI,5                ;判断是否已经读取超过5次
            JAE .readfail           ;上面cmp判断(>=)结果为true则跳转到DisplayError
    
            call .reset
            loop ReadFiveLoop
            
    ;准备下一个扇区
    .readok:
            
            MOV AX,ES
            ADD AX,0x0020           
            MOV EX,AX               ;内存单元基址后移0x20。[EX+0x20:]
            ADD CL,1                ;读取扇区数递增+1
            CMP CL,18               ;判断是否读取到18扇区
            JBE readdisk        ;上面cmp判断(<=)结果为true则跳转到DisplayError 
            
     .readxx       
     ;读取另一面磁头。循环读取柱面
        MOV CL,1                ;设置柱面为0
        ADD DH,1                ;设置磁头递增+1:读取下一个磁头
        CMP DH,2                ;判断磁头是否读取完毕
        JB ReadSectorLoop       ;上面cmp判断(<)结果为true则跳转到DisplayError

        MOV DH,0                ;设置磁头为0
        ADD CH,1                ;设置柱面递增+1;读取下一柱面
        CMP CH,10               ;判断是否已经读取10个柱面
        JB  readdisk        ;上面cmp判断(<)结果为true则跳转到DisplayError       

完整代码

最后,完整的boot.asm文件代码如下:

    ;RATSBOOT
    ;TAB=4
    
    ;定义常量
    DISC_ADDR       EQU 0x8000      ;磁盘第一个扇区开始,加载到内存缓冲的地址
    SECTOR_NUM      EQU 18      ;读取扇区数
    CYLINDER_NUM    EQU 10          ;读取柱面数
    
            ORG 0x7c00  ;指明程序的偏移的基地址
    
    ;以下这段是标准FAT32   格式软盘专用的代码
    
            JMP     Entry
    
            DB      0x90                ;nop,0x02
            DB      "RATSBOOT"          ;(8字节)启动区的名称可以是任意的字符串
            DW      512                 ;每个扇区(sector)的大小(必须为512 字节)
            DB      8                   ;簇(cluster )的大小(每个簇为8个扇区)
            DW      584                 ;保留扇区数,包括启动扇区
            DB      2                   ;FAT的个数(必须为2)
            DW      0                   ;最大根目录条目个数
            DW      0                   ;总扇区数(如果是0,就使用偏移0x20处的4字节值)
            DB      0x00f8              ;磁盘介质描述
            DW      0                   ;(FAT16)每个文件分配表的扇区
            DW      63                  ;每个磁道扇区数
            dw      255                 ;磁头数
            dd      63                  ;隐藏扇区
            dd      3902913             ;磁盘大小,总共扇区数(如果超过65535,参见偏移0x13)
            dd      3804                ;每个文件分配表的扇区,3804个扇区
    
            dw      0                   ;Flagss
            dw      0                   ;版本号
            dd      2                   ;根目录启始簇
    
            dw      1                   ;FSInfo扇区
            dw      6                   ;启动扇区备份
            times 12 db 0               ;保留未使用
    
            DW      0                   ;操作系统自引导代码
            db      0x80                ;BIOS设备代号
            db      0                   ;未使用
            db      0x29                ;标记
            DD      0xffffffff          ;序列号
            DB      "HELLO-OS   "       ;(11字节)磁盘名称,卷标。字符串长度固定
            DB      "FAT32   "          ;(8字节)FAT文件系统类型。 0x52
    
            times 12 db 0
    
    ;程序核心内容
    Entry:
            MOV AX,0                ;初始化寄存器
            MOV SS,AX
            MOV SP,0x7c00
            MOV DS,AX
    
            MOV DI,StartMessage ;将Message1段的地址放入SI
            CALL DisplayStr     ;调用函数
            MOV DI,BootMessage  ;将Message1段的地址放入SI
            ADD DH,1
            CALL DisplayStr     ;调用函数


    ;读取磁盘初始化
            MOV AX,DISC_ADDR/0x10   ;设置磁盘读取的缓冲区基本地址为ES=0x820。[ES:BX]=ES*0x10+BX
            MOV ES,AX               ;BIOS中断参数:ES:BX=缓冲区的地址
    
            MOV CH,0                ;设置柱面为0
            MOV DH,0                ;设置磁头为0
            MOV CL,1                ;设置扇区为2
    
    ReadSectorLoop:
            CALL ReadDisk0;         ;读取一个扇区
    
    ;准备下一个扇区
    ReadNextSector:
            MOV AX,ES
            ADD AX,0x0020           
            MOV ES,AX               ;内存单元基址后移0x20(512字节)。[ES+0x20:]
            ADD CL,1                ;读取扇区数递增+1
            CMP CL,SECTOR_NUM       ;判断是否读取到18扇区
            JBE ReadSectorLoop      ;上面cmp判断(<=)结果为true则跳转到DisplayError
    
    ;读取另一面磁头。循环读取柱面
            MOV CL,1                ;设置柱面为0
            ADD DH,1                ;设置磁头递增+1:读取下一个磁头
            CMP DH,2                ;判断磁头是否读取完毕
            JB  ReadSectorLoop      ;上面cmp判断(<)结果为true则跳转到DisplayError
    
            MOV DH,0                ;设置磁头为0
            ADD CH,1                ;设置柱面递增+1;读取下一柱面
            CMP CH,CYLINDER_NUM     ;判断是否已经读取10个柱面
            JB  ReadSectorLoop      ;上面cmp判断(<)结果为true则跳转到DisplayError
    
    ;LoadSuccess:
        MOV DI,Succmsg
        MOV DH,3
        CALL DisplayStr            ;此处必须注释掉,不能调用INT。原因不明。
    
    ;加载执行boot文件:
            ;MOV    [0x0ff0],CH         ;将总共读取的柱面数存储在内存单元中
            ;JMP 0xc200             ;跳转执行在内存单元0xc200的代码


    GoLoader:
            MOV [0x0ff0],CH         ;将总共读取的柱面数存储在内存单元中
            JMP 0xc200              ;跳转执行在内存单元0xc200的代码:DISC_ADDR-0x200+0x4200
                                    ;(启动扇区开始地址0x8000+软盘代码:boot文件开始0x4200)
    
    LoadError:
            MOV DI,Errormsg
            MOV DH,3
            CALL DisplayStr ;如果加载失败显示加载错误
    
    ;程序挂起
    Fin:
        HLT                     ;让CPU挂起,等待指令。
        JMP Fin


    ; ------------------------------------------------------------------------
    ; 读取一个扇区函数:ReadDisk0
    ; ------------------------------------------------------------------------
    ; 参数:ES:BS 缓冲区地址,CH柱面,DH磁头,CL扇区,AL扇区数=1,DL驱动器=0x
    ; ------------------------------------------------------------------------
    ReadDisk0:
    
            MOV SI,0                ;初始化读取失败次数,用于循环计数
    
    ;为了防止读取错误,循环读取5次
    ;调用BIOS读取一个扇区
    ReadFiveLoop:
    
            MOV AH,0x02             ;BIOS中断参数:读扇区
            MOV AL,1                ;BIOS中断参数:读取扇区数
            MOV BX,0
            MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
            INT 0x13                ;调用BIOS中断操作磁盘:读取扇区
            JNC ReadEnd             ;条件跳转,操作成功进位标志=0。则跳转执行ReadNextSector
    
            ADD SI,1                ;循环读取次数递增+1
            CMP SI,5                ;判断是否已经读取超过5次
            JAE LoadError           ;上面cmp判断(>=)结果为true则跳转到DisplayError
    
            MOV AH,0x00             ;BIOS中断参数:磁盘系统复位
            MOV DL,0x00             ;BIOS中断参数:设置读取驱动器为软盘
            INT 0x13                ;调用BIOS中断操作磁盘:磁盘系统复位
            JMP ReadFiveLoop
    ;扇区读取完成
    ReadEnd:
            RET
    
    ; ------------------------------------------------------------------------
    ; 显示字符串函数:DisplayStr
    ; ------------------------------------------------------------------------
    ; 参数:SI:字符串开始地址, DH为第N行
    ; ------------------------------------------------------------------------
    DisplayStr:
        MOV CX,0            ;BIOS中断参数:显示字符串长度
        MOV BX,DI
    .1:;获取字符串长度
        MOV AL,[BX]         ;读取1个字节。这里必须为AL
        ADD BX,1            ;读取下个字节
        CMP AL,0            ;是否以0结束
        JE .2
        ADD CX,1            ;计数器
        JMP .1
    .2:;显示字符串
        MOV BX,DI
        MOV BP,BX
        MOV AX,DS
        MOV ES,AX               ;BIOS中断参数:计算[ES:BP]为显示字符串开始地址
    
        MOV AH,0x13             ;BIOS中断参数:显示文字串
        MOV AL,0x01             ;BIOS中断参数:文本输出方式(40×25 16色 文本)
        MOV BH,0x0              ;BIOS中断参数:指定分页为0
        MOV BL,0x0c             ;BIOS中断参数:指定白色字体07          
        MOV DL,0                ;列号为0
        INT 0x10                ;调用BIOS中断操作显卡。输出字符
        RET
    
    ;数据初始化
    StartMessage:   DB "hello,rats os start",0
    BootMessage:    DB "booting............",0
    Errormsg:       DB "load error  ",0
    Succmsg:        DB "load success",0
    
    FillSector:
        RESB    510-($-$$)      ;处理当前行$至结束(1FE)的填充
        DB      0x55, 0xaa

运行结果如下:

上面代码的作用

首先boot.asm会被加载到内存并且执行.后面开始读取磁盘的10个柱面(10*18个扇区).
读取的扇区数据复制到 内存 0x8000 开始的位置.
然后打印输出"hello,rats os start"

猜你喜欢

转载自www.cnblogs.com/mlzrq/p/10223053.html
今日推荐