在第三天中,在原来的基础上添加了部分功能。
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下这段是标准FAT12格式软盘专用的代码
JMP entry
DB 0x90
--略--
; 程序核心
entry:
MOV AX,0 ; 初始化寄存器
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
MOV AH,0x02 ; AH=0x02 : 读盘
MOV AL,1 ; 1个扇区
MOV BX,0
MOV DL,0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS
JC error
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
error:
MOV SI,msg
这里新出现的指令JC,意思是如果进位标志是1的话,就跳转。
关于INT 0x13,调用磁盘BIOS,此时相关寄存器如下:
AH = 0x02 (读盘)
AH = 0x03
AH = 0x04
AH = 0x0c
AL = 处理对象的扇区数(只能同时处理连续的扇区)
CH = 柱面号 & 0xff
CL = 扇区号(0-5位) | (柱面号 & 0x300) >> 2
DH = 磁头号
DL = 驱动器号
ES : BX = 缓冲地址(校验及寻道时不使用)
返回值:
FLAGS.CF == 0,没有错误, AH == 0
FLAGS.CF == 1;有错误,错误号码存入AH内。
当我们从软盘读出数据时,需要存放的地址是个内存地址,一个BX只能表示0~0xffff的值,最大即64K,为了解决这个问题,增加了一个EBX的寄存器。另一种方式则是设计了一个起辅助作用的段寄存器,使用段寄存器时,以ES:BX这种方式来表示地址,写成MOV AL, [ES:BX],它代表EX x 16 + BX的内存地址。
在上述程序中,ES = 0x0820,所以软盘的数据将被装载到内存中0x8200到0x83ff的地方。不管要指定什么地址,都必须同时指定段寄存器。一般如果省略的话就会把DS:作为默认的段寄存器。比如MOV AL, [SI],也就是MOV AL,[DS :SI]。
接下来我们看,有以下一个程序:
fin:
HLT
JMP fin
将以上内容保存为haribote.nas,用nask编译,输出haribote.sys,再将这个文件保存到磁盘映像文件haribote.img,会发现,在该文件的0x002600附近保存文件名,而在0x004200的位置保存文件的内容,所以我们可以讲操作系统本身的内容写到名为haribote.sys文件中,再把它保存到磁盘映像里,然后从启动区执行这个haribote.sys。
以下是haribote.sys的内容:
; haribote-os
; TAB=4
ORG 0xc200 ; 之所以为这个值是因为程序是从启动区开始,把磁盘上的内容装载到
; 内存0x8000号地址,所以磁盘0x4200处就位于0xc200号地址
MOV AL,0x13 ; VGA显卡,320x200x8位彩色
MOV AH,0x00
INT 0x10
fin:
HLT
JMP fin
设定AH=0x00后,调用显卡BIOS的函数,可以切换显示模式,具体参数如下:
AH=0x00
AL = 模式
0x03:16色字符模式,80x25
0x12:VGA图形模式,640x480x4位彩色模式,独特的4面存储模式
0x13:VGA图形模式,320x200x8位彩色模式,调色板模式
所以上述程序会切换到VGA图形模式