读取磁盘:CHS方式

BIOS读取磁盘

读取磁盘也是调用BIOS:

中断命令: INT 13H

读取扇区的入口参数为

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

AL = 扇区数

CH = 柱面

CL = 扇区

DH = 磁头

DL = 驱动器号,00H7FH:软盘驱动器号;80H0FFH:硬盘驱动器号

ES:BX = 缓冲区的地址

出口参数

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

否则,AH = 状态代码

定义磁盘读取函数

1. 读取一个扇区

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

2. 读取多个扇区

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

代码如下:

3. 读取多个柱面

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

然后调用函数

  1. ;读取磁盘初始化
  2. MOV AX,DISC_ADDR/0x10 ;设置磁盘读取的缓冲区基本地址为ES=0x820。[ES:BX]=ES*0x10+BX
  3. MOV ES,AX ;BIOS中断参数:ES:BX=缓冲区的地址
  4. MOV CH,0 ;设置柱面为0
  5. MOV DH,0 ;设置磁头为0
  6. MOV CL,2 ;设置扇区为2
  7. ReadSectorLoop:
  8. CALL ReadDisk0; ;读取一个扇区

转换LBA到CHS方式读取

  1. ; ==============================================
  2. ; 读取磁盘:Func_readCHS2LBA
  3. ; 参数:
  4. ; ebx 扇区逻辑号
  5. ; cx 读入的扇区数,8
  6. ; es 读取到内存单元的地址
  7. ; ==============================================
  8. .reset
  9. MOV AH,0x00 ;BIOS中断参数:磁盘系统复位
  10. MOV DL,0x00 ;BIOS中断参数:设置读取驱动器为软盘
  11. INT 0x13 ;调用BIOS中断操作磁盘:磁盘系统复位
  12. ret
  13. .readdisk
  14. ;初始化读取失败次数,用于循环计数
  15. push cx
  16. MOV cx,5
  17. ;为了防止读取错误,循环读取5
  18. ;调用BIOS读取一个扇区
  19. ReadFiveLoop:
  20. MOV AH,0x02 ;BIOS中断参数:读扇区
  21. MOV AL,1 ;BIOS中断参数:读取扇区数
  22. MOV BX,0
  23. MOV DL,0x00 ;BIOS中断参数:设置读取驱动器为软盘
  24. INT 0x13 ;调用BIOS中断操作磁盘:读取扇区
  25. JNC .readok ;条件跳转,操作成功进位标志=0。则跳转执行ReadNextSector
  26. inc si ;循环读取次数递增+1
  27. CMP SI,5 ;判断是否已经读取超过5
  28. JAE .readfail ;上面cmp判断(>=)结果为true则跳转到DisplayError
  29. call .reset
  30. loop ReadFiveLoop
  31. ;准备下一个扇区
  32. .readok:
  33. MOV AX,ES
  34. ADD AX,0x0020
  35. MOV EX,AX ;内存单元基址后移0x20。[EX+0x20:]
  36. ADD CL,1 ;读取扇区数递增+1
  37. CMP CL,18 ;判断是否读取到18扇区
  38. JBE readdisk ;上面cmp判断(<=)结果为true则跳转到DisplayError
  39. .readxx
  40. ;读取另一面磁头。循环读取柱面
  41. MOV CL,1 ;设置柱面为0
  42. ADD DH,1 ;设置磁头递增+1:读取下一个磁头
  43. CMP DH,2 ;判断磁头是否读取完毕
  44. JB ReadSectorLoop ;上面cmp判断(<)结果为true则跳转到DisplayError
  45. MOV DH,0 ;设置磁头为0
  46. ADD CH,1 ;设置柱面递增+1;读取下一柱面
  47. CMP CH,10 ;判断是否已经读取10个柱面
  48. JB readdisk ;上面cmp判断(<)结果为true则跳转到DisplayError

