自制操做系統 (三) 從啓動區執行操做系統並進入C世界

qq:992591601 歡迎交流ios

2016.04.03 2016.05.31 2016.06.29數據結構

這一章是有些複雜的,我不太懂做者爲何要把這麼多內容都放進一天。函數

1讀入了十個柱面工具

2從啓動區執行操做系統oop

3進入32位ui

4導入C語言spa

 

makefile的內容:操作系統

TOOLPATH = ../z_tools/
INCPATH  = ../z_tools/haribote/

MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
NASM     = $(TOOLPATH)nasm.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
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del

default :
    $(MAKE) img

ipl.bin : ipl.asm Makefile
    $(NASM) ipl.asm -o ipl.bin

main.bin : main.nas Makefile
    $(NASK) main.nas main.bin main.lst

c_main.gas : c_main.c Makefile
    $(CC1) -o c_main.gas c_main.c

c_main.nas : c_main.gas Makefile
    $(GAS2NASK) c_main.gas c_main.nas

c_main.obj : c_main.nas Makefile
    $(NASK) c_main.nas c_main.obj c_main.lst

assemblyFunc.obj : assemblyFunc.nas Makefile
    $(NASK) assemblyFunc.nas assemblyFunc.obj assemblyFunc.lst

c_main.bim : c_main.obj assemblyFunc.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:c_main.bim stack:3136k map:c_main.map \
        c_main.obj assemblyFunc.obj
# 3MB+64KB=3136KB

c_main.hrb : c_main.bim Makefile
    $(BIM2HRB) c_main.bim c_main.hrb 0

haribote.sys : main.bin c_main.hrb Makefile
    copy /B main.bin+c_main.hrb haribote.sys

haribote.img : ipl.bin haribote.sys Makefile
    $(EDIMG)   imgin:../z_tools/fdimg0at.tek \
        wbinimg src:ipl.bin len:512 from:0 to:0 \
        copy from:haribote.sys to:@: \
        imgout:haribote.img


img :
    $(MAKE) haribote.img

run :
    $(MAKE) img
    $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
    $(MAKE) -C ../z_tools/qemu

install :
    $(MAKE) img
    $(IMGTOL) w a: haribote.img

clean :
    -$(DEL) *.bin
    -$(DEL) *.lst
    -$(DEL) *.gas
    -$(DEL) *.obj
    -$(DEL) c_main.nas
    -$(DEL) c_main.map
    -$(DEL) c_main.bim
    -$(DEL) c_main.hrb
    -$(DEL) haribote.sys

src_only :
    $(MAKE) clean
    -$(DEL) haribote.img

 

注意end.exe,在次日,做者提到:本身開發的磁盤映像管理工具end.exe,先讀入一個空白的磁盤映像文件,而後在開頭寫入ipl.bin的內容,最後將結果輸出爲名爲helloos.img的磁盤映像文件。code

這樣一來,邏輯上就很簡單了,用makefile,調用end.exe,將ipl10.nas和操做系統代碼,製成一個img文件。ipl10.nas是啓動區。最後操做系統的啓動是,在啓動區啓動。blog

而後咱們用工具觀察製成的img,會發現:

做者得出的結論:

              通常向一個空軟盤保存文件時

                    (1)文件名會寫在0x002600之後的地方;

                    (2)文件內容會寫在0x004200之後的地方。

因此,要執行磁盤映像上位於0x004200號地址的程序,如今的程序是從啓動區開始,把磁盤上的內容裝載到內存0x8000號地址,因此磁盤0x4200處的內容就應該位於內存0x8000+0x4200=0xc200號地址。

因此從啓動區,啓動操做系統就只須要jmp到0xc200地址便可。

 

這兩張圖能夠簡單解釋原理(第二張是我畫的):

 

ipl.asm:

; author:      無    名
; date:        2016.05.31 06.01 06.02 06.03
; description: bootsector

    CYLS equ 10          
    org 07c00h

;如下,FAT12格式引導程序專用代碼
    JMP       entry
    DB        0x90
    DB        "HELLOIPL"         ; name
    DW        512                ; size of a sector(must be 512byte)
    DB        1                  ; size of a cluster(must be a sector)
    DW        1                  ; FAT begin from 1st sector 
    DB        2                  ; FAT num 
    DW        224                ; size of root directory
    DW        2880               ; size of disk(2880 sectors)
    DB        0xf0               ; type of disk
    DW        9                  ; length of FAT(must be 9 sectors)
    DW        18                 ; how many sectors with a track 
    DW        2                  ; head num
    DD        0                  ; 不使用分區
    DD        2880               ; size of disk(2880 sectors)
    DB        0,0,0x29        
    DD        0xffffffff        
    DB        "HELLO-OS   "    
    DB        "FAT12   "        
    RESB    18                   ; 先空出18字節

entry:
    mov ax,0          
    mov ss,ax
    mov sp,0x7c00 
    mov ds,ax

;read disk
  
    mov ax,0x0820
    mov es,ax
    mov ch,0                     ;柱面0
    mov dh,0                     ;磁頭0
    mov cl,2                     ;扇區2

readloop:
    mov si,0                     ;記錄失敗次數

retry:
    mov ah,0x02                  ;ah=0x02:讀入磁盤
    mov al,1                     ;a sector
    mov bx,0  
    mov dl,0x00                  ;A驅動器
    int 0x13                     ;調用磁盤bios
    jnc next                     ;沒出錯跳轉next
    add si,1
    cmp si,5                     ;if si > 5 errorへ
    jae error
    mov ah,0x00
    mov dl,0x00   
    int 0x13                     ;重置驅動器
    jmp retry

