我們當(dāng)前的系統(tǒng)內(nèi)核媒熊,必須包含在虛擬軟盤的第1扇區(qū)奇适,由于一個(gè)扇區(qū)只有512字節(jié),因此芦鳍,系統(tǒng)內(nèi)核的大小不可能超過512字節(jié)嚷往。但是,一個(gè)擁有完善功能的內(nèi)核不可能只有512字節(jié)柠衅,因此要想越過512字節(jié)的限制皮仁,具體的做法就是做一個(gè)內(nèi)核加載器,放入到第一扇區(qū)菲宴,加載器加載如內(nèi)存后贷祈,再將內(nèi)核從軟盤加載到系統(tǒng)內(nèi)存,然后喝峦,跳轉(zhuǎn)到內(nèi)核的加載地址势誊。假定我們把編譯好的內(nèi)核代碼寫入軟盤的第1柱面,第2扇區(qū)谣蠢,那么加載器的代碼如下粟耻,boot.asm:
org 0x7c00;
LOAD_ADDR EQU 0X8000
entry:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov si, ax
readFloppy:
mov CH, 1 ;CH 用來存儲柱面號
mov DH, 0 ;DH 用來存儲磁頭號
mov CL, 2 ;CL 用來存儲扇區(qū)號
mov BX, LOAD_ADDR ; ES:BX 數(shù)據(jù)存儲緩沖區(qū)
mov AH, 0x02 ; AH = 02 表示要做的是讀盤操作
mov AL, 1 ; AL 表示要練習(xí)讀取幾個(gè)扇區(qū)
mov DL, 0 ;驅(qū)動器編號,一般我們只有一個(gè)軟盤驅(qū)動器眉踱,所以寫死
;為0
INT 0x13 ;調(diào)用BIOS中斷實(shí)現(xiàn)磁盤讀取功能
JC fin
jmp LOAD_ADDR
fin:
HLT
jmp fin
readFloppy 這段代碼從軟盤的1柱面挤忙,2扇區(qū),將內(nèi)核讀取到系統(tǒng)內(nèi)存的0x8000處勋锤,讀取成功后饭玲,通過一個(gè)jmp 跳轉(zhuǎn)到內(nèi)核的加載地址,將機(jī)器的控制權(quán)轉(zhuǎn)交給內(nèi)核叁执。我們看看內(nèi)核代碼,kernel.asm:
org 0x8000
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 "This is Hello World from kernel"
我們的內(nèi)核很簡單茄厘,只不過打印出一條語句.
通過命令分別編譯內(nèi)核和加載器: nasm kernel.asm -o kernerl.bat nasm boot.asm -o boot.bat
編譯好后矮冬,通過以下的java代碼先將編譯好的內(nèi)核寫入虛擬軟盤:
public void makeFllopy() {
writeFileToFloppy("kernel.bat", false, 1, 2);
floppyDisk.makeFloppy("system.img");
}
上面的代碼先將編譯好的kernel.bat寫入按軟盤的1柱面,2扇區(qū)次哈,然后生成虛擬軟盤文件:system.img.
最后胎署,我們將虛擬軟件加載到虛擬機(jī)中,就可以看到如下效果:
如果內(nèi)核大小超過512字節(jié)窑滞,我只要在加載器中多讀取幾個(gè)扇區(qū)琼牧,就可以將內(nèi)核加載進(jìn)系統(tǒng)內(nèi)存了,由此哀卫,通過內(nèi)核加載器這個(gè)二傳手巨坊,我們能夠有效的突破512字節(jié)的大小限制,今后我們在內(nèi)核中添加各種操作系統(tǒng)功能時(shí)此改,系統(tǒng)內(nèi)核肯定是遠(yuǎn)遠(yuǎn)不止512字節(jié)的趾撵。
本節(jié)代碼可以通過以下命令下載:
git clone https://github.com/wycl16514/OS-Kernel-from-loader-to-kernel.git
在下一節(jié),我們將實(shí)現(xiàn)新的突破共啃,看看內(nèi)核如何由時(shí)模式進(jìn)入保護(hù)模式占调,也就是讓內(nèi)核從dos級別轉(zhuǎn)變?yōu)閣in95級別。