3、进入32位模式并导入C语言

之前的IPL(Intial Program Loader)并没有装载程序,接下来通过之前的IPL装载程序,读入磁盘内容,完成真正的IPL。

 ; hello-os
 ; TAB=4

         CYLS    EQU        10      ; 相当于c语言中的#define,声明常数,CYLS = 10
         ORG        0x7c00          ; 指明程序的装载地址

 ; 以下这段是标准FAT32格式软盘专用的代码

         JMP       entry
         DB        0x90
         DB        "HELLOIPL"       ; freeparam 启动区的名称可以是任意的字符串(8字节)
         DW        512              ; 每个扇区(sector)的大小(必须为512字节)
         DB        1                ; 簇(cluster)的大小(必须为1个扇区)
         DW        1                ; FAT的起始位置(一般从第一个扇区开始)
         DB        2                ; FAT的个数(必须为2)
         DW        224              ; 根目录的大小(一般设成224项)
         DW        2880             ; 该磁盘的大小(必须是2880扇区)
         DB        0xf0             ; 磁盘的种类(必须是0xf0)
         DW        9                ; FAT的长度(必须是9扇区)
         DW        18               ; 1个磁道(track)有几个扇区(必须是18)
         DW        2                ; 磁头数(必须是2)
         DD        0                ; 不使用分区,必须是0
         DD        2880             ; 重写一次磁盘大小
         DB        0,0,0x29         ; 意义不明,固定
         DD        0xffffffff       ; (可能是)卷标号码
         DB        "HELLO-OS   "    ; freeparam 磁盘的名称(11字节)
         DB        "FAT12   "       ; 磁盘格式名称(8字节)
         RESB      18               ; 先空出18字节

 ; 程序核心

 entry:
         MOV        AX,0            ; 初始化寄存器
         MOV        SS,AX
         MOV        SP,0x7c00       ; 0x7c00到0x7dff为启动区内容的装载地址
         MOV        DS,AX           ; DS必须指定为0,因为它是默认的段寄存器,地址的值会加上这个值的16倍

 ; 读磁盘,读入第二个扇区 C0-H0-S1(柱面0,磁头0,扇区1的缩写)第一个扇区存储IPL

         MOV        AX,0x0820      
         MOV        ES,AX           ; [ES:BX] = ES * 16 + BX 中的数据被加载到0x8200到0x83ff的地方,0x8200到0x81ff为读入启动区后放置的地方
         MOV        CH,0        ; 柱面0,CH代表柱面号
         MOV        DH,0        ; 磁头0,DH代表磁头号,0表示正面
         MOV        CL,2        ; 扇区2,CL代表扇区号

readloop:
         MOV        SI,0            ; 记录失败次数的寄存器


 ;如果装载不成功,重试最多5次

 retry:
         MOV        AH,0x02     ; AH=0x02 : 读盘,AH=0x03:写盘
         MOV        AL,1        ; 1个扇区
         MOV        BX,0
         MOV        DL,0x00     ; A驱动器,DL代表驱动器号
         INT        0x13        ; 调用磁盘BIOS
         JNC        next        ; 没出错时跳转到next,进位标志为0时跳转
         ADD        SI,1        ; SI加1  
         CMP        SI,5        ; 比较SI与5
         JAE        error       ; SI >= 5时,跳转到 error
         MOV        AH,0x00         ; 连同下面两句是系统复位,复位软盘状态
         MOV        DL,0x00     ; A驱动器
         INT        0x13        ; 重置驱动器
         JMP        retry

 ;读到第18扇区

 next:
         MOV        AX,ES       ; 把内存地址后移0x200(0x200 = 512)
         ADD        AX,0x0020       ; ADD    AX, 512 / 16 ,下一个扇区地址
         MOV        ES,AX       ; 因为没有ADD ES,0x020 指令,所以这里稍微绕个弯,ES指定读入地址
         ADD        CL,1        ; CL加1,CL是扇区号
         CMP        CL,18       ; 比较CL与18
         JBE        readloop        ; 如果CL<=18,跳转至readloop

 ;至此已读完一个柱面,接下来再读入9个柱面(1个柱面18个扇区)

         MOV        CL,1            ; 扇区号
         ADD        DH,1            ; 磁头号,1表示反面,C0-H0-S18扇区的下一扇区是磁盘反面的C0-H1-S1
         CMP        DH,2
         JB         readloop        ; 如果DH < 2,则跳转到readloop
         MOV        DH,0
         ADD        CH,1            ; 柱面号加1
         CMP        CH,CYLS        
         JB         readloop        ; 如果CH < CYLS,则跳转到readloop,CYLS为声明的常数,为10

