03day 进入32位模式并导入C语言

从启动区执行操作系统

ipl:

; haribote-ipl
; TAB=4

CYLS    EQU     10              ; 

        ORG     0x7c00          ; 我们将磁盘映像的启示512字节加载到Boot Sector Entry中

; 

        JMP     entry
        DB      0x90
        DB      "HARIBOTE"      ; 
        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      "HARIBOTEOS "   ; 
        DB      "FAT12   "      ; 
        RESB    18              ; 

; 

entry:
        MOV     AX,0            ; init
        MOV     SS,AX
        MOV     SP,0x7c00
        MOV     DS,AX

; 

        MOV     AX,0x0820
        MOV     ES,AX
        MOV     CH,0            ; 柱面 0
        MOV     DH,0            ; 磁头 0
        MOV     CL,2            ; 扇区 2(扇区从1开始到18)
readloop:
        MOV     SI,0            ; 
retry:
        MOV     AH,0x02         ; AH=0x02 : 
        MOV     AL,1            ; 
        MOV     BX,0
        MOV     DL,0x00         ; 
        INT     0x13            ; 
        JNC     next            ; 
        ADD     SI,1            ; 
        CMP     SI,5            ; 
        JAE     error           ; SI >= 5 
        MOV     AH,0x00
        MOV     DL,0x00         ; 
        INT     0x13            ; 
        JMP     retry
next:
        MOV     AX,ES           ; 
        ADD     AX,0x0020
        MOV     ES,AX           ; ADD ES,0x020 写入位置向后移动512字节
        ADD     CL,1            ; 写入扇区+1
        CMP     CL,18           ; CL大于18 ?
        JBE     readloop        ; CL <= 18 
        MOV     CL,1 
        ADD     DH,1
        CMP     DH,2            ;CL=1 磁头+=1 磁头>=2 ?
        JB      readloop        ; DH < 2 
        MOV     DH,0
        ADD     CH,1
        CMP     CH,CYLS         ;CYLS=10 我们要读取10个柱面
        JB      readloop        ; CH < CYLS 

; 执行到这里说明我们读取完成
; 10*2*18*512/1024=180KB 我们将磁盘中180KB读取到0x08200~0x34fff 
; 那0x08000~0x081fff 呢 这部分是留给启动区的 要将这512字节留给启动区
; 通过我们的观察 操作系统的代码的启示位置位于文件偏移的0x4200处,加载后的内存位置应该是
; 0x8000+0x4200=0xc200
; 所以这里我们要跳转到操作系统的代码起始处 c200


        MOV     [0x0ff0],CH     ; CH=10
        JMP     0xc200   
;到这里 

error:
        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      0x0a, 0x0a      ; 
        DB      "load error"
        DB      0x0a            ; 
        DB      0

        RESB    0x7dfe-$       ; 

        DB      0x55, 0xaa

启动区的制作大体就是这样 读取我们的操作系统 然后跳转到操作系统代码的入口处。

这里示例的代码很简单。

haribote.nas

; haribote-os
; TAB=4

        ORG     0xc200          ; 写入内存位置

        MOV     AL,0x13         ; al=13 调用显卡设置模式
                                ; al=0x13 VGA图形模式 320*200*8 彩色模式 调色板模式
        MOV     AH,0x00
        INT     0x10
fin:
        HLT
        JMP     fin

32位模式前期准备
一旦使用32位模式就不能调用BIOS功能了,因为BIOS是用16位机器语言写的,在进入BIOS前 我们要获取我们想获取的信息。

; haribote-os
; TAB=4

; BOOT_INFO

CYLS    EQU     0x0ff0          ; 把我们需要的信息保存在0X0FF* 的区域
LEDS    EQU     0x0ff1
VMODE   EQU     0x0ff2          ; 
SCRNX   EQU     0x0ff4          ; 
SCRNY   EQU     0x0ff6          ; 
VRAM    EQU     0x0ff8          ; 

        ORG     0xc200          ; 

        MOV     AL,0x13         ; 
        MOV     AH,0x00
        INT     0x10            ;VGA显卡 320*200*8
        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

fin:
        HLT
        JMP     fin

BIOS内存分布图

接下来我们直接切换到32位模式 然后运行C语言写的程序。
所以haribote.sys 前半部分是由汇编写的 后面是用c语言写的。汇编的后半部分使我们切换到32位模式的代码,暂时不作讲解。

接下来是c语言部分。
比如:

void HariMain(void)
{

fin:
    /*  */
    goto fin;

}

程序一直在死循环中。
那么bootpack.c是怎么样变成机器语言呢?

  1. ccl.exe c编译器 bootpack.c –> bootpack.gas
  2. gas2nask.exe 汇编格式转换 bootpack.gas –> bootpack.nas
  3. nask.exe 汇编编译为目标文件 bootpack.nas –> bootpack.obj
  4. obj2bim.exe 链接生成二进制映像文件替代品 bootpack.obj –> bootpack.bim
  5. bim2hrb.exe bootpack.bim –> bootpack.hrb

此时c语言就变成了机器语言 使用copy指令将asmhead.bin 与bootpack.hrb 结合起来,成为haribote.sys

程序是从以HariMain命名的函数开始运行的。

为了不要我们程序进入死循环中,我们想办法让程序进入HLT状态

; naskfunc
; TAB=4

[FORMAT "WCOFF"]                ;   
[BITS 32]                       ; 


; 

[FILE "naskfunc.nas"]           ; 

        GLOBAL  _io_hlt         ; 


; 

[SECTION .text]     ; 

_io_hlt:    ; void io_hlt(void);
        HLT
        RET

显而易见,我们添加了io_hlt函数的实现 它的行为很简单,使计算机处于HLT状态。

同时看一下c文件

void io_hlt(void);
void HariMain(void)
{
fin:
    io_hlt(); 
    goto fin;
}

可以同时看一下我们的编译规则

bootpack.bim : bootpack.obj naskfunc.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
        bootpack.obj naskfunc.obj

把汇编文件和c文件链接到一起即可。

make run 运行,大功告成。


最后附上asmhead.nas, (切换到32位模式)

; haribote-os boot asm
; TAB=4

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

; BOOT_INFO娭學
CYLS    EQU     0x0ff0          ; 
LEDS    EQU     0x0ff1
VMODE   EQU     0x0ff2          ; 
SCRNX   EQU     0x0ff4          ; 
SCRNY   EQU     0x0ff6          ; 
VRAM    EQU     0x0ff8          ; 

        ORG     0xc200          ; 

; 

        MOV     AL,0x13         ; 
        MOV     AH,0x00
        INT     0x10
        MOV     BYTE [VMODE],8  ; 
        MOV     WORD [SCRNX],320
        MOV     WORD [SCRNY],200
        MOV     DWORD [VRAM],0x000a0000

; 

        MOV     AH,0x02
        INT     0x16            ; keyboard BIOS
        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         ; enable A20
        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

; bootpack偺揮憲

        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           ; 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
bootpack:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值