模拟软盘的读写,将上节汇编生成的boot.bin的二进制代码写入到虚拟软盘中,然后将虚拟软盘写成磁盘文件system.img中,并用虚拟机运行

在前两节,我们将一段代码通过软盘加载到了系统内存中,并指示cpu执行加入到内存的代码。

事实上,操作系统内核加载也是这么做的。

现在我们windows操作系统,操作系统内核都会安装在硬盘上(在系统盘C盘上存储)。机器上电之后,会从硬盘上将操作系统内核读取到内存中,再执行。

而我们现在做的这个项目是将操作系统内核写在软盘上,机器上电之后,我们会指示硬件从软盘中将我们的系统内核加载到内存中。

在早期win95以前或者是DOS,要安装操作系统的话,需要将很多快软盘插入到机器中,让我们机器从软盘中读取内容才能去安装操作系统,后来硬盘普及了之后操作系统才安装在硬盘上的。我们现在就是在模拟操作操作系统的加载方式

只不过我们加载的代码,最大只能512 byte, 一个操作系统内核,少说也要几百兆,由此,系统内核不可能直接从软盘读入系统内存。通常的做法是,被加载进内存的512 Byte程序,实际上是一个内核加载器,它运行起来后,通过读取磁盘,将存储在磁盘上的内核代码加载到指定的内存空间,然后再把cpu的控制权提交给加载进来的系统内核。

软盘结构

软盘的物理结构如上图,一个盘面被划分成若干个圆圈,例如图中的灰色圆圈,我们称之为磁道,也可以称作柱面,一个磁道或柱面,又被分割成若干部分,每一部分,我们称之为一个扇区,一个扇区的大小正好是512k,从而,当我们把数据存储到软盘上时,数据会分解成若干个512Byte大小的块,然后写入到扇区里。

要读取数据时,磁头会挪动到扇区所在的磁道或柱面,然后盘面转动,当要读取的扇区转到磁头正下方时,磁头通电,通过电磁效应将扇区的数据读取到内存中。

从上图的左边图形可以了解,一个磁盘有两个盘面,每个盘面的组成跟右边图形一样,同时每个盘面对应一个磁头,所以当想从磁盘上读取数据时,需要确定数据在哪一个盘面,从而确定要用哪一个磁头来读取数据,然后确定哪一个磁道,最后再确定要读取的数据都存储在哪一个扇区。

对于我们要开发的系统,我们要模拟的是3.5寸软盘,这种软盘的特点是,它有两个盘面,因此就对应两个磁头,每个盘面有80个磁道,也就是柱面,编号分别为0-79. 每个柱面都有18个扇区,编号分别为1-18. 所以一个盘面可以存储的数据量大小为:
512 * 18 * 80
一个软盘有两个盘面,因此一个软盘可以存储的数据为:
2 * 512 * 18 * 80 = 1474560 Byte = 1440 KB = 1.5M

接下来,我们用java来模拟一个3.5寸软盘,以及它的读写逻辑。

实现

