30天自制作業系統:第三天

若 光發表於2020-10-20

對第二天程式碼進行了修改,只列印hello ,uos沒一點意思。

讀取磁碟上10個柱面的1-18個扇區,(目前ssd已經沒有柱面這個概念了)。讀出來的資料放入記憶體0x8200起始的地方。

啟動區放在0x8000記憶體扇區中。為什麼要放在0x8000以後的記憶體中的呢? 只是因為這塊記憶體沒有用而已。

為什麼要將啟動程式(img的0扇區)放在0x7c00處? 這是ibm規定的。

向一個空軟盤儲存檔案時:

​ 1.檔名會寫在0x002600以後的地方。

​ 2.檔案內容會寫在0x004200以後的地方。

所以若想啟動位於0x004200的程式,就得讓載入程式執行完成後跳轉到0x8000+0x4200=0xc200處。

作者這一塊寫的很混亂啊,我們們整理一下為啥是0xc200地址,看下圖:

在這裡插入圖片描述

bios會把磁碟0位置的內容拷貝到記憶體0x7c00這個位置然後跳過去執行,
也就是把A拷貝到了記憶體,然後執行A
A會把磁碟後面的內容從記憶體0x8200開始拷貝
這樣的話磁碟0x4200位置就會對應到記憶體0xC200
一個扇區512位元組,十六進位制表示就是0x200

程式的執行情況:

1.bios讀取磁碟0扇區到0x7c00處。

2.bios跳轉到0x7c00處開始執行,該處為ipl10.nas程式,該程式功能為載入磁碟[1-最後]扇區到記憶體的0x8200處。並跳轉到0xc200處執行。

3.0xc200處為asmhead.nas程式,該程式功能為,呼叫顯示卡bios,設定畫面模式,呼叫作業系統程式碼。

4.作業系統程式碼目前就一個功能就是讓cpu睡眠,開始進入c程式。

下面根據功能修改程式碼:

1.修改ipl.nas

ipl10.nas:

; haribote-ipl
; TAB=4

CYLS	EQU		10				; 宣告CYLS=10

		ORG		0x7c00			; 指明程式裝載地址

