自制操作系统(三)

今天就来完成到C语言的过度。

首先说,映像永远是1440KB,按照软盘的格式来,就算你用了512字节的img,只有启动区,然后BIOS只从头开始检查,它的确可以执行,然后就执行了512字节的,然后完了,也不会出什么错误,但是最好还是1440KB的,因为剩下的整个系统都放在这里,把IPL制成了一个映像,然后再编写其他的脚本往映像里面添加就好了。

但是,一般C语言程序都是32位程序,而BIOS是16位的,因此二者不能互相调用了,一旦进入32位很难进入16位了,因此如果什么事情想要BIOS做,就放到开头去做。我们用BIOS设置画面模式,获取键盘信息后,直接找到C语言编写的二进制代码的函数地址,调用就可以了。

因此现在的问题是,如何能将C语言编写的二进制代码,放到img映像里,这里有准备一个程序edimg.exe,但是我没有,怎么办呢?鉴于也十分好做,自己造一个也未尝不可。

因为启动区被放在了0x8000~0x81ff,因此把数据装在到0x8200~0x83ff吧,0x7c00~0x7dff留给启动区,0x7e00以后直到0x9fbff的区域都没有什么特别的用途,操作系统可以随便使用。

因为我们的程序是从内存0x8000号地址上开始的,因此我们就直接跳到0x8000+512那个地址,就可以直接执行程序了。

现在简要说一下步骤:

首先将启动区代码稍微改一下,最后JMP到系统程序JMP 0xc200,这个0xc200就是系统程序所在地址。

这个文件的文件名设为IPL.asm

ORG 0x7c00 ; 程序的内存装载地址
JMP entry
CYLS EQU 10 ; 声明10个柱面
; 标准FAT12格式软盘专用的代码
DB		"MyOS_IPL"		; 启动扇区名称(8字节)
DW		512				; 每个扇区(sector)大小(必须512字节)
DB		1				; 簇(cluster)大小(必须为1个扇区)
DW		1				; FAT起始位置(一般为第一个扇区)
DB		2				; FAT个数(必须为2)
DW		224				; 根目录大小(一般为224项)
DW		2880			; 该磁盘大小(必须为2880扇区1440*1024/512)
DB		0xf0			; 磁盘类型(必须为0xf0)
DW		9				; FAT的长度(必须是9扇区)
DW		18				; 一个磁道(track)有几个扇区(必须为18)
DW		2				; 磁头数(必须是2)
DD		0				; 不使用分区,必须是0
DD		2880			; 重写一次磁盘大小
DB		0,0,0x29		; 意义不明(固定)
DD		0xffffffff		; (可能是)卷标号码
DB		"MyOS_disk  "	; 磁盘的名称(必须为11字节,不足填空格)
DB		"FAT12   "		; 磁盘格式名称(必须是8字节,不足填空格)
RESB	18				; 先空出18字节
; 程序主体
entry:
    MOV AX, 0 ; 初始化
    MOV SS, AX ; 堆栈地址为0
    MOV SP, 0x7c00 ; 堆栈指针附了特定值
    MOV DS, AX ; DS, ES地址必须置0

    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 ; 一个扇区
    MOV BX, 0
    MOV DL, 0x00 ; A驱动器
    INT 0x13 ; 读入
    JNC next ; 没出错跳出
    ADD SI, 1 ; 计数加1
    CMP SI, 5 ; 重复5次
    JAE error ; 5次还不行就出错
    MOV AH, 0x00
    MOV DL, 0x00 ; A驱动器
    INT 0x13 ; 重置驱动器
    JMP retry 
next:
    MOV AX, ES
    ADD AX, 0x0020
    MOV ES, AX ; 把内存地址后移512
    ADD CL, 1 ; CL的加1
    CMP CL, 18 ; 读完18个扇区
    JBE readloop ; 嗯,到这里
    MOV CL, 1
    ADD DH, 1
    CMP DH, 2
    JB readloop ; 两个正反面
    MOV DH, 0
    ADD CH, 1
    CMP CH, CYLS
    JB readloop ; 读完10个柱面

    ;JMP main
    JMP 0xc200 ; 跳转到系统执行

error:
    MOV SI, msg
    putloop:
        MOV AL, [SI] ; 把si中的内容放到AL中
        ADD SI, 1
        CMP AL, 0
        JE halt
        MOV AH, 0x0e
        MOV BX, 15
        INT 0x10
    JMP putloop

halt:
    HLT 
    JMP halt

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

RESB    0x7dfe-$ 
DB		0x55, 0xaa

紧接着将IPL.asm编译成IPL.bin,语句为nask IPL.asm IPL.bin

然后设计主程序代码,这里让它输出一个loaded的信号,注意一开始要注明程序的内存地址ORG 0xc200

ORG 0xc200

mov SI, msg1
putloop1:
    MOV AL, [SI] ; 把si中的内容放到AL中
    ADD SI, 1
    CMP AL, 0
    JE halt
    MOV AH, 0x0e
    MOV BX, 15
    INT 0x10
JMP putloop1

halt:
    HLT 
    JMP halt

msg1:
DB		0x0a, 0x0a		; 换行两次
DB		"loaded"
DB		0x0a			; 换行
DB		0
RESB    0x7dfe-$ 
DB		0x55, 0xaa

再将这个文件编译成MyOS.bin,语句为nask MyOS.asm MyOS.bin

然后下载软件WinImage(共享软件),安装后点击菜单栏的新建按钮,新建一个1.44mb的软盘

然后点击菜单栏Image->Boot sector properties->open...,将IPL.bin选入,点击确定。
然后点击工具栏中的Inject,将MyOS.bin选入。
最后保存该镜像,镜像名为MyOS.img,方便Virtual Box读取。
启动Virtual Box出现如下画面证明成功:

采坑记:

关于RESB 0x7dfe-$这一段,注意在之前并不是这个数值,之前是0x1fe,这里会有一个问题,那就是nasm不认识这个,而nask认识这个,倘若用nasm的话,需改成times,还不一定对,而且关于编译,nasm的语句是:

nasm MyOS.asm -o MyOS.iso

而nask的语句是:

nask MyOS.asm MyOS.iso

没有那个-o参数,如果填上,会报NASK : LSTBUF is not enough这个错误,坑得很。

nask是《30天自制操作系统》作者编写的汇编编译器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值