利用BIOS INT 0x13读取软盘

转载自
https://blog.csdn.net/guzhou_diaoke/article/details/8436037

注:以下程序为原创,若发现任何BUG,欢迎指正;若有问题,欢迎交流;权利归原作者所有,若转载,请注明出处;若能有益于一二访客,幸甚。

昨天学习了VGA显示的一些东西,今天准备学习一下读取软盘的知识。


1.babyos将使用的引导过程

1)系统上电或reset时,处理器执行一些初始化,CPU处于实模式
2)处理器会执行一个位于已知位置处的代码,PC中这个位置位于BIOS,它保存在主板上的闪存中
3)控制权交给BIOS后,它寻找一个可引导的设备(软盘、硬盘等),BIOS读取引导扇区(512字节)到内存0x7c00处,并跳转到该地址执行
4)引导扇区中存放的指令可以使用BIOS中断,它将会读取软盘中内核部分到一个临时地址(如0x10000,不覆盖0x7c00处的boot代码即可)
5)将内核前512字节(load.s, 它主要负责将内核剩余部分拷贝到load.s后面)移动到0x0处,将GDT拷贝到0x80000处。为什么不一次全部将内核放到0x0处呢?因为内核可能较大,会覆盖掉0x7c00处的代码。
6)开启A20总线,置位CR0的bit 0,开启保护模式,加载GDT到GDTR,跳转到GDT第二项(第一项为空GDT),即load.s处执行
7)load.s将内核剩余部分移动到load.s后面,即0x200开始的地址处。然后执行初始化代码。
8)初始化代码,至此系统启动成功。

所以首当其冲的问题就是如何读软盘。

2.软盘的结构

3.5寸1.44M 软盘,如图floppy_struct.png 所示,有两个磁头,正反两面各一个;80个磁道(即80个圆圈);每个磁道有18个扇区;每个扇区为512字节。
容量 = 512字节/扇区 * 2面 * 80磁道(柱面)/面 * 18扇区/磁道 = 1440 KB

磁头,即面:编号[0, 1]
80个磁道,即柱面(圆圈):编号[0, 79]
18个扇区:编号[1, 18]

相对扇区号[0, 2879]:
相对扇区号按照柱面排序,即从最外头的圆圈到最里头的圆圈。
0柱面正面(即磁头号为0)的1-18扇区为0-17号相对扇区,0柱面反面(即磁头号为2)的1-18扇区为18-35号相对扇区,然后是1柱面,2柱面,直到79柱面。如下:

 
 
  1. 0柱面, 0磁头, 1扇区 0
  2. 0柱面, 0磁头, 2扇区 1
  3. ……
  4. 0柱面, 0磁头, 18扇区 17
  5. 0柱面, 1磁头, 1扇区 18
  6. ……
  7. 0柱面, 1磁头, 18扇区 35
  8. 1柱面, 0磁头, 1扇区 36
  9. ……
  10. 1柱面, 0磁头, 18扇区 53
  11. 1柱面, 1磁头, 1扇区 54
  12. ……
  13. 1柱面, 1磁头, 18扇区 71
  14. 2柱面, 0磁头, 1扇区 72
  15. ……

3.利用BIOS 中断读取软盘


 
 
  1. -------------------------------------------------------------------
  2. INT 0x13,功能 02
  3. -----------------------------------------------------------
  4. 参数:
  5. AH 02
  6. AL 读取扇区数
  7. CH 柱面[ 0, 79]
  8. CL 扇区[ 1, 18]
  9. DH 磁头[ 0, 1]
  10. DL 驱动器( 0x0 ~ 0x7f表示软盘, 0x80 ~ 0xff表示硬盘)
  11. ES:BX 缓冲区地址,即数据读到这里
  12. 返回值:
  13. CF = 0表示操作成功,此时AH= 0,AL=传输的扇区数
  14. CF = 1即carry位置位(可用JC表示跳转)表示操作失败,AH=状态代码
  15. --------------------------------------------------------------------

4.相对扇区号的计算