Floppy.java 用于实现虚拟软盘

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;public class Floppy {enum MAGNETIC_HEAD {//磁头编号0对应着上面的磁头(读上盘面),1对应着下面的磁头(读下盘面)MAGNETIC_HEAD_0,MAGETIC_HEAD_1};public int SECTOR_SIZE = 512;//1个扇区存储容量大小是512字节private int CYLINDER_COUNT = 80; //80个柱面private int SECTORS_COUNT = 18;//每个柱面都有18个扇区,也就是1个圆圈含有18个扇形private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;private int current_cylinder = 0;private int current_sector = 0;//HashMap来模拟整个盘片//byte[] 对应一个扇区//ArrayList对应一个磁道,或者叫一个柱面   一个ArrayList含有18个byte[]//外层的ArrayList含有80个里面的子ArrayListprivate HashMap<Integer,ArrayList<ArrayList<byte[]>> > floppy = new HashMap<Integer,ArrayList<ArrayList<byte[]>> >(); //一个磁盘两个面public Floppy() {//初始化initFloppy();}private void initFloppy() {//一个磁盘有两个盘面//初始化两个盘面,将2个盘面加入到floppy Hashmap中floppy.put(MAGNETIC_HEAD.MAGNETIC_HEAD_0.ordinal(), initFloppyDisk());floppy.put(MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(), initFloppyDisk());}//初始化盘面private ArrayList<ArrayList<byte[]>> initFloppyDisk() {ArrayList<ArrayList<byte[]>> floppyDisk = new ArrayList<ArrayList<byte[]>>(); //磁盘的一个面//一个磁盘面有80个柱面for(int i = 0; i < CYLINDER_COUNT; i++) {floppyDisk.add(initCylinder());}return floppyDisk;}private ArrayList<byte[]> initCylinder() {//构造一个柱面,一个柱面有18个扇区ArrayList<byte[]> cylinder = new ArrayList<byte[]> ();for (int i = 0; i < SECTORS_COUNT; i++) {byte[] sector = new byte[SECTOR_SIZE];cylinder.add(sector);}return cylinder;}//读写的时候首先要确定磁头,即确定要读取的盘面是上面还是下面public void setMagneticHead(MAGNETIC_HEAD head) {magneticHead = head;}//设置磁道编号0-79public void setCylinder(int cylinder) {if (cylinder < 0) {this.current_cylinder = 0;}else if (cylinder >= 80) {this.current_cylinder = 79;}else {this.current_cylinder = cylinder;}}//确定要访问的扇区编号public void setSector(int sector) {//sector 编号从1到18if (sector < 0) {this.current_sector = 0;}else if (sector > 18) {this.current_sector = 18 - 1;}else {this.current_sector = sector - 1;}}//读扇区public byte[] readFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num) {setMagneticHead(head);setCylinder(cylinder_num);setSector(sector_num);ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());ArrayList<byte[]> cylinder = disk.get(this.current_cylinder);byte[] sector = cylinder.get(this.current_sector);return sector;}//写扇区public void writeFloppy(MAGNETIC_HEAD head, int cylinder_num, int sector_num, byte[] buf) {setMagneticHead(head);setCylinder(cylinder_num);setSector(sector_num);ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());ArrayList<byte[]> cylinder = disk.get(this.current_cylinder);byte[] buffer = cylinder.get(this.current_sector);System.arraycopy(buf, 0, buffer, 0, buf.length);}public void makeFloppy(String fileName) {try {/*虚拟软盘是二进制文件前512*18字节的内容对应盘面0,柱面0的所有扇区内容接着的512*18字节对应盘面1,柱面0的所有扇区内容再接着的512*18字节对应盘面0,柱面1的所有扇区内容再接着的512*18字节对应盘面1,柱面1的所有扇区内容以此类推*/DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));for (int cylinder = 0; cylinder < CYLINDER_COUNT; cylinder++) {for (int head = 0; head <= MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(); head++) {for (int sector = 1; sector <= SECTORS_COUNT; sector++) {byte[] buf = readFloppy(MAGNETIC_HEAD.values()[head], cylinder, sector);out.write(buf);}}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

OperatingSystem.java将上节用汇编编译的操作系统内核写入到虚拟软盘中,然后将虚拟软盘写成磁盘文件

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;public class OperatingSystem {private Floppy floppyDisk = new Floppy();private void writeFileToFloppy(String fileName) {File file = new File(fileName);InputStream in = null;try {in = new FileInputStream(file);byte[] buf = new byte[512];buf[510] = 0x55;buf[511] = (byte) 0xaa;if (in.read(buf) != -1) {//将内核读入到磁盘第0面,第0柱面,第1个扇区floppyDisk.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0, 0, 1, buf);}} catch(IOException e) {e.printStackTrace();return;}}public OperatingSystem(String s) {writeFileToFloppy(s);}public void makeFllopy()   {floppyDisk.makeFloppy("system.img");}public static void main(String[] args) {OperatingSystem op = new OperatingSystem("boot.bin");op.makeFllopy();}
}

用virtualbox运行system.img

下面是怎样读取软盘

用汇编语言实现软盘的读写

Java代码先把要打印的字段写入到虚拟软盘的某个位置

然后我们用汇编写的操作系统内核从软盘的指定位置把要打印的内容读出来,显示到屏幕上

boot_readstring_from_floppy.asm

org  0x7c00;jmp  entry
db   0x90
DB   "OSKERNEL"
DW   512
DB   1
DW   1
DB   2
DW   224
DW   2880
DB   0xf0
DW   9
DW   18
DW   2
DD   0
DD   2880
DB   0,0,0x29
DD   0xFFFFFFFF
DB   "MYFIRSTOS  "
DB   "FAT12   "
RESB  18entry:mov  ax, 0mov  ss, axmov  ds, axmov  es, axmov  si, msgreadFloppy:mov  CH, 1        ;CH 用来存储柱面号mov  DH, 0        ;DH 用来存储磁头号mov  CL, 2        ;CL 用来存储扇区号mov  BX, msg       ;ES:BX 数据存储缓冲区;BX存储读取的512字节的内容mov  AH, 0x02      ;AH=02 表示要做的是读盘操作mov  AL, 1        ;AL 表示要连续读取几个扇区mov  DL, 0         ;驱动器编号,一般我们只有一个软盘驱动器,所以写死,为0;早年有一些机器可以同时插入多个软盘INT  0x13          ;调用BIOS中断实现磁盘读取功能jc   error         ;如果读盘出现错误,跳转到error处执行响应代码;将缓冲区里面的字符打印到屏幕上
putloop:mov  al, [si]add  si, 1cmp  al, 0je   finmov  ah, 0x0emov  bx, 15int  0x10jmp  putloopfin:HLTjmp  finerror:mov si, errmsg   ;出现错误打印errorjmp  putloopmsg:RESB   64
errmsg:DB "error"

用nasm将boot_readstring_from_floppy.asm编译成boot.bin

此时修改Java代码

以前

现在

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;public class OperatingSystem {private Floppy floppyDisk = new Floppy();private void writeFileToFloppy(String fileName) {File file = new File(fileName);InputStream in = null;try {in = new FileInputStream(file);byte[] buf = new byte[512];buf[510] = 0x55;buf[511] = (byte) 0xaa;if (in.read(buf) != -1) {//将内核读入到磁盘第0面,第0柱面,第1个扇区floppyDisk.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0, 0, 1, buf);}} catch(IOException e) {e.printStackTrace();return;}}public OperatingSystem(String s) {writeFileToFloppy(s);}public void makeFllopy()   {String s = "This is a text from cylinder 1 and sector 2";floppyDisk.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0,1,2,s.getBytes());floppyDisk.makeFloppy("system.img");}public static void main(String[] args) {OperatingSystem op = new OperatingSystem("boot.bin");op.makeFllopy();}
}

这次我们要打印的语句,不再写死到内核里面了,而是通过代码写入到磁盘的第0盘面(磁头0),第一柱面的第二扇区
操作系统内核从这个位置把要打印的字符串的内容读取出来,最后打印到屏幕上

Java代码的作用

①将这句话写在软盘里

This is a text from cylinder 1 and sector 2

②将汇编语言写的操作系统内核写到软盘里

运行结果

参考:

https://blog.csdn.net/tyler_download/article/details/51815483

MyOS(三):软盘读写相关推荐

  1. linux dd命令制作软盘,[Ubuntu]dd 命令,软盘读写实例:二进制文件.bin -镜像文件 .img - 软盘设备 /dev/fd0...

    本文将利用linux的dd命令往软盘的0道0面1扇区(即主引导扇区)写入数据: 实现在屏幕上显示asm这个三个字符的功能: 由于Ubuntu系统以软盘(floppy disk)作为启动盘,当选择系统从 ...

  2. 新视野大学英语第三版读写教程2答案

    新视野大学英语第三版读写教程2答案 链接:https://pan.baidu.com/s/1Vx4pIwG-bfGZXFqxg_OaIw 提取码:kncm 这份文档找的不太容易,能不能打赏一下.点个赞 ...

  3. Hadoop(三)读写流程

    Remote Procedure Call RPC--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP, ...

  4. 分布式数据库中间件的实现原理介绍三:读写分离

    声明:本文并非原创,转自华为云帮助中心的分布式数据库中间件(DDM)服务的产品介绍. 数据库中对计算和缓存资源消耗较多的往往是密集或复杂的SQL查询.当系统资源被查询语句消耗,反过来会影响数据写入操作 ...

  5. 缓存常用的三种读写策略==》Write Behind Pattern(异步缓存写入)

    Write Behind Pattern(异步缓存写入) Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 ...

  6. STM32 Cubemax(三)——时序读写完成称重传感器+HX711的使用

    STM32称重传感器+HX711的使用--HAL库 文章目录 STM32称重传感器+HX711的使用--HAL库 前言 一.接线 二.CubeMax配置 三.代码编写 注意点 前言 因为在一个项目中使 ...

  7. 新视野大学英语第三版读写教程(四)Unite 4 Midterm test answer

                                          注意了:仅对校对答案作参考,请勿走捷径,成功路上没有捷径哈!                                 ...

  8. linux 汇编 读取软盘,[Linux]dd 读写软盘:在软盘主引导扇区写入显示hello world的二进制代码数据...

    代码效果 在软盘主引导扇区写入显示 hello world 的二进制代码数据 命令行操作 第一步,格式化软盘,/dev/fd0是软盘的名字 $ sudo fdformat /dev/fd0 $ sud ...

  9. bios x86保护模式下的软盘操作floppy

    Cpu启动时,如果在bios中设置了从软盘启动,则bios会自动把软盘的第一个扇区(512字节)搬移到0x7c00,然后会从0x7c00开始运行,我们需要在这512字节的程序中实现把boot从软盘中搬 ...

最新文章

  1. 蛋白对接_【分子对接教程】蛋白/核酸/多肽-小分子对接(DOCK 6.9)
  2. 蛋花花简单阐述HTML5和Web前端的区别
  3. websocket规范 RFC6455 中文版
  4. 成功解决AttributeError: module ‘tensorflow‘ has no attribute ‘get_variable‘
  5. SpringMVC 基于注解的Controller详解
  6. uva1331三角剖分
  7. C#语法——await与async的正确打开方式
  8. POJ 2847 Widget Factory
  9. vscode快捷键的修改
  10. 详解EMC测试国家标准GB/T 17626
  11. Python基于Snap7与PLC建立连接并读写数据
  12. 常用名词理解(APK,SDK,JDK,API,DLL)
  13. 打开客户端出现 sorry this application cannot run under a virtual machine错误
  14. godaddy无法修改域名服务器,godaddy的DNS A记录不能修改原因
  15. Redis Hget 命令
  16. 《中华大字库2012》ttf字库字体样张总汇
  17. JS的迭代器和可迭代对象详解
  18. Win10截图和草图无法使用怎么办
  19. 从java代码到网络编程
  20. C语言练习——提高篇

热门文章

  1. 轻松搞定分组报表中的各种排序
  2. html5网页录音和语音识别
  3. 共享文件夹服务器内存资源不足,『excel文件打开就提示可用资源不足,无法完成此任务』共享文件夹怎么设置...
  4. DR钻戒能给“真爱”定价,但难救股价
  5. 聊聊并发编程的12种业务场景
  6. 最近知识的总结与复习
  7. Sparql查询RDF
  8. 独立开发变现周刊(第81期):开发一个应用来减少屏幕使用时间,月收入2万美元...
  9. EffectiveC++详解:条款05-了解C++默默编写并调用哪些函数
  10. 关于spring IoC 学习