; 標準FAT12格式軟盤專用的程式碼 Stand FAT12 format floppy code

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 啟動扇區名稱(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		"HARIBOTEOS "	; 磁碟的名稱(必須為11字?,不足填空格)
		DB		"FAT12   "		; 磁碟格式名稱(必??8字?,不足填空格)
		RESB	18				; 先空出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		SI,0			; 記錄失敗次數暫存器

retry:
		MOV		AH,0x02			; AH=0x02 : 讀入磁碟
		MOV		AL,1			; 1個扇區
		MOV		BX,0
		MOV		DL,0x00			; A驅動器
		INT		0x13			; 呼叫磁碟BIOS
		JNC		next			; 沒出錯則跳轉到next
		ADD		SI,1			; 往SI加1
		CMP		SI,5			; 比較SI與5
		JAE		error			; SI >= 5 跳轉到error
		MOV		AH,0x00
		MOV		DL,0x00			; A驅動器
		INT		0x13			; 重置驅動器
		JMP		retry
next:
		MOV		AX,ES			; 把記憶體地址後移0x200(512/16十六進位制轉換)
		ADD		AX,0x0020
		MOV		ES,AX			; ADD ES,0x020因為沒有ADD ES,只能通過AX進行
		ADD		CL,1			; 往CL裡面加1
		CMP		CL,18			; 比較CL與18
		JBE		readloop		; CL <= 18 跳轉到readloop
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		; DH < 2 跳轉到readloop
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		; CH < CYLS 跳轉到readloop

; 讀取完畢,跳轉到haribote.sys執行!
		MOV		[0x0ff0],CH		; 記下IPL讀到哪裡了
		JMP		0xc200

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; 給SI加1
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 顯示一個文字
		MOV		BX,15			; 指定字元顏色
		INT		0x10			; 呼叫顯示卡BIOS
		JMP		putloop

fin:
		HLT						; 讓CPU停止,等待指令
		JMP		fin				; 無限迴圈

msg:
		DB		0x0a, 0x0a		; 換行兩次
		DB		"load error"
		DB		0x0a			; 換行
		DB		0

		RESB	0x7dfe-$		; 填寫0x00直到0x001fe

		DB		0x55, 0xaa

我們在使用段暫存器時,以ES:BX這種方式表示地址,寫成"MOV AL, [ES:BX]"她代表ES×16+BX記憶體地址。

2.修改asmhead.nas

; haribote-os boot asm
; TAB=4

;一些定義
BOTPAK	EQU		0x00280000		; bootpack�̃��[�h��
DSKCAC	EQU		0x00100000		; �f�B�X�N�L���b�V���̏ꏊ
DSKCAC0	EQU		0x00008000		; �f�B�X�N�L���b�V���̏ꏊ�i���A�����[�h�j

; 有關BOOT_INFO
CYLS	EQU		0x0ff0			; 設定啟動區
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 該位置儲存顏色數目的資訊,顏色的位數。
SCRNX	EQU		0x0ff4			; 該位置儲存 解析度的x
SCRNY	EQU		0x0ff6			; 該位置儲存 解析度的y
VRAM	EQU		0x0ff8			; 影像緩衝區的開始地址。

		ORG		0xc200			; 這個程式需要裝載到記憶體的什麼地方呢。

; 畫面設定

		MOV		AL,0x13			; VGA顯示卡,320*320*8位彩色,調色盤模式。
		MOV		AH,0x00
		INT		0x10			;呼叫顯示卡bios的函式,切換顯示模式。
		MOV		BYTE [VMODE],8	; 將畫面模式資訊儲存到這些記憶體地址中。
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000		
;VRAM指的時顯示卡記憶體,也就是用來顯示畫面的記憶體。這一塊記憶體地址都對應著畫面上的畫素。
;VRAM在0xa0000~0xaffff之間的64kb。 VRAM分佈在記憶體分佈圖中的好幾個不同的地方。

; 用bios取得鍵盤上各種led燈的狀態。

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

;=====================================後邊的留以後再看,這塊時呼叫bootpack.c程式的======================
; 防止PIC接受所有中斷
;	AT相容機的規範、PIC初始化
;	然後之前在CLI不做任何事就掛起
;	PIC在同意後初始化

		MOV		AL,0xff
		OUT		0x21,AL
		NOP						; ; 不斷執行OUT指令
		OUT		0xa1,AL

		CLI						;進一步中斷CPU

; ; 讓CPU支援1M以上記憶體、設定A20GATE

		CALL	waitkbdout
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout

; 保護模式轉換

[INSTRSET "i486p"]				; 說明使用486指令

		LGDT	[GDTR0]			;設定臨時GDT
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	; 使用bit31(禁用分頁)
		OR		EAX,0x00000001	; bit0到1轉換(保護模式過渡)
		MOV		CR0,EAX
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			;  寫32bit的段
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX

;bootpack傳遞

		MOV		ESI,bootpack	; 源
		MOV		EDI,BOTPAK		; 目標
		MOV		ECX,512*1024/4
		CALL	memcpy

; 傳輸磁碟資料

; 從引導區開始

		MOV		ESI,0x7c00		; 源
		MOV		EDI,DSKCAC		; 目標
		MOV		ECX,512/4
		CALL	memcpy

; 剩餘的全部

		MOV		ESI,DSKCAC0+512	; 源
		MOV		EDI,DSKCAC+512	; 目標
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; 除以4得到位元組數
		SUB		ECX,512/4		; IPL偏移量
		CALL	memcpy

; 由於還需要asmhead才能完成
; 完成其餘的bootpack任務

; bootpack啟動

		MOV		EBX,BOTPAK
		MOV		ECX,[EBX+16]
		ADD		ECX,3			; ECX += 3;
		SHR		ECX,2			; ECX /= 4;
		JZ		skip			; 傳輸完成
		MOV		ESI,[EBX+20]	; 源
		ADD		ESI,EBX
		MOV		EDI,[EBX+12]	; 目標
		CALL	memcpy
skip:
		MOV		ESP,[EBX+12]	; 堆疊的初始化
		JMP		DWORD 2*8:0x0000001b

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		; AND結果不為0跳轉到waitkbdout
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			; 運算結果不為0跳轉到memcpy
		RET
; memcpy地址字首大小

		ALIGNB	16
GDT0:
		RESB	8				; 初始值
		DW		0xffff,0x0000,0x9200,0x00cf	; 寫32bit位段暫存器
		DW		0xffff,0x0000,0x9a28,0x0047	; 可執行的檔案的32bit暫存器(bootpack用)

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:

3.加入bootpack.c作業系統程式碼

這個作業系統實現了一個最簡單的功能:讓cpu睡眠

void io_hlt(void);


void HariMain(void)
{

fin:
	io_hlt(); /* 執行naskfunc.nas裡邊的_io_hlt()函式。 */
	goto fin;

}

4.加入naskfunc.nas

加入這個檔案是因為c程式不能呼叫HLT指令,所以使用c程式呼叫匯程式設計序,在彙編程式中用HLT讓cpu睡眠。

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 製作目標檔案的模式	
[BITS 32]						; 製作32位模式用的機器語言


; 製作目標檔案的資訊。
[FILE "naskfunc.nas"]			; 原始檔名資訊

		GLOBAL	_io_hlt			; 程式中包含的函式名


;實際的函式

[SECTION .text]		;目標中間中寫了這些之後再寫程式

_io_hlt:	; void io_hlt(void); 這個函式只執行了一個HLT命令,讓cpu睡眠。
		HLT
		RET

5.執行結果

在這裡插入圖片描述
本文程式碼下載地址:https://download.csdn.net/download/u011164819/12981508

相關文章