1)知道柱面号,磁头号,扇区号计算相对扇区号
由上面可知0号柱面包含了相对扇区号[0,35],1号柱面包含相对扇区号[36,71],依次类推。
设相对扇区号为N,则
柱面号CH = N / 36;
令x = N % 36;
则x范围为[0,35],其中[0,17] 为磁头号0, [18,35]为磁头号1.
则磁头号DH = x / 18;
零y = x % 18; y范围[0, 17]
则扇区号CL = y + 1。

2)知道相对扇区号,计算柱面号、磁头号、扇区号
N = 36*CH + 18*DH + CL;
由此式子,也可计算:
CH = N / 36
DH = (N % 36) / 18
CL = (N % 36) % 18 + 1

5.读取一个扇区

实验:将一些数据写入软盘的第二个扇区(第一个扇区是引导扇区),然后用BIOS 中断读取该扇区的数据,并显示在屏幕上。然后看读取的数据是否与写入的数据相同。注:第二个扇区相对扇区号为1.

 
 
  1. 写数据的C代码:
  2. /*************************************************************************
  3. > File: write_data.c
  4. > Author: 孤舟钓客
  5. > Mail: guzhoudiaoke@126.com
  6. > Time: 2012年12月26日 星期三 01时20分26秒
  7. ************************************************************************/
  8. #include <stdio.h>
  9. #include <string.h>
  10. int main()
  11. {
  12. FILE *fp;
  13. fp = fopen( "./data", "wb");
  14. int i;
  15. char *str = "baby os, guzhoudiaoke@126.com ";
  16. int len = strlen(str);
  17. for (i = 0; i < len; i++)
  18. fprintf(fp, "%c", str[i]);
  19. for (i = 512-len; i > 0; i--)
  20. fprintf(fp, "%c", i % 26 + 'A');
  21. return 0;
  22. }
  23. 汇编代码:
  24. # This program draws color pixels at mode 0x13
  25. # 2012 -12 -26 01: 31
  26. # guzhoudiaoke@126.com
  27. .include "boot.inc"
  28. .section .text
  29. .global _start
  30. .code16
  31. _start:
  32. jmp main
  33. #--------------------------------------------------------------
  34. # 清屏函数:
  35. # 设置屏幕背景色,调色板的索引 0指代的颜色为背景色
  36. clear_screen: # 清屏函数
  37. movb $ 0x06, %ah # 功能号 0x06
  38. movb $ 0, %al # 上卷全部行,即清屏
  39. movb $ 0, %ch # 左上角行
  40. movb $ 0, %ch # 左上角列
  41. movb $ 24, %dh # 右下角行
  42. movb $ 79, %dl # 右下角列
  43. movb $ 0x07, %bh # 空白区域属性
  44. int $ 0x10
  45. ret
  46. #---------------------------------------------------------------
  47. # 直接写显存显示一些文字函数:
  48. # 调用前需要设置DS:SI为源地址,DI为显示位置,
  49. # CX 为显示的字符个数, AL为颜色属性
  50. draw_some_text:
  51. # ES:DI is the dst address, DS:SI is the src address
  52. movw $VIDEO_SEG_TEXT, %bx
  53. movw %bx, %es
  54. copy_a_char:
  55. movsb
  56. stosb
  57. loop copy_a_char
  58. ret
  59. #----------------------------------------------------------------
  60. # 读取软盘第二个扇区:
  61. # 使用BIOS INT 0x13中断,使用前需要设置ES:BX作为缓冲区
  62. read_one_sect:
  63. movb $ 0x02, %ah # 功能号
  64. movb $ 0x01, %al # 读取扇区数
  65. movb $ 0x00, %ch # 柱面号
  66. movb $ 0x02, %cl # 扇区号
  67. movb $ 0x00, %dh # 磁头号
  68. movb $ 0x00, %dl # 驱动器号
  69. re_read: # 若调用失败则重新调用
  70. int $ 0x13
  71. jc re_read # 若进位位(CF)被置位,表示调用失败
  72. ret
  73. main:
  74. movw %cx, %ax
  75. movw %ax, %ds
  76. movw %ax, %es
  77. call clear_screen # 清屏
  78. movw $ 0, %ax
  79. movw %ax, %ds
  80. leaw msg_str, %si
  81. xorw %di, %di
  82. movw msg_len, %cx
  83. movb $TEXT_COLOR,%al
  84. call draw_some_text # 绘制字符串
  85. movw $BUFFER_SEG,%ax
  86. movw %ax, %es # ES:BX 为缓冲区地址
  87. xorw %bx, %bx
  88. call read_one_sect
  89. # 下面调用绘制函数,在屏幕上显示读取的信息
  90. movw $BUFFER_SEG,%ax
  91. movw %ax, %ds # ds:si 为源地址
  92. xorw %si, %si
  93. movw $ 160, %di # 第一行已经打印了msg_str,从第二行开始显示
  94. movw $ 512, %cx # 显示 512个字符
  95. movb $ 0x01, %al
  96. call draw_some_text
  97. 1:
  98. jmp 1b
  99. msg_str:
  100. .asciz "The data of the second sect of the floppy (sect 1):"
  101. msg_len:
  102. . int . - msg_str - 1
  103. .org 0x1fe, 0x90
  104. .word 0xaa55

