注:以下程序为原创,若发现任何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柱面。如下:

[cpp] view plaincopyprint?
  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 中断读取软盘

[cpp] view plaincopyprint?
  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.

[cpp] view plaincopyprint?
  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),然后读取给定的相对扇区号的扇区,将读取的内容打印到屏幕上。并与写入的数据比较,验证读取的正确性。

[cpp] view plaincopyprint?
  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

[cpp] view plaincopyprint?
  1. <pre></pre>
  2. <pre></pre>

babyos (三)——利用BIOS INT 0x13读取软盘相关推荐

  1. 突破BIOS无法连续读取软盘72扇区的限制

    具体代码调试和讲解请参看视频: Linux kernel Hacker, 从零构建自己的内核 一直以来,我们的操作系统加载器,秉承简单够用的原则,只要能把编译好的二进制内核送进内存就可以了,所以加载器 ...

  2. 利用BIOS 中断INT 0x10显示字符和字符串

    注:以下程序系原创,使用AT&T格式汇编来调用BIOS 0x10中断,如有错误,欢迎指正.表达能力较差,写的不好,但若能帮助一二访客,幸甚. 使用BIOS 显示服务(Video Service ...

  3. linux 汇编 读取软盘,读取软盘逻辑扇区的汇编实现代码

    该过程以int 13H 02H子功能为基础,与int 13H采用相同的基于1的扇区地址,完成读取若干逻辑扇区的功能.过程没有对输入参数做任何检测,请读者自行保证输入参数的正确性.参数的合法范围:AX& ...

  4. linux 汇编 读取软盘,学习x86汇编语言7 使用INT13读取软盘数据

    学习x86汇编语言7 使用INT13读取软盘数据 一.本章使用工具 二.软盘存储介绍 三.BIOS int13功能 四.引导程序源代码 一.本章使用工具 nasm FloppyWriter bochs ...

  5. 30天自制操作系统 - 用INT 0x13/AH=0x42h读磁盘

    背景 基本上,每个硬盘除了每扇(Sector)大小依旧是512字节外,柱面(Cylinder)数.磁头(Header)数都不一致. 用磁盘来取代原作者的软盘后,沿用原来的INT 0x13/AH=2h读 ...

  6. xml 和android脚本之家,Android利用Document实现xml读取和写入操作

    本文实例为大家分享了利用Document实现xml读取和写入操作,供大家参考,具体内容如下 首先先来介绍一下什么xml?xml是可扩展标记语言,他可以用来标记数据,定义数据类型.是一种允许用户对自己标 ...

  7. BIOS INT中断整理

    BIOS 中断 1. 显示服务(Video Service--INT 10H) 2. 直接磁盘服务(Direct Disk Service--INT 13H) 3.串行口服务(Serial Port ...

  8. CUDA实例系列三:利用GPU优化向量规约问题

    CUDA实例系列三:利用GPU优化向量规约问题 先简单的描述一下题目中说的向量规约问题. 这里举个例子, 比如: 我要求出1+2+3-+100的和 我要求出123-*100的积 我要找到a[100]中 ...

  9. BIOS int 13H中断介绍

    BIOS int 13H中断也叫直接磁盘服务(Direct Disk Service),该中断的各个功能号及对应的功能描述如下: 1.功能 00H 功能描述:磁盘系统复位 入口参数:AH=00H DL ...

最新文章

  1. c++ make_pairpair
  2. UiBot带你两分钟看懂RPA是什么
  3. viewflipper动画切换屏幕
  4. IE6与其他浏览器的区别
  5. 常用数据绑定控件详解
  6. SAP 电商云 Spartacus UI set delivery mode HTTP put 请求的触发时机
  7. 关于 hibernate 官网的例子 出现的问题
  8. 给谷歌浏览器安装vue调试工具:vue-devtools
  9. pg10 10.3 1 linux64,Install Postgresql 10 In Ubutnu 16.04 LTS
  10. 理解PHP5中static和const关键字
  11. 使用Windows版Redis
  12. 使用OGR2OGR将S57数据转为shp格式
  13. C/C++编程语言中指针(pointer)介绍
  14. win10电脑显示无法自动修复此计算机,win10系统无法自动修复此计算机的操作步骤...
  15. ACL2021 | 对比学习8篇论文一句话总结
  16. 计算机专业毕业论文选题方向,计算机毕业方向论文选题 计算机毕业论文题目选什么比较好...
  17. cppc文件无法正常输出汉字,将文件修改为UTF-8格式
  18. 企业cc邮箱发件服务器设置,C#发送邮件(阿里企业邮箱示例 包括各个类型的服务器及端口配置)...
  19. 2019年Q4三星和华为都败了,谁也想不到第一名是它
  20. 近10年的网盘发展史(那些年你的网盘存了多少资料)

热门文章

  1. 【Java 并发编程】线程池机制 ( 线程池状态分析 | 线程池状态转换 | RUNNING | SHUTDOWN | STOP | TIDYING | TERMINATED )
  2. 【错误记录】Android Studio 编译报错 ( SDK location not found )
  3. 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )
  4. 【错误记录】Android Studio 导入外部 so 动态库报错 ( java.lang.UnsatisfiedLinkError | 指定 APK 打包动态库的 CPU 架构 )
  5. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 交叉编译 OpenSSL 开源库 )
  6. Nginx初学第一步
  7. cs224n第一讲深度自然语言处理
  8. js实现旋转木马轮播图
  9. VMware虚拟机 CentOS 6.5系统安装配置详细图文教程 --技术支持TPshop商城
  10. 119. Pascal's Triangle II (Graph; WFS)