当前位置:   article > 正文

自己动手写操作系统:4.模拟软盘的数据结构,加载指定软盘扇区中的数据_用数组实现软盘

用数组实现软盘

前面两节介绍了如何在系统加载的时候在屏幕上打印出Hello OS!

我们是使用汇编直接对cpu进行操作,我们的数据容量只有启动扇区的512字节,这样的空间显然不够以后的开发使用。

本节我们引入软盘的数据结构,对软盘的数据结构进行模拟,并加载软盘中指定扇区的内容。

本节按照一下结构组织:

1.介绍软盘的物理以及逻辑结构

2.根据软盘逻辑结构,使用C语言创建软盘映像文件,并把数据写入软盘扇区

3.介绍如何使用汇编读取软盘中扇区的数据

4.实际运行测试



一.介绍软盘的物理以及逻辑结构
以一块软盘为例,一块软盘有两个面,正面和反面,每个面被80个圆环分成80个磁道(1-80),每个磁道(或者称为柱面)由18个扇区(0-17)组成,每个扇区的大小为512字节。
所以一块软盘的大小为 2*80*18*512 = 1474560 字节 = 1440KB = 1.44M

物理地址                        逻辑扇区地址
0面0磁道  1扇区                       0
0面0磁道  2扇区                       1
           :                         :       
0面0磁道 18扇区                       17
1面0磁道  1扇区                       18
1面0磁道  2扇区                       19
           :                          :
1面0磁道18扇区                        35
           :                          :      
我们把逻辑扇区地址可以看成大小为1.44M的数组的下标,每个数组元素的大小为512字节。
所以我们希望能根据 面 磁道 扇区 找到和 逻辑扇区的对应的关系,这样把对 面、磁道、扇区转化为对数组元素的操作,
这样就大大简化了我们的实现难度。
相对扇区号 = {盘面(0~1)*每条磁道扇区数(18)} + {2*磁道(0~79)*每条磁道扇区数(18)} +  {扇区(1-18)-1};

对于我们制作写盘来说知道上面的公式就可以了,补充一点,知道了逻辑扇面号,怎么推断出 扇面 磁道 和 盘面 号呢?
而当知道相对扇区号,怎么推算出盘面、磁道、扇区呢?
具体步骤:
(1)从上面公式可以看出,相对扇区号对每条磁道扇区数(18)取余数 加1 就得到扇区;
(2)再根据(1)得到的商,如果盘面为1则商为奇数,否则为偶数,于是通过判断商的奇偶性,就可以得出盘;同时也可以算出磁道(减去1可得);

二、.根据软盘逻辑结构,使用C语言创建软盘映像文件,并把数据写入软盘扇区

下面是主程序 ReadWrite.c

  1. #include "stdio.h"
  2. #include <stdlib.h>
  3. #include "floppy.h"
  4. #include <stdlib.h>
  5. void TestResult(FILE * fp)
  6. {
  7. if(feof(fp))
  8. {
  9. //printf("Read OK\n"); //读取成功不许要打印消息
  10. }
  11. else if(ferror(fp))
  12. {
  13. printf("Read REEOR\n");
  14. }
  15. }
  16. int main()
  17. {
  18. char Shan[512] = {0};
  19. FILE *fpA = NULL;
  20. FILE *fpB = NULL;
  21. int ret = 0;
  22. int DateNo = 2*80*18*512;
  23. char * Floppy = NULL;
  24. char *meg = "This is message from floppy!" ;
  25. fpA = fopen("A.boot","rb");//1.修改文件名为A.boot 2.b表示打开对象为二进制文件
  26. fpB = fopen("system.img","w+");//目的文件
  27. if(0 != fflush(NULL))
  28. {
  29. printf("flushall REEOR\n");
  30. return 0;
  31. }
  32. if(NULL == fpA || NULL == fpB)
  33. {
  34. printf("open file error\n!");
  35. return 0;
  36. }
  37. ret = fread(Shan, 1, DateNo,fpA);//读取A文件数据
  38. if(ret != DateNo)
  39. {
  40. TestResult(fpA);
  41. }
  42. Shan[512-1-1] = 0x55;// 写512最后两字字节
  43. Shan[512-1] = 0xaa;
  44. Floppy = MakeFloppy();
  45. if(False == WriteFloppy(0, 0, 1, Floppy, Shan))
  46. {
  47. printf("WriteFloppy Error!\n");
  48. free(Floppy);
  49. return 0;
  50. }
  51. if(False == WriteFloppy(0, 1, 4, Floppy, meg))
  52. {
  53. printf("WriteFloppy Error!\n");
  54. free(Floppy);
  55. return 0;
  56. }
  57. ret = fwrite(Floppy, 1, DateNo, fpB);//把缓冲文件写入到B文件中
  58. if(ret != DateNo)
  59. {
  60. TestResult(fpB);
  61. }
  62. if(0 != fclose(fpB) && 0 != fclose(fpA) )//关闭所有打开的文件
  63. {
  64. printf("fcloseall REEOR\n");
  65. }
  66. free(Floppy);
  67. return 0;
  68. }

