自己动手写操作系统: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

#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;  
} 

下面是创建软盘印象文件的具体实现程序floppy.c :
#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!




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值