参考:
https://blog.csdn.net/tyler_download/article/details/51815483
https://www.bilibili.com/video/BV1VJ41157wq?p=3&spm_id_from=pageDriver
模拟操作系统早期DOS时代的做法,操作系统内核写在软盘上,上两节有读取量的限制,最多将前512字节读取到内存中。
当操作系统大于512byte就不能这样了。改改思路,第一个扇区不再是内核本身,而是一个内核加载器。负责把操作系统内核从软盘读取到内存
Floppy.java
代码注释有些问题,应该是写完一个盘面,再写另外的盘面。
512×18×80×2=1474560bytes=1440KB=1.5M
OpSystem.java
重复上节的例子,这次是用Floppy类在写磁盘,更精准,比如在512字节末尾两个字节写上0x55aa
boot_helloworld.asm于上节boot.asm相同
nasm -o boot.bat boot_helloworld.asm
发现编译问题,原来从网页上copy下来不行,直接把boot.asm拷贝过来就行,应该是有不可见的错误字符。
运行效果也相同,virtualbox中显示hello world.
改为读盘的汇编:boot_readstring_from_sector.asm
运行发现sytem.img的大小有误:1474091,应该是1474560,差了469字节,应该是第二扇区的内容不足512,没有补充。需要修改一下代码:
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);
//cylinder.set(this.current_sector, buf);
byte[] buffer = cylinder.get(this.current_sector);
System.arraycopy(buf,0,buffer,0,buf.length);
}
重新运行system.img就正确了,大小1474560
按文中加载运行是一个黑屏,未读到文字,二进制查看已经写道磁盘上了,估计是写的顺序不对。修正了一下:柱面在外层,盘面在内层。
public void makeFloppy(String fileName) {
/**
* 虚拟软盘是一个纯粹的二进制文件
* 512×18 盘面0,柱面0
* 521×18 盘面1,柱面0
* 512×18 盘面0,柱面1
* 512×18 盘面1,柱面1
* 以此类推
*/
try {
DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
/*
for (int head = 0; head <= MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(); head++) {
for (int cylinder = 0; cylinder < CYLINDER_COUNT; cylinder++) {
for (int sector = 1; sector <= SECTORS_COUNT; sector++) {
byte[] buf = readFloppy(MAGNETIC_HEAD.values()[head], cylinder, sector);
out.write(buf);
}
}
}
*/
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 block
e.printStackTrace();
}
}
这样就可以运行了:
boot_helloworld.asm
org 0x7c00;
entry:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov si, msg
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
msg:
DB 0x0a,0x0a
DB "Hello,World"
DB 0x0a
DB 0
boot_readstring_from_sector.asm
org 0x7c00;
entry:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov si, msg
readFloppy:
mov CH, 1
mov DH, 0
mov CL, 2
mov BX, msg
mov AH, 0x02
mov AL, 1
mov DL, 0
int 0x13
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"
Floppy.java
package osfloppy;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
public class Floppy {
enum MAGNETIC_HEAD {
MAGNETIC_HEAD_0,
MAGETIC_HEAD_1
};
public int SECTOR_SIZE = 512;
private int SECTORS_COUNT = 18;
private int CYLINDER_COUNT = 80;
private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;
private int current_cylinder = 0;
private int current_sector = 0;
// 80*18*512
//一个磁盘两个面
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++) {
byte[] sector = new byte[SECTOR_SIZE];
cylinder.add(sector);
}
return cylinder;
}
public void setMagneticHead(MAGNETIC_HEAD head) {
this.magneticHead = head;
}
public void setCylinder(int cylinder) {
//80个柱面,磁道0-79
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到18
if (sector < 0) {
this.current_sector = 0;
} else if(sector > 18) {
this.current_sector = 17;
} 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);
//cylinder.set(this.current_sector, buf);
byte[] buffer = cylinder.get(this.current_sector);
System.arraycopy(buf,0,buffer,0,buf.length);
}
public void makeFloppy(String fileName) {
/**
* 虚拟软盘是一个纯粹的二进制文件
* 512×18 盘面0,柱面0
* 521×18 盘面1,柱面0
* 512×18 盘面0,柱面1
* 512×18 盘面1,柱面1
* 以此类推
*/
try {
DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
/*
for (int head = 0; head <= MAGNETIC_HEAD.MAGETIC_HEAD_1.ordinal(); head++) {
for (int cylinder = 0; cylinder < CYLINDER_COUNT; cylinder++) {
for (int sector = 1; sector <= SECTORS_COUNT; sector++) {
byte[] buf = readFloppy(MAGNETIC_HEAD.values()[head], cylinder, sector);
out.write(buf);
}
}
}
*/
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 block
e.printStackTrace();
}
}
}
OpSystem.java
package osfloppy;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class OpSystem {
private Floppy floppyDisk = new Floppy();
public OpSystem(String s) {
writeFileToFloppy(s);
}
private void writeFileToFloppy(String fileName) {
File file = new File(fileName);
InputStream in;
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 (Exception e) {
e.printStackTrace();
return;
}
}
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) {
OpSystem op = new OpSystem("boot.bat");
op.makeFllopy();
}
}