读取磁盘:CHS方式

读取磁盘:CHS方式

BIOS读取磁盘

读取磁盘也是调用BIOS:

中断命令: INT 13H

读取扇区的入口参数为

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

AL = 扇区数

CH = 柱面

CL = 扇区

DH = 磁头

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

ES:BX = 缓冲区的地址

出口参数

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"

原文地址:https://www.cnblogs.com/mlzrq/p/10223053.html

时间: 2024-07-29 14:14:52

读取磁盘:CHS方式的相关文章

读取磁盘:LBA方式

LBA简介 磁盘读取发展 IO操作读取硬盘的三种方式: chs方式 :小于8G (8064MB) LBA28方式:小于137GB LBA48方式:小于144,000,000 GB LBA方式访问使用了data寄存器,LBA寄存器(总共3个),device寄存器,command寄存器来完成的. LBA28和LBA48方式: LBA28方式使用28位来描述一个扇区地址,最大支持128GB的硬磁盘容量. LBA28的寄存器 寄存器 端口 作用 data寄存器 0x1F0 已经读取或写入的数据,大小为两

通过DeviceIoControl读磁盘的方式读取独占文件内容

前言 windows操作系统中常见的一个文件存储系统是NTFS.在这个文件系统中MFT是它的核心.             图一 MFT是一个数据结构,上图是它的结构,它主要用来存放每个文件和目录在磁盘中的索引.MFT由一个个MFT项构成.每个MFT项的大小是1024Bytes.每个MFT项由固定头结构和多个属性构成.属性用来记录与文件相关的信息.每个属性又由属性头和属性体构成.属性头包含了一些该属性的重要信息,如属性类型.属性大小.是否为常驻属性等等.[1]文件内容也被NTFS看作属性.  其

【原创】Android 4.4前后版本读取图库图片方式的变化

Android 4.4前后版本读取图库图片方式的变化 本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化 Android 4.4(KitKat)以前: 访问图库(方法一): 1 /** 2 * Access the gallery to pick up an image. 3 */ 4 private void startPickPhotoActivity() { 5 Intent intent = new Intent(Intent. ACTION_

C3P0数据库连接池-方式2读取配置文件的方式

package com.itheima.c_c3p0; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0Utils { //提供连接池 private static DataSource dataSource = new ComboPool

Java读取配置文件的方式

Java读取配置文件的方式-笔记 1       取当前启动目录下的配置文件 一般来讲启动java程序的时候,在启动的目录下会有配置文件 classLoader.getResource("").getFile()  会取到java当前启动项目的目录,然后指定对应的配置文件路径即可比如conf/conf.properties //取当前启动目录的配置文件 String filePath =classLoader.getResource("").getFile()+&q

Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息。”的问题解决

现象描述: 服务器经常在午夜,自动死机,无法连接外网,查询日志报如下错误: " 无法从系统读取磁盘性能信息. 必须至少有一个物理磁盘或逻辑磁盘卷启用了 "磁盘性能计数器",这些计数器才会出现. 可以使用"硬件设备管理器"属性页来启用磁盘性能计数器. 返回的状态码是数据 DWORD 0. " 解决办法: 这是没有启用"磁盘性能计数器",可以在命令行下执行:diskperf -y 来启用! 更详细的可以执行diskperf /?

无法从系统读取磁盘性能信息

    有时候系统日志会不断出现:"无法从系统读取磁盘性能信息. 必须至少有一个物理磁盘或逻辑磁盘卷启用了 "磁盘性能计数器",这些计数器才会出现. 可以使用"硬件设备管理器"属性页来启用磁盘性能计数器. 返回的状态码是数据 DWORD 0. "而且频繁出现,一会你的日志就满了,一般都是有多块硬盘等原因引起的,解决办法可以参考以下参数: Diskperf(控制计数器的类型,这些计数器可以用系统监视器查看.) 命令参数: diskperf [-y[

Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息。

Windows Server 2003中报PerfDisk "无法从系统读取磁盘性能信息."的问题解决 2015-01-22 09:49:02 标签:Windows Server2003 PerfDisk 磁盘性能计数器 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://huangfuff.blog.51cto.com/2632203/1606861 现象描述: 服务器经常在午夜,自动死机,无法连接外网,查询日志报如下

面试题目java读取文本内容方式

面试题目java读取文本内容方式二种方式 第一种通过FileInputStream()方式读取 FileInputStream fis = new FileInputStream("a.txt"); //创建流对象 byte[] arr = new byte[4]; int len; while((len = fis.read(arr)) != -1) { System.out.print(new String(arr,0,len)); } fis.close(); 第二种通过:Fil