; 读完所有数据后,调到0x8200位置,即haribote.sys中的指令

         MOV        [0x0ff0],CH     ; 将CYLS的值写到内存地址0x0ff0中。
         JMP        0xc200          ; naskfunc.nas开始执行的地方

 fin:
         HLT                        ; 让CPU停止;等待指令
         JMP        fin             ; 无限循环

 error:
     MOV        SI,msg

 putloop:
         MOV        AL,[SI]
         ADD        SI,1            ; 给SI加1
         CMP        AL,0
         JE         fin
         MOV        AH,0x0e         ; 显示一个文字
         MOV        BX,15           ; 指定字符颜色
         INT        0x10            ; 调用显卡BIOS
         JMP        putloop


 msg: ; 信息显示部分
         DB        0x0a, 0x0a       ; 换行2次
         DB        "load, error!"   ; freeparam
         DB        0x0a             ; 换行
         DB        0

         RESB      0x7dfe-$         ; 填写0x00,直到0x001fe,是为了保证第510字节(即第0x1fe字节)开始的地方是55AA,

         DB        0x55, 0xaa       ;如果启动区最后2字节不是0x55aa,计算机会认为盘上没有需要启动的程序。


现在已经把软盘中的10 * 2 * 18 * 512 = 180KB 装载入内存0x8200到0x34fff的地方了。至此,已完成启动区的制作。
双击!cons_nt.bat,输入make run后,出现如下画面:
这里写图片描述

着手开发操作系统
编写一个OS程序,保存为haribote.nas

;haribote-os
;TAB = 4


    ORG     0xc200      ;程序要装载的地方

    MOV     AL,0x13     ;VGA显卡,32x00x8位颜色
    MOV     AH,0x00     ;设置AH=0x00,调用显卡BIOS函数,就可以切换显示模式了,AL中设置模式
    INT     0x10        

fin:
    HLT                  ; 使CPU基本处于睡眠状态
    JMP fin

用nask编译,输出成二进制文件haribote.sys:
双击!cons_nt.bat,输入:..\z_tools\nask.exe haribote.nas haribote.sys
接下来将这个文件保存到磁盘映像hribote.img中。
Makefile中的内容更新:

TOOLPATH = ../z_tools/
MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
EDIMG    = $(TOOLPATH)edimg.exe
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del

default :
    $(MAKE) img

#制作文件ipl.bin

ipl.bin : ipl.nas Makefile #要制作文件ipl.bin,需先检查ipl.nas和Makefile这两个文件是否准备好
    $(NASK) ipl.nas ipl.bin ipl.lst

haribote.sys : haribote.nas Makefile
    $(NASK) haribote.nas haribote.sys haribote.lst

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
#生成 helloos.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) ipl.bin
    -$(DEL) ipl.lst
    -$(DEL) haribote.sys
    -$(DEL) haribote.lst
    -del ipl.lst

#把源程序以外的文件全部删干净

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

双击!cons_nt.bat,输入make img后,生成haribote.img,此时hanbote.sys已经写入hairbote.img中
说明:
文件名写在0x002600以后的地方
文件的内容写在0x004200以后的地方

从启动区执行操作系统

目的:执行磁盘映像上位于0x4200号地址的程序。
现况:从启动区开始,磁盘上的内容转载到了内存0x8000号地址。
结果:0x4200处的内容位于内存0x8000+0x4200=0xc200处
操作:haribote.nas中加入ORG 0xc200
ipl.nas中处理的最后加JMP 0xc200

输入make run后的画面:
这里写图片描述

32位模式前期准备
修改harbote.nas

;haribote-os
;TAB = 4

