30天自制操作系统(一)启动区
一、启动区
ORG 0x7C00
JMP 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
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
readloop:
MOV AL, 1 ;扇区数量
MOV BX, 0
MOV DL, 0 ;A驱动器
MOV AH, 0x02 ;读扇区
INT 0x13
JNC next
error:
MOV AH, 0x0e
MOV AL, 'e'
INT 0x10
MOV AL, 'r'
INT 0x10
MOV AL, 'r'
INT 0x10
MOV AL, 'o'
INT 0x10
MOV AL, 'r'
INT 0x10
JMP fin
next:
MOV AX, ES
ADD AX, 0x20 ;下一扇区
MOV ES, AX
ADD CL, 1
CMP CL, 18
JBE readloop
MOV CL, 1
ADD DH, 1
CMP DH, 2
JB readloop ;读反面的磁头1
MOV DH, 0
ADD CH, 1
CMP CH, 10 ;读10个柱面
JB readloop
JMP 0xc200
fin:
HLT
JMP fin
RESB 0x7dfe-$
DB 0x55, 0xaa
前面的一部分内容(entry之前)是img镜像文件的固定格式,后面是启动区的正式内容
使用循环的方式读磁盘,按扇区——磁头——柱面的顺序,一个磁头18个扇区,一个柱面两个磁头。
程序的最后跳转到0xc200,因为磁盘内容装载在0x8000,文件内容存在0x4200,所以kernal.com就在0x8000+0x4200=0xc200的位置
(二)操作系统本身
;kernal.nas
[BITS 16]
ORG 0xc200
MOV AH, 0x0e
MOV AL, 'A'
INT 0x10
fin:
HLT
JMP fin
输出一个A字符。
使用nasm kernal.nas -o kernal.com
的方式编译,装载到img文件中即可。程序的开始要指定ORG 0xc200, 这样汇编器才能正确把标签名对照到正确的地址。
(三)图形模式切换
切换到图形模式:
MOV AL, 0x13
MOV AH, 0x00
INT 0x10
分辨率320*200的VGA图形模式,VRAM的地址在0xa0000~0xaffff。
注意十六位下,用SI/DI寻址只能寻址到0x0000~0xffff的地址,所以要用寄存器寻址。
描画条纹图案:
MOV AX,0xA000
MOV DS,AX
MOV AL, 0x13
MOV AH, 0x00
INT 0x10
MOV SI, 0x0000
L1:
MOV BX, SI
AND BL, 0x0f
MOV BYTE[DS:SI], BL
ADD SI, 1
CMP SI, 0xFFFF
JBE L1
fin:
HLT
JMP fin
参考书中第四天的内容写的,不过暂时还未切换32位模式所以只能用汇编写。用[DS:SI]的方式寻址,16位下段号相当于[DS*16+SI],DS代入0xA000,SI代入0x0000,那么[DS:SI]就是[0xA0000]。
上一节是在80*25的字符模式下描画了一个文字A,这次我们尝试着在图形模式下描画文字A,参考第五天中文字显示的代码。
用汇编语言写比较复杂的循环可能是比较麻烦...(
实现如下:
其实主体的结构不难,最难的其实是内存段的处理,访问font_A的时候指定的是代码段寄存器CS,而访问显存需要指定数据段DS,还不能混用,如果给CS赋0xA0000就会出大问题。
[BITS 16]
ORG 0xc200
MOV AL, 0x13
MOV AH, 0x00
INT 0x10
;font_A
MOV CX, 0
MOV AX, 0xa000
MOV DS, AX
MOV SI, 0x0000
ADD SI, 8*320
ADD SI, 8
loop:
CMP CX, 16
JE fin
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x80
CMP BH, 0
JE L1
MOV BYTE[DS:SI+0], 15
L1:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x40
CMP BH, 0
JE L2
MOV BYTE[DS:SI+1], 15
L2:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x20
CMP BH, 0
JE L3
MOV BYTE[DS:SI+2], 15
L3:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x10
CMP BH, 0
JE L4
MOV BYTE[DS:SI+3], 15
L4:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x08
CMP BH, 0
JE L5
MOV BYTE[DS:SI+4], 15
L5:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x04
CMP BH, 0
JE L6
MOV BYTE[DS:SI+5], 15
L6:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x02
CMP BH, 0
JE L7
MOV BYTE[DS:SI+6], 15
L7:
MOV BX, CX
MOV BH, BYTE[CS:font_A+BX]
AND BH, 0x01
CMP BH, 0
JE L8
MOV BYTE[DS:SI+7], 15
L8:
ADD CX, 1
ADD SI, 320
JMP loop
fin:
HLT
JMP fin
font_A:
DB 0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24
DB 0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00
话说在320*200的分辨率下,8*16的字符看上去确实很大==