《30天自制操做系統》讀書筆記(3) 引入C語言

這一次的學習至關曲折, 主要是由於粗心, Makefile裏面的錯誤致使了文件生成出現各類奇奇怪怪的問題, 弄得心力交瘁, 所以製做過程仍是儘可能按着做者的路子來吧. vim

做者提供的源碼的註釋在中文系統下是亂碼, 並且代碼的分隔用了兩個Tab, 在這裏要處理一下: 緩存

:%s/;.*//g 刪除全部的註釋; 函數

:%s/\t\t/\t 把兩個Tab替換爲一個Tab; 工具

要讓做者的nas文件和asm文件擁有相同的語法規則, 在_vimrc文件的最後一行添加 oop

au BufNewFile,BufRead *.nas set filetype=asm 學習

  • 真正的IPL

    以前咱們寫的只是軟盤啓動區代碼, 全部代碼只能放在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裏面的代碼已經被執行.

 

  • 進入32位模式&導入C語言*

這裏做者開始用咱們看不懂的東西了, 給出了一個長長的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. 

 

 

 

此次更新慢了, 下次爭取早一點…

相關文章
相關標籤/搜索