赞
踩
前面两节介绍了如何在系统加载的时候在屏幕上打印出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
- #include "stdio.h"
- #include <stdlib.h>
- #include "floppy.h"
- #include <stdlib.h>
- void TestResult(FILE * fp)
- {
- if(feof(fp))
- {
- //printf("Read OK\n"); //读取成功不许要打印消息
- }
- else if(ferror(fp))
- {
- printf("Read REEOR\n");
- }
-
- }
- int main()
- {
- char Shan[512] = {0};
- FILE *fpA = NULL;
- FILE *fpB = NULL;
- int ret = 0;
- int DateNo = 2*80*18*512;
- char * Floppy = NULL;
- char *meg = "This is message from floppy!" ;
-
-
- fpA = fopen("A.boot","rb");//1.修改文件名为A.boot 2.b表示打开对象为二进制文件
- fpB = fopen("system.img","w+");//目的文件
-
- if(0 != fflush(NULL))
- {
- printf("flushall REEOR\n");
- return 0;
- }
- if(NULL == fpA || NULL == fpB)
- {
- printf("open file error\n!");
- return 0;
- }
-
-
- ret = fread(Shan, 1, DateNo,fpA);//读取A文件数据
- if(ret != DateNo)
- {
- TestResult(fpA);
- }
-
- Shan[512-1-1] = 0x55;// 写512最后两字字节
- Shan[512-1] = 0xaa;
-
-
- Floppy = MakeFloppy();
-
- if(False == WriteFloppy(0, 0, 1, Floppy, Shan))
- {
- printf("WriteFloppy Error!\n");
- free(Floppy);
- return 0;
- }
-
- if(False == WriteFloppy(0, 1, 4, Floppy, meg))
- {
- printf("WriteFloppy Error!\n");
- free(Floppy);
- return 0;
- }
-
- ret = fwrite(Floppy, 1, DateNo, fpB);//把缓冲文件写入到B文件中
- if(ret != DateNo)
- {
- TestResult(fpB);
- }
-
- if(0 != fclose(fpB) && 0 != fclose(fpA) )//关闭所有打开的文件
- {
- printf("fcloseall REEOR\n");
- }
- free(Floppy);
- return 0;
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "floppy.h"
-
- char * MakeFloppy(void)
- {
- char * pFloppy = NULL;
- pFloppy = (char *)malloc(2*80*18*512);
- if(NULL == pFloppy)
- {
- printf("malloc error!\n");
- }
- else
- {
- memset(pFloppy, 0, (2*80*18*512));
- }
-
- return pFloppy;
- }
-
- int CheckPara(char bSide, char bCidao, char bShanmian, char * pFloppy, char * pBuffe)
- {
- if(NULL != pFloppy && NULL != pBuffe)
- {
- if(0 == bSide || 1 == bSide)
- {
- if(bCidao <= 79 && bCidao >= 0)
- {
- if(bShanmian <= 18 && bShanmian >= 1)
- {
- return True;
- }
- }
- }
- }
- return False;
- }
- static void WriteFloppyShanZero(char * pFloppy, char * pBuffe)
- {
- int ShanNum = 512;
- int i = 0;
- for(i=0; i<ShanNum; i++)
- {
- *pFloppy = *pBuffe;
- pFloppy++;
- pBuffe++;
- }
- }
-
- static void WriteFloppyShanNotZero(char * pFloppy, char * pBuffe)
- {
- int ShanNum = 0;
- ShanNum = strlen(pBuffe);
- ShanNum = ShanNum/512;
- printf("we will write %d ShanQu\n", ShanNum+1);
- while(* pBuffe)
- {
- *pFloppy = *pBuffe;
- pFloppy++;
- pBuffe++;
- }
- }
-
- int WriteFloppy(char bSide, char bCidao, char bShanmian, char * pFloppy, char * pBuffe)
- {
- int LogicShanMian = 0;
- if(False == CheckPara(bSide, bCidao, bShanmian, pFloppy, pBuffe))
- {
- printf("Para error!\n");
- return False;
- }
-
- LogicShanMian = bSide * 18 + bCidao * 2 * 18 + (bShanmian - 1);
-
- pFloppy += LogicShanMian * 512;//把指针移动到第 LogicShanMian 个扇区开头
-
- if(0 == LogicShanMian)
- {
- WriteFloppyShanZero(pFloppy, pBuffe);//0 扇区写满
- }
- else
- {
- WriteFloppyShanNotZero(pFloppy, pBuffe);
- }
-
- return True;
- }
三、介绍如何使用汇编读取软盘中扇区的数据
通过调用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
然后调用中断,具体的程序如下所示:
- org 0x7c00;
-
- entry:
- mov ax, 0
- mov ss, ax
- mov ds, ax
- mov es, ax
- mov si, msg
-
-
- readFloppy:
- mov CH, 1 ;CH 用来存储磁道号
- mov DH, 0 ;DH 用来存储磁头号
- mov CL, 4 ;CL 用来存储扇区号
-
- mov BX, msg ; ES:BX 数据存储缓冲区
-
- mov AH, 0x02 ; AH = 02 表示要做的是读盘操作
- mov AL, 2 ; AL 表示要练习读取几个扇区
- mov DL, 0 ;驱动器编号,一般我们只有一个软盘驱动器,所以写死
- ;为0
- INT 0x13 ;调用BIOS中断实现磁盘读取功能
-
- jc error
-
- putloop:
- mov al, [si]
- add si, 1
- cmp al, 0
- je fin
- mov ah, 0x0e
- mov bx, 15
- int 0x10
- jmp putloop
-
-
-
- fin:
- HLT
- jmp fin
-
- error:
- mov si, errmsg
- jmp putloop
-
- msg:
- RESB 64
- errmsg:
- 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!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。