next:
    mov ax,es                 
    add ax,0x0020
    mov es,ax          
    add cl,1           
    cmp cl,18            
    jbe readloop                 ; if cl <= 18 readloopへ
    mov  cl,1
    add  dh,1
    cmp dh,2
    jb readloop                  ; if dh < 2 readloopへ
    mov dh,0
    add ch,1
    cmp ch,CYLS
    jb  readloop                 ; if ch < CYLS readloopへ

    ;mov ax,cs                    ; print boot poem
        ;mov ds,ax
    ;mov es,ax
    ;call PrintStr                
    ;jmp $

    mov [0x0ff0],ch        
    jmp 0xc200

fin:
    hlt                        
    jmp fin    

error:
    mov  si,msg

putloop:
    mov al,[si]
    add si,1            
    cmp al,0                     ; if al == 0 finへ
    je fin
    mov ah,0x0e            
    mov bx,15            
    int 0x10            
    jmp putloop


PrintStr:                            
    mov ax,BootPoem              ; print boot poem
    mov bp,ax
mov cx,170 mov ax,01301h mov bx,00009h mov dh,10 mov dl,0 int 10h ret msg: db 0x0a, 0x0a db "load error" db 0x0a db 0 BootPoem: db "Hold fast to dreams" db 0x0a db "For if dreams die" db 0x0a db "Life is a broken-winged bird " db 0x0a db "That can never fly" db 0x0a db "Hold fast to dreams" db 0x0a db "For when dreams go" db 0x0a db "Life is a barren field" db 0x0a db "Frozen only with snow" db 0x0a times 510-($-$$) db 0 ; 接下來510字節寫0 dw 0xaa55 ; 最後一個字0xaa55是引導程序結束標誌

 

main.nas

; sonn-os boot asm
; TAB=4
; author:      無    名
; date:        2016.06.03 2016.06.05
; description: jmp to 32bit

BOTPAK    EQU        0x00280000        
DSKCAC    EQU        0x00100000        
DSKCAC0    EQU        0x00008000        

; BOOT_INFO 數據結構
CYLS    EQU        0x0ff0            ; 啓動區
LEDS    EQU        0x0ff1
VMODE    EQU        0x0ff2            ; 顏色數目的信息。顏色的位數
SCRNX    EQU        0x0ff4            ; 分辨率的X
SCRNY    EQU        0x0ff6            ; 分辨率的Y
VRAM    EQU        0x0ff8            ; 圖像緩衝區的開始地址

        ORG        0xc200            ; 這個程序要被裝載到內存什麼地方

; 畫面模式定位

        MOV        AL,0x13            ; VGA顯卡,320*200*8位彩色
        MOV        AH,0x00
        INT        0x10
        MOV        BYTE [VMODE],8            ; 記錄畫面模式
        MOV        WORD [SCRNX],320
        MOV        WORD [SCRNY],200
        MOV        DWORD [VRAM],0x000a0000

; 用BIOS取得鍵盤上各類LED指示燈的狀態

        MOV        AH,0x02
        INT        0x16             ; keyboard BIOS
        MOV        [LEDS],AL

; PIC關閉一切中斷
;    根據AT兼容機的規格、初始化PIC
;    必須在CLI以前進行,到CLI掛起
;    隨後進行PIC初始化

        MOV        AL,0xff
        OUT        0x21,AL
        NOP                        ; 若是連續進行OUT命令,有些機種不能夠
        OUT        0xa1,AL

        CLI                        ; 禁止CPU級別中斷

; OPEN A20GATE

        CALL    waitkbdout
        MOV        AL,0xd1
        OUT        0x64,AL
        CALL    waitkbdout
        MOV        AL,0xdf            ; enable A20
        OUT        0x60,AL
        CALL    waitkbdout

; 保護模式

[INSTRSET "i486p"]                ; 開始使用486命令

        LGDT    [GDTR0]            ; 臨時GDT
        MOV        EAX,CR0
        AND        EAX,0x7fffffff    ; bit31設0,禁止分頁
        OR        EAX,0x00000001    ; bit0設1,爲了切換到保護模式
        MOV        CR0,EAX
        JMP        pipelineflush
pipelineflush:
        MOV        AX,1*8            ;  可讀寫的段,32bit
        MOV        DS,AX
        MOV        ES,AX
        MOV        FS,AX
        MOV        GS,AX
        MOV        SS,AX

; 轉移

        MOV        ESI,c_main           
        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

; main到此爲止接下來是c_main

; c_main啓動

        MOV        EBX,BOTPAK
        MOV        ECX,[EBX+16]
        ADD        ECX,3            ; ECX += 3;
        SHR        ECX,2            ; ECX /= 4;
        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
c_main:

 

這裏前一部分是對32位模式的啓動,後一部分是對C語言的準備。

其實不是很好理解,等我理解了再回來補充吧。

。。EQU。。這樣的語句其實就至關於C語言中的#define語句。

mov dword[vram],0x000a0000;

vram,顯卡內存,也就是用於顯示畫面的內存,將之存儲0xa0000,也就是種對畫面的設置了。具體暫時不討論。

這段代碼應該還涉及16位進入32位,GDT尋址等等,這麼重要的東西,做者都沒有講。無語。

c_main.c:

void io_hlt(void);

void HariMain(void)
{

fin:
    io_hlt(); 
    goto fin;

}

 c_main.c調用的彙編函數在assemblyFunc.nas中,這須要一個編譯(將C語言編譯爲彙編文件c_main.nas)、連接(兩個.nas彙編文件)的過程

_io_hlt:    ; void io_hlt(void);
        HLT
        RET
相關文章
相關標籤/搜索