完整代码

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

  1. ;RATSBOOT
  2. ;TAB=4
  3. ;定义常量
  4. DISC_ADDR EQU 0x8000 ;磁盘第一个扇区开始,加载到内存缓冲的地址
  5. SECTOR_NUM EQU 18 ;读取扇区数
  6. CYLINDER_NUM EQU 10 ;读取柱面数
  7. ORG 0x7c00 ;指明程序的偏移的基地址
  8. ;以下这段是标准FAT32 格式软盘专用的代码
  9. JMP Entry
  10. DB 0x90 ;nop,0x02
  11. DB "RATSBOOT" ;(8字节)启动区的名称可以是任意的字符串
  12. DW 512 ;每个扇区(sector)的大小(必须为512 字节)
  13. DB 8 ;簇(cluster )的大小(每个簇为8个扇区)
  14. DW 584 ;保留扇区数,包括启动扇区
  15. DB 2 ;FAT的个数(必须为2
  16. DW 0 ;最大根目录条目个数
  17. DW 0 ;总扇区数(如果是0,就使用偏移0x20处的4字节值)
  18. DB 0x00f8 ;磁盘介质描述
  19. DW 0 ;(FAT16)每个文件分配表的扇区
  20. DW 63 ;每个磁道扇区数
  21. dw 255 ;磁头数
  22. dd 63 ;隐藏扇区
  23. dd 3902913 ;磁盘大小,总共扇区数(如果超过65535,参见偏移0x13
  24. dd 3804 ;每个文件分配表的扇区,3804个扇区
  25. dw 0 ;Flagss
  26. dw 0 ;版本号
  27. dd 2 ;根目录启始簇
  28. dw 1 ;FSInfo扇区
  29. dw 6 ;启动扇区备份
  30. times 12 db 0 ;保留未使用
  31. DW 0 ;操作系统自引导代码
  32. db 0x80 ;BIOS设备代号
  33. db 0 ;未使用
  34. db 0x29 ;标记
  35. DD 0xffffffff ;序列号
  36. DB "HELLO-OS " ;(11字节)磁盘名称,卷标。字符串长度固定
  37. DB "FAT32 " ;(8字节)FAT文件系统类型。 0x52
  38. times 12 db 0
  39. ;程序核心内容
  40. Entry:
  41. MOV AX,0 ;初始化寄存器
  42. MOV SS,AX
  43. MOV SP,0x7c00
  44. MOV DS,AX
  45. MOV DI,StartMessage ;将Message1段的地址放入SI
  46. CALL DisplayStr ;调用函数
  47. MOV DI,BootMessage ;将Message1段的地址放入SI
  48. ADD DH,1
  49. CALL DisplayStr ;调用函数
  50. ;读取磁盘初始化
  51. MOV AX,DISC_ADDR/0x10 ;设置磁盘读取的缓冲区基本地址为ES=0x820。[ES:BX]=ES*0x10+BX
  52. MOV ES,AX ;BIOS中断参数:ES:BX=缓冲区的地址
  53. MOV CH,0 ;设置柱面为0
  54. MOV DH,0 ;设置磁头为0
  55. MOV CL,1 ;设置扇区为2
  56. ReadSectorLoop:
  57. CALL ReadDisk0; ;读取一个扇区
  58. ;准备下一个扇区
  59. ReadNextSector:
  60. MOV AX,ES
  61. ADD AX,0x0020
  62. MOV ES,AX ;内存单元基址后移0x20(512字节)。[ES+0x20:]
  63. ADD CL,1 ;读取扇区数递增+1
  64. CMP CL,SECTOR_NUM ;判断是否读取到18扇区
  65. JBE ReadSectorLoop ;上面cmp判断(<=)结果为true则跳转到DisplayError
  66. ;读取另一面磁头。循环读取柱面
  67. MOV CL,1 ;设置柱面为0
  68. ADD DH,1 ;设置磁头递增+1:读取下一个磁头
  69. CMP DH,2 ;判断磁头是否读取完毕
  70. JB ReadSectorLoop ;上面cmp判断(<)结果为true则跳转到DisplayError
  71. MOV DH,0 ;设置磁头为0
  72. ADD CH,1 ;设置柱面递增+1;读取下一柱面
  73. CMP CH,CYLINDER_NUM ;判断是否已经读取10个柱面
  74. JB ReadSectorLoop ;上面cmp判断(<)结果为true则跳转到DisplayError
  75. ;LoadSuccess:
  76. MOV DI,Succmsg
  77. MOV DH,3
  78. CALL DisplayStr ;此处必须注释掉,不能调用INT。原因不明。
  79. ;加载执行boot文件:
  80. ;MOV [0x0ff0],CH ;将总共读取的柱面数存储在内存单元中
  81. ;JMP 0xc200 ;跳转执行在内存单元0xc200的代码
  82. GoLoader:
  83. MOV [0x0ff0],CH ;将总共读取的柱面数存储在内存单元中
  84. JMP 0xc200 ;跳转执行在内存单元0xc200的代码:DISC_ADDR-0x200+0x4200
  85. ;(启动扇区开始地址0x8000+软盘代码:boot文件开始0x4200)
  86. LoadError:
  87. MOV DI,Errormsg
  88. MOV DH,3
  89. CALL DisplayStr ;如果加载失败显示加载错误
  90. ;程序挂起
  91. Fin:
  92. HLT ;让CPU挂起,等待指令。
  93. JMP Fin
  94. ; ------------------------------------------------------------------------
  95. ; 读取一个扇区函数:ReadDisk0
  96. ; ------------------------------------------------------------------------
  97. ; 参数:ES:BS 缓冲区地址,CH柱面,DH磁头,CL扇区,AL扇区数=1,DL驱动器=0x
  98. ; ------------------------------------------------------------------------
  99. ReadDisk0:
  100. MOV SI,0 ;初始化读取失败次数,用于循环计数
  101. ;为了防止读取错误,循环读取5
  102. ;调用BIOS读取一个扇区
  103. ReadFiveLoop:
  104. MOV AH,0x02 ;BIOS中断参数:读扇区
  105. MOV AL,1 ;BIOS中断参数:读取扇区数
  106. MOV BX,0
  107. MOV DL,0x00 ;BIOS中断参数:设置读取驱动器为软盘
  108. INT 0x13 ;调用BIOS中断操作磁盘:读取扇区
  109. JNC ReadEnd ;条件跳转,操作成功进位标志=0。则跳转执行ReadNextSector
  110. ADD SI,1 ;循环读取次数递增+1
  111. CMP SI,5 ;判断是否已经读取超过5
  112. JAE LoadError ;上面cmp判断(>=)结果为true则跳转到DisplayError
  113. MOV AH,0x00 ;BIOS中断参数:磁盘系统复位
  114. MOV DL,0x00 ;BIOS中断参数:设置读取驱动器为软盘
  115. INT 0x13 ;调用BIOS中断操作磁盘:磁盘系统复位
  116. JMP ReadFiveLoop
  117. ;扇区读取完成
  118. ReadEnd:
  119. RET
  120. ; ------------------------------------------------------------------------
  121. ; 显示字符串函数:DisplayStr
  122. ; ------------------------------------------------------------------------
  123. ; 参数:SI:字符串开始地址, DH为第N
  124. ; ------------------------------------------------------------------------
  125. DisplayStr:
  126. MOV CX,0 ;BIOS中断参数:显示字符串长度
  127. MOV BX,DI
  128. .1:;获取字符串长度
  129. MOV AL,[BX] ;读取1个字节。这里必须为AL
  130. ADD BX,1 ;读取下个字节
  131. CMP AL,0 ;是否以0结束
  132. JE .2
  133. ADD CX,1 ;计数器
  134. JMP .1
  135. .2:;显示字符串
  136. MOV BX,DI
  137. MOV BP,BX
  138. MOV AX,DS
  139. MOV ES,AX ;BIOS中断参数:计算[ES:BP]为显示字符串开始地址
  140. MOV AH,0x13 ;BIOS中断参数:显示文字串
  141. MOV AL,0x01 ;BIOS中断参数:文本输出方式(40×25 16 文本)
  142. MOV BH,0x0 ;BIOS中断参数:指定分页为0
  143. MOV BL,0x0c ;BIOS中断参数:指定白色字体07
  144. MOV DL,0 ;列号为0
  145. INT 0x10 ;调用BIOS中断操作显卡。输出字符
  146. RET
  147. ;数据初始化
  148. StartMessage: DB "hello,rats os start",0
  149. BootMessage: DB "booting............",0
  150. Errormsg: DB "load error ",0
  151. Succmsg: DB "load success",0
  152. FillSector:
  153. RESB 510-($-$$) ;处理当前行$至结束(1FE)的填充
  154. DB 0x55, 0xaa

运行结果如下:

上面代码的作用

首先boot.asm会被加载到内存并且执行.后面开始读取磁盘的10个柱面(10*18个扇区).

读取的扇区数据复制到 内存 0x8000 开始的位置.

然后打印输出"hello,rats os start"

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

  1. 读取磁盘:LBA方式

    LBA简介 磁盘读取发展 IO操作读取硬盘的三种方式: chs方式 :小于8G (8064MB) LBA28方式:小于137GB LBA48方式:小于144,000,000 GB LBA方式访问使用了 ...

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

    前言 windows操作系统中常见的一个文件存储系统是NTFS.在这个文件系统中MFT是它的核心.             图一 MFT是一个数据结构,上图是它的结构,它主要用来存放每个文件和目录在磁 ...

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

    Android 4.4前后版本读取图库图片方式的变化   本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化   Android 4.4(KitKat)以前 ...

  4. python读取配置文件的方式

    python读取配置文件的方式 1.从config.ini中读取,后缀无所谓,文件名字也无所谓,不过config.ini是常用写法,所谓见名知意 config.ini内容: [global] ip = ...

  5. JavaWeb中servlet读取配置文件的方式

    我们在JavaWeb中常常要涉及到一些文件的操作,比如读取配置文件,下载图片等等操作.那我们能不能采用我们以前在Java工程中读取文件的方式呢?废话不多说我们来看看下我们以前在Java工程中读取文件是 ...

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

    Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息.”的问题解决 2015-01-22 09:49:02 标签:Windows Server2003 PerfDi ...

  7. Java读取配置文件的方式

    Java读取配置文件的方式-笔记 1       取当前启动文件夹下的配置文件   一般来讲启动java程序的时候.在启动的文件夹下会有配置文件 classLoader.getResource(&qu ...

  8. linux初学者-磁盘分区方式篇

    linux初学者-磁盘分区方式篇 一般的计算机都会采用mbr分区方式,这种分区方式只能够建立四个主分区,如果还需要或更多的分区,就需要将其中一个主分区建立成一个扩展分区,在里面建立逻辑分区,这些分区信 ...

  9. Java 将数据写入磁盘并读取磁盘上的文件

    package test; import java.io.BufferedReader;import java.io.FileReader;import java.io.FileWriter;impo ...

随机推荐

  1. window中普通用户无法登录远程桌面

    解决方案就是将该用户加到 Remote Desktop Users 这个用户组中. 使用命令 net localgroup "Remote Desktop Users" 用户名 / ...

  2. xxnet to google部署

    1,github上下载xxnet项目 2,启动(点击 start) 3,确定启动好后访问 www.google.com (此时是可以访问的) 4,注册google账号或直接登陆 5,访问 https: ...

  3. linux tail命令及其它日志查看命令的用法

    当日志文件存储日志很大时,我们就不能用vi直接进去查看日志,需要Linux的命令去完成我们的查看任务. Log位置: /var/log/message 系统启动后的信息和错误日志,是Red Hat L ...

  4. hdu5517 二维树状数组

    题意是给了 n个二元组 m个三元组, 二元组可以和三元组 合并生成3元组,合并条件是<a,b> 与<c,d,e>合并成 <a,c,d> 前提是 b==e, 如果存在 ...

  5. java.lang.RuntimeException: wrong class format Caused by: org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException: null

    Spring Boot 启动的时候报的错 使用Drools 5.6版本,Spring Boot1.5.8版本,JAVA8版本,Eclipse4.4.2版本. Google后在Stack上发现一个,中文 ...

  6. mybatis中的foreach方法

    select  t.service_id, t.prod_id, t.prod_name, t.prod_type, t.buss_type, t.pricing_fee, t.detail from ...

  7. C#异步编程基础入门总结

    1.前言 *.NET Framework提供了执行异步操作的三种模式: 异步编程模型(APM)模式(也称为IAsyncResult的模式),其中异步操作要求Begin和End方法(例如,BeginWr ...

  8. button theme

    children:[ButtonTheme.bar( child:ButtonBar( children:[ FlatButton... ], ),), ]

  9. PHP保留两位小数并且四舍五入及不四舍五入的方法

    php保留两位小数并且四舍五入 $num = 123213.666666; echo sprintf("%.2f", $num); php保留两位小数并且不四舍五入 $num = ...

  10. Python Redis list

    List操作,redis中的List在在内存中按照一个name对应一个List来存储. 注:列表存入 从右到左 如图: lpush(name,values) # 在name对应的list中添加元素,每 ...