30天自制作業系統(一)啟動區

计算机知识杂谈發表於2024-10-19

一、啟動區

	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的字元看上去確實很大==

相關文章