; hello-os
; TAB=4
ORG 0x7c00 ; ORG命令指令程序开始地址
JMP entry ;无条件跳转到entry函数中
//我寻思,后面这段代码不会执行啊,直接跳entry了
//测试后发现如果不加后面这一段,是无法通过编译阶段的
DB 0x90
DB "HELLOIPL" ;
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 "HELLO-OS " ;
DB "FAT12 " ;
RESB 18 ;
entry:
MOV AX,0 ; 将0放入AX通用寄存器
MOV SS,AX ; 这里将栈顶位置设置成0,需要注意的是SS不能直 ;接赋值
MOV SP,0x7c00 ;栈的偏移地址 SS:SP
MOV DS,AX ;DS,ES均为段寄存器,一般在DS中存放即将访问的数;据地址
MOV ES,AX
MOV SI,msg ;对源变址寄存器进行修改,作用为存放输出函数的地址
//attention:能够只带地址的寄存器非常有限,只有BX,BP,SI,DI
putloop:
MOV AL,[SI] ; 将SI的内存地址copy到AL
ADD SI,1 ; SI++
CMP AL,0 ; AL的值为0,即msg程序已经执行完成了
JE fin ;条件跳转
MOV AH,0x0e ;
MOV BX,15 ;
INT 0x10 ; BIOS文档中调用显卡的中断
/*
显示一个字符:
AH=0X0E;
AL=character code;
BH=0;
BL=color code;
*/
JMP putloop
fin:
HLT ; 程序结束,CPU休眠
JMP fin ;
msg:
DB 0x0a, 0x0a ;
DB "hello, world" ;这里可以替换成各种字符,只要不超过内存上限
DB 0x0a ;
DB 0
RESB 0x7dfe-$ ;在该地址后面填0,否则会报错
DB 0x55, 0xaa
CPU部分寄存器的介绍
以上给出的寄存器均为16位寄存器,其中AX,BX,CX,DX均可以拆分为高8位与低8位,反过来说,后面的四个寄存器是不能直接读取到其高8和低8位的。应该通过前4个16位寄存器来间接读取。
mov AX SI
再通过AH和AL来读取SI的高低8位。
间接寻址 mov AL [SI] 将SI的内存地址赋值给AL,这种用法仅限于BX,BP,SI,DI。
到此,该系统还只是运行内存中的代码,而实际中操作系统需要从其他外部存储器获得程序运行所需要的的机器代码,所以后面增加了通过软盘为介质装载程序的步骤。
增加的代码如下:
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 ;JUMP if carray
中断号0x13手册中的说明为:
AH=0x02//读盘
AH=0X03;//写盘
AH=0x04;//校验
AH=0x0c;//寻道
AL=处理对象的扇区数;
CH=柱面号&0xff;
CL=扇面区(0-5位)|(柱面号&0x300)>>2;
DH=磁头号;
DL=驱动器号;
ES:BX=缓冲地址;
FLAGS.CF=0;没有错误
FLAGS.CF=1;有错误,错误号码存入AH内(与重置功能相同)
可以理解为该段代码设定了磁盘数据读入后存放的缓存区,ES:BX但是,磁盘存在读取过程中出现错误的可能性,所以将该段代码改为最多重复读取五次。
entry:
//配置上没有变化
MOV AX,0
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV AX,0x0820
MOV ES,AX
MOV CH,0
MOV DH,0
MOV CL,2
//将失败次数存到SI中
MOV SI,0
retry:
MOV AH,0x02
MOV AL,1
MOV BX,0
MOV DL,0x00
INT 0x13
JNC fin
ADD SI,1 ;SI++
CMP SI,5 ; SI>=5?
JAE error ; SI >= 5 JMP error
MOV AH,0x00
MOV DL,0x00 ; 使用驱动器A
INT 0x13 ; 触发中断
JMP retry