软盘读写
使用Java代码模拟出Floppy软盘:
package org.dreamtech;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class Floppy {
// 由于有两个盘面,于是有两个磁头
enum MAGNETIC_HEAD {
MAGNETIC_HEAD_0, MAGETIC_HEAD_1
};
// 每一个盘面有80个柱面
private int CYLINDER_COUNT = 80;
// 每一个柱面有18个扇区
private int SECTORS_COUNT = 18;
// 每一个扇区大小512字节
public int SECTOR_SIZE = 512;
// 默认设置第一个磁头
private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;
// 当前读取到的柱面
private int currentCylinder = 0;
// 当前读取到的扇区
private int currentSector = 0;
// 软盘可以定义成key为Integer,value为List<List<byte[]>>的HashMap
// Integer是两个盘面的表示
// byte[]表示一个扇区存储的内容
// List<byte[]>表示一个柱面存储的内容
// List<List<byte[]>>表示一个盘面所有的柱面存储的内容
private HashMap<Integer, ArrayList<ArrayList<byte[]>>> floppy = new HashMap<Integer, ArrayList<ArrayList<byte[]>>>();
public Floppy() {
initFloppy();
}
private void initFloppy() {
// 一个磁盘有两个盘面
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++) {
// 每个扇区先申请512字节的好内存
byte[] sector = new byte[SECTOR_SIZE];
cylinder.add(sector);
}
return cylinder;
}
// 设置读的盘面
public void setMagneticHead(MAGNETIC_HEAD head) {
magneticHead = head;
}
// 设置读的柱面
public void setCylinder(int cylinder) {
if (cylinder < 0) {
this.currentCylinder = 0;
} else if (cylinder >= 80) {
this.currentCylinder = 79;
} else {
this.currentCylinder = cylinder;
}
}
// 设置读的扇区
public void setSector(int sector) {
if (sector < 0) {
this.currentSector = 0;
} else if (sector > 18) {
this.currentSector = 18 - 1;
} else {
this.currentSector = sector - 1;
}
}
// 读磁盘的方法需要设置盘面柱面和扇区号
public byte[] readFloppy(MAGNETIC_HEAD head, int cylinderNum, int sectorNum) {
setMagneticHead(head);
setCylinder(cylinderNum);
setSector(sectorNum);
ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
ArrayList<byte[]> cylinder = disk.get(this.currentCylinder);
byte[] sector = cylinder.get(this.currentSector);
return sector;
}
// 写磁盘的方法需要设置盘面柱面和扇区号以及数据
public void writeFloppy(MAGNETIC_HEAD head, int cylinderNum, int sectorNum, byte[] buf) {
setMagneticHead(head);
setCylinder(cylinderNum);
setSector(sectorNum);
ArrayList<ArrayList<byte[]>> disk = floppy.get(this.magneticHead.ordinal());
ArrayList<byte[]> cylinder = disk.get(this.currentCylinder);
byte[] buffer = cylinder.get(this.currentSector);
System.arraycopy(buf, 0, buffer, 0, buf.length);
}
public void makeFloppy(String fileName) {
DataOutputStream out = null;
try {
// 虚拟软盘是存粹的二进制文件,它的逻辑结构如下:
// 前512*18 字节的内容对应盘面0,柱面0的所有扇区内容
// 接着的512*18字节的内容对应盘面1,柱面0的所有扇区内容
// 再接着的512*18字节的内容对应盘面0,柱面1所有扇区内容
// 再接着512*18字节的内容对应盘面1,柱面1所有扇区内容
// 以此类推
// 简单理解就是柱面一正一反来写
// 计算得出最终一个磁盘可以写1440KB的数据
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) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
将上节课的汇编代码编译后的二进制文件写入软盘:
package org.dreamtech;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
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];
// Intel的CPU规定必须在第511-512字节写入0x55aa
buf[510] = (byte) 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;
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public OperatingSystem(String s) {
writeFileToFloppy(s);
}
public void makeFllopy() {
floppyDisk.makeFloppy("system.img");
}
public static void main(String[] args) {
OperatingSystem op = new OperatingSystem("boot.bat");
op.makeFllopy();
}
}
生成的system.img被成功加载并启动
使用Java实现软盘读写并不是正确的方案,下面采用汇编来实现:
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, 2 ;CL用来存储扇区号
mov BX, msg ;ES:BX数据存储缓冲区,是INT 0x13中断需要的参数
;BX寄存器里面保存的是msg的地址
mov AH, 0x02 ;AH=2表示要做的是读盘操作
mov AL, 1 ;AL表示要连续读取几个扇区
mov DL, 0 ;驱动器编号(一般我们只有一个软盘驱动器,所以写死为0)
INT 0x13 ;调用BIOS中断实现磁盘读取功能
;效果是是将读取到的数据写入msg地址
jc error ;如果读盘出现错误,就执行error处的代码
;如果BIOS调用出错,FLAGS寄存器的CF位会置1,同时把错误代码写入AH
;如果BIOS调用没错,FLAGS寄存器的CF位会置0
;所以这里类似if(FLAGS.CF==1){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 ;申请64字节的地址(从当前的地址开始空出64字节)
errmsg:
DB "error"
进行编译:nasm -o boot.bat boot_readstring_from_sector.asm
修改Java代码并执行:
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");
}
加载到虚拟机,成功打印代码中的这段话