利用BIOS INT 0x13读取软盘

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



  1. <pre></pre>  
  2. <pre></pre> 


  3. 原文地址 :http://blog.csdn.net/guzhou_diaoke/article/details/8436037 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值