实验结果:



6.读取任意扇区(给定相对扇区号)

实验,写用C语言写入文件,该文件包含512个‘a’,512个1……512个‘z’, 循环50次,将该文件写入软盘(相对扇区号1~50*26),然后读取给定的相对扇区号的扇区,将读取的内容打印到屏幕上。并与写入的数据比较,验证读取的正确性。


 
 
  1. C代码用于写文件:
  2. /*************************************************************************
  3. > File: write_data.c
  4. > Author: 孤舟钓客
  5. > Mail: guzhoudiaoke@126.com
  6. > Time: 2012年12月26日 星期三 20时16分45秒
  7. ************************************************************************/
  8. #include <stdio.h>
  9. #include <string.h>
  10. int main(int argc, char *argv[])
  11. {
  12. if (argc != 2)
  13. {
  14. printf( "usage: ./write_data file_name");
  15. exit( 0);
  16. }
  17. FILE *fp;
  18. fp = fopen(argv[ 1], "wb");
  19. int i, j, k;
  20. for (i = 0; i < 50; i++)
  21. {
  22. for (j = 'a'; j <= 'z'; j++)
  23. {
  24. for (k = 0; k < 512; k++)
  25. {
  26. fprintf(fp, "%c", ( char)j);
  27. }
  28. }
  29. }
  30. return 0;
  31. }
  32. 汇编代码:
  33. # This program draws color pixels at mode 0x13
  34. # 2012 -12 -26 20: 23: 42
  35. # guzhoudiaoke@126.com
  36. .include "boot.inc"
  37. .section .text
  38. .global _start
  39. .code16
  40. _start:
  41. jmp main
  42. #--------------------------------------------------------------
  43. # 清屏函数:
  44. # 设置屏幕背景色,调色板的索引 0指代的颜色为背景色
  45. clear_screen: # 清屏函数
  46. movb $ 0x06, %ah # 功能号 0x06
  47. movb $ 0, %al # 上卷全部行,即清屏
  48. movb $ 0, %ch # 左上角行
  49. movb $ 0, %ch # 左上角列
  50. movb $ 24, %dh # 右下角行
  51. movb $ 79, %dl # 右下角列
  52. movb $ 0x07, %bh # 空白区域属性
  53. int $ 0x10
  54. ret
  55. #---------------------------------------------------------------
  56. # 直接写显存显示一些文字函数:
  57. # 调用前需要设置DS:SI为源地址,DI为在屏幕上的显示位置,
  58. # CX 为显示的字符个数, AL为颜色属性
  59. draw_some_text:
  60. # ES:DI is the dst address, DS:SI is the src address
  61. movw $VIDEO_SEG_TEXT, %bx
  62. movw %bx, %es
  63. copy_a_char:
  64. movsb
  65. stosb
  66. loop copy_a_char
  67. ret
  68. #----------------------------------------------------------------
  69. # 读取软盘一个扇区:
  70. # 使用BIOS INT 0x13中断,使用前需要设置ES:BX作为缓冲区
  71. # AX为相对扇区号
  72. read_one_sect:
  73. movb $ 36, %dl
  74. divb %dl
  75. movb %al, %ch # 柱面号=N / 36, 假设x = N % 36
  76. movb %ah, %al # AL = N % 36
  77. movb $ 0, %ah # AX = N % 36
  78. movb $ 18, %dl
  79. divb %dl
  80. movb %al, %dh # 磁头号DH = x / 18
  81. movb %ah, %cl
  82. incb %cl # 扇区号CL = x % 18 + 1
  83. movb $ 0x00, %dl # 驱动器号DL
  84. movb $ 0x02, %ah # 功能号
  85. movb $ 0x01, %al # 读取扇区数
  86. re_read: # 若调用失败则重新调用
  87. int $ 0x13
  88. jc re_read # 若进位位(CF)被置位,表示调用失败
  89. ret
  90. #-------------------------------------------------------------------
  91. # 该函数读取指定的若干扇区号
  92. # 需要指定ES:BX作为缓冲区
  93. read_sects:
  94. movw $ 0x00, %si # 已经读取的扇区数
  95. leaw sect_no, %di
  96. 1:
  97. movw (%di), %ax # 获取相对扇区号
  98. addw $ 2, %di
  99. call read_one_sect
  100. incw %si
  101. incw %bx
  102. cmpw num_to_read, %si
  103. jne 1b
  104. ret
  105. main:
  106. movw %cx, %ax
  107. movw %ax, %ds
  108. movw %ax, %es
  109. call clear_screen # 清屏
  110. # 显示提示信息
  111. movw $ 0, %ax
  112. movw %ax, %ds
  113. leaw msg_str, %si
  114. xorw %di, %di
  115. movw msg_len, %cx
  116. movb $TEXT_COLOR,%al
  117. call draw_some_text # 绘制字符串
  118. # 读取软盘
  119. movw $BUFFER_SEG, %ax
  120. movw %ax, %es # ES:BX 为缓冲区地址
  121. xorw %bx, %bx
  122. call read_sects
  123. # 在屏幕上显示读取的信息
  124. # movw $BUFFER_SEG,%ax
  125. # movw %ax, %ds # ds:si 为源地址
  126. # movw $ 0, %si
  127. # movw $ 320, %di # 第一行已经打印了msg_str,从第二行开始显示
  128. # movw $ 512, %cx # 显示字符数
  129. # movb $ 0x01, %al
  130. # call draw_some_text
  131. # 将缓冲区中前data_len个字节拷贝到data_save
  132. xorw %ax, %ax
  133. movw %ax, %ds
  134. movw num_to_read,%cx
  135. movw $BUFFER_SEG,%ax
  136. movw %ax, %ds
  137. xorw %ax, %ax
  138. movw %ax, %es
  139. movw $ 0, %si
  140. movw $data_save, %di
  141. cld
  142. rep movsb
  143. # 下面调用绘制函数,在屏幕上显示读取的信息
  144. xorw %ax, %ax
  145. movw %ax, %ds # ds:si 为源地址
  146. leaw data_save, %si
  147. movw $ 160, %di # 第一行已经打印了msg_str,从第二行开始显示
  148. movw num_to_read,%cx # 显示字符数
  149. movb $ 0x01, %al
  150. call draw_some_text
  151. 1:
  152. jmp 1b
  153. msg_str:
  154. .asciz "The data read from floppy:"
  155. msg_len:
  156. . short . - msg_str - 1
  157. sect_no:
  158. # 下面的扇区数据为: "babyosguzhoudiaoke"
  159. # sect: 2+ 26* 1, 1+ 26* 2, 2+ 26* 3, 25+ 26* 4, 15+ 26* 5, 19+ 26* 6,
  160. # 7+ 26* 11, 21+ 26* 12, 26+ 26* 13, 8+ 26* 14, 15+ 26* 15, 21+ 26* 16,
  161. # 4+ 26* 31, 9+ 26* 32, 1+ 26* 33, 15+ 26* 34, 11+ 26* 35, 5+ 26* 36
  162. . short 28, 53, 80, 129, 145, 175
  163. . short 293, 333, 364, 372, 379, 411
  164. . short 810, 841, 859, 899, 921, 941
  165. num_to_read:
  166. . short 18
  167. data_save:
  168. .asciz "XXXXXXXXXXXXXXXXXX"
  169. .org 0x1fe, 0x90
  170. .word 0xaa55




 
 
 

                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值