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

来源:互联网 发布:手游刷金币的软件 编辑:程序博客网 时间:2024/05/31 06:24

从启动区执行操作系统

ipl:

; haribote-ipl; TAB=4CYLS    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     retrynext:        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,msgputloop:        MOV     AL,[SI]        ADD     SI,1            ;         CMP     AL,0        JE      fin        MOV     AH,0x0e         ;         MOV     BX,15           ;         INT     0x10            ;         JMP     putloopfin:        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     0x10fin:        HLT        JMP     fin

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

; haribote-os; TAB=4; BOOT_INFOCYLS    EQU     0x0ff0          ; 把我们需要的信息保存在0X0FF* 的区域LEDS    EQU     0x0ff1VMODE   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],ALfin:        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=4BOTPAK  EQU     0x00280000      ; DSKCAC  EQU     0x00100000      ; DSKCAC0 EQU     0x00008000      ; ; BOOT_INFO娭學CYLS    EQU     0x0ff0          ; LEDS    EQU     0x0ff1VMODE   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     pipelineflushpipelineflush:        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    memcpyskip:        MOV     ESP,[EBX+12]    ;         JMP     DWORD 2*8:0x0000001bwaitkbdout:        IN       AL,0x64        AND      AL,0x02        JNZ     waitkbdout      ;         RETmemcpy:        MOV     EAX,[ESI]        ADD     ESI,4        MOV     [EDI],EAX        ADD     EDI,4        SUB     ECX,1        JNZ     memcpy          ;         RET;         ALIGNB  16GDT0:        RESB    8               ;         DW      0xffff,0x0000,0x9200,0x00cf ;         DW      0xffff,0x0000,0x9a28,0x0047 ;         DW      0GDTR0:        DW      8*3-1        DD      GDT0        ALIGNB  16bootpack:
0 0
原创粉丝点击