下面是创建软盘印象文件的具体实现程序floppy.c :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  1. #include <string.h>
  2. #include "floppy.h"
  3. char * MakeFloppy(void)
  4. {
  5. char * pFloppy = NULL;
  6. pFloppy = (char *)malloc(2*80*18*512);
  7. if(NULL == pFloppy)
  8. {
  9. printf("malloc error!\n");
  10. }
  11. else
  12. {
  13. memset(pFloppy, 0, (2*80*18*512));
  14. }
  15. return pFloppy;
  16. }
  17. int CheckPara(char bSide, char bCidao, char bShanmian, char * pFloppy, char * pBuffe)
  18. {
  19. if(NULL != pFloppy && NULL != pBuffe)
  20. {
  21. if(0 == bSide || 1 == bSide)
  22. {
  23. if(bCidao <= 79 && bCidao >= 0)
  24. {
  25. if(bShanmian <= 18 && bShanmian >= 1)
  26. {
  27. return True;
  28. }
  29. }
  30. }
  31. }
  32. return False;
  33. }
  34. static void WriteFloppyShanZero(char * pFloppy, char * pBuffe)
  35. {
  36. int ShanNum = 512;
  37. int i = 0;
  38. for(i=0; i<ShanNum; i++)
  39. {
  40. *pFloppy = *pBuffe;
  41. pFloppy++;
  42. pBuffe++;
  43. }
  44. }
  45. static void WriteFloppyShanNotZero(char * pFloppy, char * pBuffe)
  46. {
  47. int ShanNum = 0;
  48. ShanNum = strlen(pBuffe);
  49. ShanNum = ShanNum/512;
  50. printf("we will write %d ShanQu\n", ShanNum+1);
  51. while(* pBuffe)
  52. {
  53. *pFloppy = *pBuffe;
  54. pFloppy++;
  55. pBuffe++;
  56. }
  57. }
  58. int WriteFloppy(char bSide, char bCidao, char bShanmian, char * pFloppy, char * pBuffe)
  59. {
  60. int LogicShanMian = 0;
  61. if(False == CheckPara(bSide, bCidao, bShanmian, pFloppy, pBuffe))
  62. {
  63. printf("Para error!\n");
  64. return False;
  65. }
  66. LogicShanMian = bSide * 18 + bCidao * 2 * 18 + (bShanmian - 1);
  67. pFloppy += LogicShanMian * 512;//把指针移动到第 LogicShanMian 个扇区开头
  68. if(0 == LogicShanMian)
  69. {
  70. WriteFloppyShanZero(pFloppy, pBuffe);//0 扇区写满
  71. }
  72. else
  73. {
  74. WriteFloppyShanNotZero(pFloppy, pBuffe);
  75. }
  76. return True;
  77. }


三、介绍如何使用汇编读取软盘中扇区的数据

通过调用BIOS的 0x13 号中断,用于读取软盘数据,

在调用之前需要在相应的寄存器中设置该函数入参:

    mov          CH, 1        ;CH 用来存储磁道号
    mov          DH, 0        ;DH 用来存储磁头号
    mov          CL, 4        ;CL 用来存储扇区号


    mov          AH, 0x02   ; AH = 02 表示要做的是读盘操作
    mov          AL, 2         ; AL 表示要连续读取几个扇区
    mov          DL, 0         ;驱动器编号,一般我们只有一个软盘驱动器,所以写死为0

然后调用中断,具体的程序如下所示:

  1. org 0x7c00;
  2. entry:
  3. mov ax, 0
  4. mov ss, ax
  5. mov ds, ax
  6. mov es, ax
  7. mov si, msg
  8. readFloppy:
  9. mov CH, 1 ;CH 用来存储磁道号
  10. mov DH, 0 ;DH 用来存储磁头号
  11. mov CL, 4 ;CL 用来存储扇区号
  12. mov BX, msg ; ES:BX 数据存储缓冲区
  13. mov AH, 0x02 ; AH = 02 表示要做的是读盘操作
  14. mov AL, 2 ; AL 表示要练习读取几个扇区
  15. mov DL, 0 ;驱动器编号,一般我们只有一个软盘驱动器,所以写死
  16. ;为0
  17. INT 0x13 ;调用BIOS中断实现磁盘读取功能
  18. jc error
  19. putloop:
  20. mov al, [si]
  21. add si, 1
  22. cmp al, 0
  23. je fin
  24. mov ah, 0x0e
  25. mov bx, 15
  26. int 0x10
  27. jmp putloop
  28. fin:
  29. HLT
  30. jmp fin
  31. error:
  32. mov si, errmsg
  33. jmp putloop
  34. msg:
  35. RESB 64
  36. errmsg:
  37. DB "error"


注:(1)实际上从软盘读取到缓冲区是读的软盘扇区的起始地址,经过测试:在创建的“缓冲区”只有64的时候能也够读到3个扇区的内容。 (2)软盘多扇区的连续读或者写是按照逻辑扇区的顺序进行读写的,因此当创建好软盘之后可以直接往软盘中写入大于一个扇区的内容,超过的部分会自动写入逻辑上连续物理上不连续的扇区中。
4.实际运行测试

我们使用下面的命令来编译执行上面的程序:

A.asm -o A.boot && gcc ReadWrite.c floppy.c -g -o ReadWrite && ./ReadWrite

执行效果如图所示,可以在屏幕上看到我们写入到软盘中的数据:This is message from floppy!




本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/346589
推荐阅读
相关标签
  

闽ICP备14008679号