這一次的學習至關曲折, 主要是由於粗心, Makefile裏面的錯誤致使了文件生成出現各類奇奇怪怪的問題, 弄得心力交瘁, 所以製做過程仍是儘可能按着做者的路子來吧. vim
做者提供的源碼的註釋在中文系統下是亂碼, 並且代碼的分隔用了兩個Tab, 在這裏要處理一下: 緩存
:%s/;.*//g 刪除全部的註釋; 函數
:%s/\t\t/\t 把兩個Tab替換爲一個Tab; 工具
要讓做者的nas文件和asm文件擁有相同的語法規則, 在_vimrc文件的最後一行添加 oop
au BufNewFile,BufRead *.nas set filetype=asm 學習
以前咱們寫的只是軟盤啓動區代碼, 全部代碼只能放在512字節裏, 根本不夠用, ui
因此咱們要利用這一段代碼讀入軟盤的其餘內容, 並將控制權移交給它, 因此叫作IPL(Initial Program Loader). spa
int 0x13 磁盤中斷 設計
AH = 0x02 ; 讀盤 code
AH = 0x03 ; 寫盤
AH = 0x04 ; 校驗
AH = 0x0c ; 尋道
AH = 0x00 ;大概是重置磁盤, 配合DH = 0x00 使用
AL = 連續處理的扇區數
CH = 柱面號
CL = 扇區號
DH = 磁頭號
DL = 驅動器號
ES:BX = 緩衝地址, 尋道及校驗不使用
C = 0 沒有錯誤, AH = 0;
C = 1 錯誤號碼存入AH.
這裏只會用到0x02和0x00.
軟盤的結構:
用柱面(C)-磁頭(H)-扇區(S) 來標識軟盤上的扇區, 咱們的啓動扇區的標號是C0-H0-S1, 值得注意的是下一個扇區是C0-H0-S2, 這個例子裏做者要讀入10個柱面, 從C0-H0-S1 讀到 C9-H1-S18, 這樣算來應該是18*2*10 = 360 個扇區, 大小是360*512/1024 = 180 KB, 從咱們如今小的可憐的需求看來, 180KB絕對夠了.(按這樣算的話不是一個柱面有36個扇區嗎? 此處不解).
如下的代碼能將軟盤除啓動區外開始的180KB的空間讀入內存中, 起始地址是0x8200, 佔用的空間是0x2d000.
編寫Haribote.nas文件以下, 結構很簡單:
1 fin: 2 HLT 3 JMP fin
問題是如何把編譯好的程序和IPL結合在一塊兒?
咱們能夠先編譯好IPL, 和以前同樣作成一個img, 而後把程序寫入img.
最直觀的方法是把img文件寫入U盤, 把程序寫入U盤, 再把U盤打包成img,
雖然有些迂迴, 可是咱們能夠藉助WinHex來直接寫入, 用WinHex直接打開做者作好的Haribote.img ,能夠發現它的內部格式以下:
發現Haribote.SYS處在0x4200的位置處 , 這是否是真的Haribote.sys?
也從Winhex裏面打開Hraibote.sys:
只有一句, F4 EB FD, 和img文件0x4200處的徹底同樣, 和做者的總結同樣:
向一個空軟盤保存文件的時候,
1.文件名會寫在0x2600之後的地方(這裏我沒有去驗證);
2.文件的內容會寫入到0x4200之後的地方.
非空軟盤的狀況沒有考慮(這裏開始咱們就真正意義上使用了FAT12的文件系統了, 而不是本身設計一個文件系統).
知道了這個咱們就能夠知道怎麼調用這個程序了, 使用做者提供的edimg.exe 能夠方便地將程序寫入到img中, 因此Makefile也要作相應的改動, 具體看Project文件夾day3裏面的e文件夾.
這個Haribote.nas 所作的只是不斷HLT, 咱們並不知道這段代碼是否真的執行, 做者這裏使用了0x10來切換畫面模式, 使得光標消失,
參數是AL = 0x13, AH = 0x00, 效果是屏幕全黑, 連光標也不能看到.
我這裏採用的是0x10中斷的另外一個功能, 可以顯示帶顏色的字符串, 代碼以下:
1 ; Program 2 ORG 0xc200 ; 加載到 0x8200 + 0x4200 – 0x200(啓動區沒有被讀入) 3 MOV AX,0 4 MOV ES,AX 5 MOV AX,loaded 6 MOV BP,AX ; ES:BP = 串地址 7 MOV CX,10 ; 串長度 8 MOV AX,0x1301 ;AH = 0x13,AL = 0x01 9 MOV BX,0x000b ; 頁號BH = 0 黑底藍字 BL = 0x0b 10 MOV DL,0 11 INT 0x10 12 JMP fin 13 loaded: 14 DB 0x0a, 0x0a 15 DB "Loaded." 16 DB 0x0a 17 DB 0 18 19 fin: 20 HLT 21 JMP fin
效果以下, 能夠肯定咱們Haribote.sys裏面的代碼已經被執行.
這裏做者開始用咱們看不懂的東西了, 給出了一個長長的asmhead.nas, 而且表示"先跳過這一部分", 讓我有點不爽, 可是畢竟不能半途而廢不是? 這裏的Makefile變得愈來愈複雜, 在這裏我第一次碰到了困難, 因爲粗心Makefile寫少了幾行, 致使編譯莫名其妙地出錯, 糾結了兩天才發現, 抄代碼都能抄錯 = =, 廢話略過, 做者還增長了一個Bootpack.c 大概就是咱們之後的主戰場了, 這裏編譯過程異常繁瑣(做者啊你可不能夠不要用你本身寫的工具!? (╯‵□′)╯︵┻━┻),
以上全部的工具都是川和先生寫的或者改寫的(╯‵□′)╯︵┻━┻.
須要強調的是HariMain這個Main函數的函數名已經寫死了, 不可以更換, 爲了在C
語言裏面使用HLT, (事實上如今C語言裏面根本就沒有函數可用), 增長naskfunc.nas.
全部文件均以下:
IPL.nas:
; hello-os ; TAB=4 ; const CYLS EQU 10 ORG 0x7c00 JMP entry DB 0x90 DB "OS 0.01 " 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 "OS ver 0.01" DB "FAT12 " RESB 18 entry: MOV AX,0 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV AX,0x0820 ; 緩存位置 = ES:BX MOV ES,AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁頭0 MOV CL,2 ; 扇區2 readloop: MOV SI,0 ; 記錄失敗次數 retry: MOV AH,0x02 ; 讀盤 MOV AL,1 ; 一個扇區 MOV BX,0 MOV DL,0x00 ; 驅動器A: INT 0x13 ; 調用磁盤中斷 JNC next ADD SI,1 CMP SI,5 ; 失敗5次跳出 JAE error MOV AH,0x00 MOV DL,0x00 ; 指定驅動器A: INT 0x13 ; 重置並重試 JMP retry
next: MOV AX,ES ADD AX,0x0020 MOV ES,AX ; 段寄存器日後移0x0020 實際偏移 0x0020*0x0010 = 0x0200 = 512d ADD CL,1 CMP CL,18 ; 讀到18扇區 JBE readloop; <= 則跳 MOV CL,1 ADD DH,1 ; 換一個磁頭 CMP DH,2 JB readloop; <則跳 MOV DH,0 ADD CH,1 ; 柱面+1 CMP CH,CYLS JB readloop MOV [0x0ff0],CH JMP 0xc200 error: ; 錯誤提示 MOV AX,0 MOV ES,AX MOV AX,msg MOV BP,AX ; ES:BP = 串地址 MOV CX,14 ; 串長度 MOV AX,0x1301 ;AH = 0x13,AL = 0x01 MOV BX,0x000c ; 頁號BH = 0 黑底紅字 BL = 0x0c MOV DL,0 INT 0x10 fin: HLT JMP fin msg: DB 0x0a, 0x0a DB "Load error." DB 0x0a DB 0 RESB 0x7dfe-$ DB 0x55, 0xaa
Asmhead.nas:
BOTPAK EQU 0x00280000 DSKCAC EQU 0x00100000 DSKCAC0 EQU 0x00008000 CYLS EQU 0x0ff0 ; 設定啓動區 LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 關於顏色數目的信息,顏色的位數 SCRNX EQU 0x0ff4 ; 分辨率 X(Screen X) SCRNY EQU 0x0ff6 ; 分辨率 Y(Screen Y) VRAM EQU 0x0ff8 ; 圖像緩衝區的起始地址 ORG 0xc200 MOV AL,0x13 ; VGA 顯卡 MOV AH,0x00 INT 0x10
MOV BYTE [VMODE],8 ; 記錄畫面模式 MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000 ; 取得鍵盤上的LED燈的狀態 MOV AH,0x02 INT 0x16 MOV [LEDS],AL MOV AL,0xff OUT 0x21,AL NOP OUT 0xa1,AL CLI CALL waitkbdout MOV AL,0xd1 OUT 0x64,AL CALL waitkbdout MOV AL,0xdf OUT 0x60,AL CALL waitkbdout [INSTRSET "i486p"] LGDT [GDTR0] MOV EAX,CR0 AND EAX,0x7fffffff OR EAX,0x00000001 MOV CR0,EAX JMP pipelineflush pipelineflush: MOV AX,1*8 MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX MOV SS,AX MOV ESI,bootpack MOV EDI,BOTPAK MOV ECX,512*1024/4 CALL memcpy MOV ESI,0x7c00 MOV EDI,DSKCAC MOV ECX,512/4 CALL memcpy MOV ESI,DSKCAC0+512 MOV EDI,DSKCAC+512 MOV ECX,0 MOV CL,BYTE [CYLS] IMUL ECX,512*18*2/4 SUB ECX,512/4 CALL memcpy MOV EBX,BOTPAK MOV ECX,[EBX+16] ADD ECX,3 SHR ECX,2 JZ skip MOV ESI,[EBX+20] ADD ESI,EBX MOV EDI,[EBX+12] CALL memcpy skip: MOV ESP,[EBX+12] JMP DWORD 2*8:0x0000001b waitkbdout: IN AL,0x64 AND AL,0x02 JNZ waitkbdout RET memcpy: MOV EAX,[ESI] ADD ESI,4 MOV [EDI],EAX ADD EDI,4 SUB ECX,1 JNZ memcpy RET ALIGNB 16 GDT0: RESB 8 DW 0xffff,0x0000,0x9200,0x00cf DW 0xffff,0x0000,0x9a28,0x0047 DW 0 GDTR0: DW 8*3-1 DD GDT0 ALIGNB 16
bootpack.c:
void io_hlt(void); void HariMain(void) { fin: io_hlt(); goto fin; }
Naskkfunc.nas:
;naskfunc [FORMAT "WCOFF"] ; 製做目標文件的模式 [BITS 32] ; 製做32位模式用的機械語言 ; 製做目標文件的信息 [FILE "naskfunc.nas"] ; 源文件名信息 GLOBAL _io_hlt ; 程序中包含的函數名 ; 實際的函數 [SECTION .text] ; _io_hlt: HLT RET
void io_hlt(void); void HariMain(void) { fin: io_hlt(); goto fin; }
萬惡的Makefile:
TOOLPATH = ../z_tools/ INCPATH = ../z_tools/haribote/ MAKE = $(TOOLPATH)make.exe -r NASK = $(TOOLPATH)nask.exe CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet GAS2NASK = $(TOOLPATH)gas2nask.exe -a OBJ2BIM = $(TOOLPATH)obj2bim.exe BIM2HRB = $(TOOLPATH)bim2hrb.exe RULEFILE = $(TOOLPATH)haribote/haribote.rul EDIMG = $(TOOLPATH)edimg.exe DEL = del SHORTCUT = "D:\Program Files\Oracle\VirtualBox\VirtualBox.exe" --comment "OS1" --startvm "a5c4b0e6-e142-4720-98ee-056911204b29" default : $(MAKE) install $(MAKE) run $(MAKE) clean ipl10.bin : ipl10.nas Makefile $(NASK) ipl10.nas ipl10.bin ipl10.lst asmhead.bin : asmhead.nas Makefile $(NASK) asmhead.nas asmhead.bin asmhead.lst bootpack.gas : bootpack.c Makefile $(CC1) -o bootpack.gas bootpack.c bootpack.nas : bootpack.gas Makefile $(GAS2NASK) bootpack.gas bootpack.nas bootpack.obj : bootpack.nas Makefile $(NASK) bootpack.nas bootpack.obj bootpack.lst naskfunc.obj : naskfunc.nas Makefile $(NASK) naskfunc.nas naskfunc.obj naskfucn.lst bootpack.bim : bootpack.obj naskfunc.obj Makefile $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ bootpack.obj naskfunc.obj echo error # 3MB+64KB=3136KB bootpack.hrb : bootpack.bim Makefile $(BIM2HRB) bootpack.bim bootpack.hrb 0 haribote.sys :asmhead.bin bootpack.hrb Makefile copy /B asmhead.bin+bootpack.hrb haribote.sys haribote.img : ipl10.bin haribote.sys Makefile $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ imgout:haribote.img install: $(MAKE) haribote.img run : echo Running... $(SHORTCUT) echo Finished clean : -$(DEL) *.bin -$(DEL) *.lst -$(DEL) *.gas -$(DEL) *.obj -$(DEL) bootpack.nas -$(DEL) bootpack.map -$(DEL) bootpack.bim -$(DEL) bootpack.hrb -$(DEL) haribote.sys -$(DEL) *.*~ -$(DEL) *~ echo Finished.
此次更新慢了, 下次爭取早一點…