《30天自制操作系统》——从引导区到磁盘

上一篇讲了如何使用虚拟机运行我们写好的操作系统,但上一篇的操作系统其实仅仅存在于引导扇区中,接下来我们将看到程序如何从引导扇区跳到其他位置。

引导区内容的装载位置为 0x00007c00-0x00007dff,规定该位置的人是当年开发IBM-PC的工程师们。0x7e00-0x9fbff是操作系统可以随便使用的内存位置。按照《30天自制操作系统》中所讲,我们把前10个磁道的数据都读入内存,内存位置从0x8000开始。因此磁盘镜像文件中,位于地址x的字符加载到内存的位置就为0x8000+x。现在设我们需要执行磁盘镜像上位于0x004200号地址的程序,那么其内存地址就为0x8000+0x4200=0xc200。

程序一、ipl.nas
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; hello-os
; TAB=8

    ORG    0x7C00

; 以下的记述用于标准FAT12格式的软盘
start:
    JMP    entry
    DB    "HELLOIPL"    ; 启动区名称(8字节)
    DW    512        ; 扇区大小(512字节)
    DB    1        ; 簇大小(1扇区)
    DW    1        ; FAT起始位置
    DB    2        ; FAT个数
    DW    224        ; 根目录大小(224项)
    DW    2880        ; 磁盘大小(2880扇区)
    DB    0xf0        ; 磁盘种类
    DW    9        ; FAT长度
    DW    18        ; 每个磁道扇区数
    DW    2        ; 磁头数
    DD    0        ; 不使用分区
    DD    2880        ; 重写一次磁盘大小
    DB    0,0,0x29    ; 意义不明
    DD    0xffffffff    ; 可能是卷标号码
    DB    "HELLO-OS   "    ; 磁盘名称(11字节)
    DB    "FAT12   "    ; 格式名称(8字节)
    RESB    18        ; 空出18字节

entry:
    MOV    AX,0        ; 初始化寄存器
    MOV    SS,AX
    MOV    SP,0x7c00
    MOV    DS,AX
    MOV    ES,AX
; 读磁盘
    CYLS    EQU    10
    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        ; 读盘
    MOV    AL,1        ; 1个扇区
    MOV    BX,0
    MOV    DL,0x00        ; A驱动器
    INT    0x13        ; 调用磁盘BIOS
    JNC    next        ; 没出错跳转fin
    ADD    SI,1        
    CMP    SI,5        ; 比较SI与5
    JAE    error        ; SI >= 5时,跳转到error
    MOV    AH,0x00
    MOV    DL,0x00
    INT    0x13        ; 重置驱动器
    JMP    retry
next:
    MOV    AX,ES
    ADD    AX,0x0020    ; 把内存地址后移0x200
    MOV    ES,AX        ; 因为没有ADD ES,0x20
    ADD    CL,1
    CMP    CL,18
    JBE    readloop    ; 如果CL <= 18,跳转至readloop
    MOV    CL,1
    ADD    DH,1        ; 读磁盘另一面
    CMP    DH,2
    JB    readloop
    MOV    DH,0
    ADD    CH,1
    CMP    CH,CYLS        ; 读CYLS个柱面
    JB    readloop

; 输出helloworld

    MOV    SI,msg
putloop:
    MOV    AL,[SI]
    ADD    SI,1        ; 给SI加1
    CMP    AL,0

    JE    0xc200        ; 跳到0xc200,即hanbote.nas程序地址
    MOV    AH,0x0e        ; 显示一个文字
    MOV    BX,15        ; 指定字符颜色
    INT    0x10        ; 调用显卡BIOS
    JMP    putloop
    JMP    0xc200
fin:
    HLT
    JMP    fin
error:
    MOV    SI,errmsg
errloop:
    MOV    AL,[SI]
    ADD    SI,1        ; 给SI加1
    CMP    AL,0

    JE    fin
    MOV    AH,0x0e        ; 显示一个文字
    MOV    BX,15        ; 指定字符颜色
    INT    0x10        ; 调用显卡BIOS
    JMP    errloop

msg:
    DB    0x0a, 0x0a    ; 换行2次
    DB    "hello, world"
    DB    0x0a        ; 换行
    DB    0
errmsg:
    DB    0x0a, 0x0a    ; 换行2次
    DB    "disk error"
    DB    0x0a        ; 换行
    DB    0
marker:
    RESB    0x1fe-(marker-start)
    DB    0x55, 0xaa
; 以下是磁盘其他内容
    DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    RESB    4600
    DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    RESB    1469432
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
程序二、hanbote.nas
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; haribote-os
; TAB=8
    ORG    0xc200    ; 程序开头在内存中的地址
    MOV    SI,msg
putloop:
    MOV    AL,[SI]
    ADD    SI,1        ; 给SI加1
    CMP    AL,0
    JE    black
    ; JE    fin
    MOV    AH,0x0e        ; 显示一个文字
    MOV    BX,15        ; 指定字符颜色
    INT    0x10        ; 调用显卡BIOS
    JMP    putloop

black:
    MOV    AL,0x13    ; VGA显卡
    MOV    AH,0x00
    INT    0x10    
fin:
    HLT
    JMP    fin

msg:
    DB    0x0d, 0x0a, 0x0a    ; 换行2次
    DB    "haha"
    DB    0x0a        ; 换行
    DB    0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
程序3、Makefile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
default:
    make img

img: hanbote.bin ipl.bin
    dd if=hanbote.bin of=ipl.img bs=512 seek=33 count=1 conv=notrunc

ipl.bin: ipl.nas
    nasm -f bin ipl.nas -o ipl.img -l ipl.lst

hanbote.bin: hanbote.nas
    nasm -f bin hanbote.nas -o hanbote.bin

run: img
    qemu-system-i386 -fda ipl.img -boot a

clean:
    rm ipl.lst
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

这样你只要在终端中输入make run就能看到运行结果了。
其中我们使用dd来把hanbote.bin写入ipl.nas中我们希望的位置。
hanbote.bin在ipl.nas中的位置从0x4200开始,因为dd以512字节为一块,所以用seek把输出文件定位到0x4200/512=0x21=33,notrunc保证ipl.img不被截断。

你可能感兴趣的:(《30天自制操作系统》——从引导区到磁盘)