; 有关BOOT_INFO
CYLS    EQU 0x0ff0      ;设定启动区
LEDS    EQU 0x0ff1
VMODE   EQU 0x0ff2      ;有关颜色数目的信息
SCRNX   EQU 0x0ff4      ;分辨率的x
SCRNY   EQU 0x0ff6      ;分辨率的y
VRAM    EQU 0x0ff8      ;图像缓冲区的开始地址,VRAM指显卡内存

    ORG     0xc200      ;程序要装载的地方

    MOV     AL,0x13     ;VGA显卡,32x00x8位颜色
    MOV     AH,0x00     ;设置AH=0x00,调用显卡BIOS函数,就可以切换显示模式了,AL中设置模式
    INT     0x10        

    MOV     BYTE [VMODE],8    ; 记录画面模式
    MOV     WORD [SCRNX],320
    MOV     WORD [SCRNY],200
    MOV     DWORD [VRAM],0x000a0000 ;这种画面模式下"VRAM是0xa0000到0xaffff的64KB

; 用BIOS取得键盘上各种LED指示灯的状态

    MOV     AH,0x02
    INT     0x16            ; keyboard BIOS
    MOV     [LEDS],AL
fin:
    HLT
    JMP fin

开始导入C语言
haribote.nas改成了asmhead.nas,为调用C语言,添加了100行左右的汇编代码。它的功能是承接IPL程序,调用bootpack.c中的主函数。这部分后面再讲。

最重要的OS核心部分为C语言程序bootpack.c,从现在开始,将越来越多的采用C语言编写OS。
bootpack.c :

//告诉C编译器,有一个函数在别的文件里

void io_hlt(void);  //是函数声明,意思是函数在别的文件中,自己找一下吧

void HariMain(void) //程序从此处开始运行,函数名不能改
{
   fin:
    io_hlt();       //执行naskfunc.nas里的_io_hlt
    goto fin;
}

接下来用汇编写一个函数naskfunc.nas,因为C语言无法实现HLT,所以需要写成汇编语言,供C语言函数调用:

; naskfunc
; TAB=4

  [FORMAT "WCOFF"]              ; 制作目标文件的模式,因为该函数之后要与bootpack.obj链接,所以也需要编译成目标文件。
  [BITS 32]                     ; 制作32位模式用的机器语言


  ; 制作目标文件的信息

 [FILE "naskfunc.nas"]          ; 源文件名信息

         GLOBAL    _io_hlt      ; 程序中包含的函数名,必须在函数前加"_",否则不能很好地与C语言函数链接
                                ;需要链接的函数名,都需要用GLOBAL声明

  ; 以下是实际的函数

 [SECTION .text]                ; 目标文件中写了这些后再写程序

 _io_hlt:                      ; 先写一个用GLOBAL声明的函数名相同的编号,表示函数void io_hlt(void)
         HLT                   ; 使CPU基本处于睡眠状态    
         RET                   ; 相当于return

Makefile中的内容也变化了,将ipl.nas、asmhead.nas、bootpack.c、naskfunc.nas组合成为一个OS程序。

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
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del


default :
    $(MAKE) img

# 启动区

ipl.bin : ipl.nas Makefile
    $(NASK) ipl.nas ipl.bin ipl.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 naskfunc.lst

bootpack.bim : bootpack.obj naskfunc.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
        bootpack.obj naskfunc.obj
# 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 : 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

#生成 helloos.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) bootpack.nas
    -$(DEL) bootpack.map
    -$(DEL) bootpack.bim
    -$(DEL) bootpack.hrb
    -$(DEL) haribote.sys


#把源程序以外的文件全部删干净

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

bootpack.c变成机器语言的过程:
使用cc1.exe从bootpack.c生成gas汇编语言bootpack.gas
使用gas2nask,将gas汇编语言bootpack.gas变成nask能翻译的汇编语言bootpack.nas
使用nask.exe将bootpack.nas生成目标文件bootpack.obj(机器语言)
使用obj2bim.exe将bootpack.obj生成二进制映像文件bootpack.bim,这一步是因为C语言不能编写所有的程序,有一部分用汇编来写,然后链接到C语言程序上
使用bim2hrb.exe将bootpack.obj生成bootpack.hrb,这是因为映像文件只是将各部分全都链接在一起,做成了完整的机器语言文件,为了实际使用,还需要加工,如加上识别的文件头,或者压缩等。

使用make run命令后,结果没有变化
这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值