文章寫于兩年前的 MacBookAir(2015)
目前筆者為 MacBookPro M1 (抽查了部分 都運(yùn)行正常)
Github項(xiàng)目地址: https://github.com/wdkang123/MyOperatingSystem
MacOS X86架構(gòu)(x新版的arm架構(gòu)的我沒有 所以大家自行測試)
VirtualBox
C/C++環(huán)境 (Xcode必裝)
前文中我們將一段代碼通過軟盤加載到了系統(tǒng)內(nèi)存中 并指示cpu執(zhí)行加入到內(nèi)存的代碼
事實(shí)上,操作系統(tǒng)內(nèi)核加載也是這么做的。只不過我們加載的代碼,大只能512 byte, 一個操作系統(tǒng)內(nèi)核,少說也要幾百兆,由此,系統(tǒng)內(nèi)核不可能直接從軟盤讀入系統(tǒng)內(nèi)存
通常的做法是 被加載進(jìn) 內(nèi)存的512byte程序 實(shí)際上是一個內(nèi)核加載器 它運(yùn)行起來之后 通過讀取磁盤 將存儲在磁盤上的內(nèi)核代碼加載到指定的內(nèi)存結(jié)構(gòu)中去 然后在把cpu的控制權(quán)提交給加載進(jìn)來的系統(tǒng)內(nèi)核
硬盤的結(jié)構(gòu)
軟盤的物理結(jié)構(gòu)如上圖 一個盤面被劃分成若干個圓圈
例如圖中的灰色圓圈 我們稱之為磁道 也可以稱作柱面
一個磁道或柱面 又被分割成若干部分 每一部分 我們稱之為一個扇區(qū)
一個扇區(qū)的大小正好是512k
從而,當(dāng)我們把數(shù)據(jù)存儲到軟盤上時,數(shù)據(jù)會分解成若干個512Byte大小的塊,然后寫入到扇區(qū)里
2.模擬我們要模擬的是3.5寸軟盤 這種軟盤的特點(diǎn)是
它有兩個盤面 因此就對應(yīng)兩個磁頭 每個盤面有80個磁道 也就是柱面 編號分別為0-79 每個柱面都有18個扇區(qū) 編號分別為1-18 所以一個盤面可以存儲的數(shù)據(jù)量大小為:
512 * 18 * 80
一個軟盤有兩個盤面,因此一個軟盤可以存儲的數(shù)據(jù)為:
2 * 512 * 18 * 80 = 1474560 Byte = 1440 KB = 1.5M
接下來,我們用java來模擬一個3.5寸軟盤,以及它的讀寫邏輯
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 CYLINDER_COUNT = 80; //80個柱面
private int SECTORS_COUNT = 18;
private MAGNETIC_HEAD magneticHead = MAGNETIC_HEAD.MAGNETIC_HEAD_0;
private int current_cylinder = 0;
private int current_sector = 0;
private HashMap>>floppy = new HashMap>>(); //一個磁盤兩個面
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>initFloppyDisk() {ArrayList>floppyDisk = new ArrayList>(); //磁盤的一個面
//一個磁盤面有80個柱面
for(int i = 0; i< CYLINDER_COUNT; i++) {floppyDisk.add(initCylinder());
}
return floppyDisk;
}
private ArrayListinitCylinder() {//構(gòu)造一個柱面,一個柱面有18個扇區(qū)
ArrayListcylinder = new ArrayList();
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;
}
public 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到18
if (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>disk = floppy.get(this.magneticHead.ordinal());
ArrayListcylinder = 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>disk = floppy.get(this.magneticHead.ordinal());
ArrayListcylinder = disk.get(this.current_cylinder);
cylinder.set(this.current_sector, buf);
}
public void makeFloppy(String fileName) {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);
}
}
}
} catch (Exception e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
讀寫虛擬軟盤需要調(diào)用接口readFloppy 或 writeFloppy
使用這些接口時必須指定磁頭 柱面和扇區(qū)號
3.主程序在主程序中 我將上節(jié)用匯編編譯的操作系統(tǒng)內(nèi)核寫入到虛擬軟盤中 然后將虛擬軟盤寫成磁盤文件 具體代碼如下:
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) {//將內(nèi)核讀入到磁盤第0面,第0柱面,第1個扇區(qū)
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.bat");
op.makeFllopy();
}
}
4.匯編軟盤讀寫在前面,我們的內(nèi)核加載到內(nèi)存后,會打印出一條語句 而語句與內(nèi)核代碼都存儲在同一個扇區(qū)中
這一次,我們將要打印的語句存儲在第一柱面的第二扇區(qū),內(nèi)核加載如內(nèi)存后,通過BIOS調(diào)用將要打印的語句從指定位置讀出,然后再顯示到屏幕上,代碼如下:
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 18
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 用來存儲扇區(qū)號
mov BX, msg ; ES:BX 數(shù)據(jù)存儲緩沖區(qū)
mov AH, 0x02 ; AH = 02 表示要做的是讀盤操作
mov AL, 1 ; AL 表示要練習(xí)讀取幾個扇區(qū)
mov DL, 0 ;驅(qū)動器編號,一般我們只有一個軟盤驅(qū)動器,所以寫死
;為0
INT 0x13 ;調(diào)用BIOS中斷實(shí)現(xiàn)磁盤讀取功能
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 ;出現(xiàn)錯誤打印error
jmp putloop
msg:
RESB 64
errmsg:
DB "error"
將上面的代碼編譯一下
nasm boot_readstring_from_sector.asm -o boot.bat
在java代碼中進(jìn)行修改:
我們在生成虛擬軟盤的java代碼中把把要輸出的語句寫入到虛擬軟盤的1柱面,2扇區(qū)
這里 將 “This is a text from cylinder 1 and sector 2” 放在了軟盤的1柱面 2扇區(qū)
在匯編中 運(yùn)行時 對這個區(qū)域進(jìn)行讀取 并將內(nèi)容輸出到屏幕上
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");
}
運(yùn)行代碼 生成system.img
載入后運(yùn)行:
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