讀書筆記《30天自制操作系統》day03

0. 自己試着在win7下用NASM和minGW改寫彙編和C混合編程,結果受挫了。還是先使用作者提供的工具構建吧。

1. 通過前2天的工作已經能使用NASM製作一個映像了,並且編寫的彙編代碼可以成爲引導扇區代碼。

2. 引導扇區代碼中可以調用BIOS中斷,讀取軟盤上其它扇區到內存中,根據FAT12文件系統格式得知,保存到軟盤內的第一個文件的文件名一定從19邏輯扇區開始,且該文件的內容從邏輯扇區33開始(見day01,圖一)。

3. 引導扇區可以將第一個保存的文件(asmhead.nas,功能是跳入保護模式並調用C語言編寫的函數代碼)讀入內存並使之執行,找這個文件用到了一個技巧(如2描述),不然通過文件系統結構分析出文件位置,並加載碼就太複雜了。

4. 引導扇區代碼如下ipl10.asm

CYLS	EQU		10				

		ORG		0x7c00			

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		
		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		"HARIBOTEOS "	
		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	   ;柱面號		
		MOV		DH,0	   ;磁頭號		
		MOV		CL,2	   ;扇區號		
readloop:
		MOV		SI,0			
retry:
		MOV		AH,0x02	   ;讀磁盤	
		MOV		AL,1	   ;讀1個扇區		
		MOV		BX,0       ;目的地址
		MOV		DL,0x00	   ;驅動器號		
		INT		0x13	   ;來BIOS中斷		
		JNC		next			
		ADD		SI,1			
		CMP		SI,5			
		JAE		error	   ;讀五次還失敗就放棄		
		MOV		AH,0x00    ;重置驅動器功能號
		MOV		DL,0x00	   ;驅動器號	
		INT		0x13			
		JMP		retry
next:
		MOV		AX,ES			
		ADD		AX,0x0020   ;保存位置向後移動512字節,0x0020是段地址加偏移量後成爲0x0200了
		MOV		ES,AX			
		ADD		CL,1			
		CMP		CL,18       ;讀18個扇區	
		JBE		readloop		
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		


		MOV		[0x0ff0],CH		
		JMP		0xc200        ;跳到軟盤kernel.sys(asmhead.nas+bootpack.c)文件內部執行
                                              ;該文件在加載軟盤文件基址0x8000+Fat12文件系統中文件出現位置0x004200處=0xc200H
error:
                MOV             SI,msg
putloop:
                MOV		AL,[SI]
                ADD		SI,1
                CMP		AL,0
                JE		fin
                MOV		AH,0x0e
                MOV		BX,15
                INT		0x10
                JMP		putloop
fin:
                HLT
                JMP		fin
msg:
                DB		0x0a, 0x0a
                DB		"load error"
                DB		0x0a
                DB		0;
                RESB	        0x7dfe-$
                times           510-($-$$) db 0
                DB		0x55, 0xaa

BIOS 13中斷說明(功能有磁盤的讀、寫、扇區校驗、尋道)
AH=0x02 讀盤/0x03寫盤/0x04校驗/0x0c尋道
AL=處理連續扇區數
CH=柱面號&0xff
CL=扇區號(0~5位)|(柱面號&0x300)>>2
DH=磁頭號
DL=驅動器號
ES:BX=緩衝地址
返回值:FLAGS=0沒有錯誤AH=0,FLAGS=1有錯誤AH保存錯誤碼

 

5. 跳入保護模式代碼如下asmhead.nas(1)準備GDT(2)用LGDT加載gdtr(3)打開A20(4)設置CR0的PE位(5)跳轉進入保護模式

BOTPAK	EQU		0x00280000		
DSKCAC	EQU		0x00100000		
DSKCAC0	EQU		0x00008000		


CYLS	EQU		0x0ff0			
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			
SCRNX	EQU		0x0ff4			
SCRNY	EQU		0x0ff6			
VRAM	EQU		0x0ff8			

		ORG		0xc200	 ;讓引導扇區加載後從這裏開始運行,認爲它們在一個段中所以能直接跳轉過來		



		MOV		AL,0x13		;保存信息	
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000


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


		MOV		AL,0xff                 ;禁止PIC主從片的中斷
      		OUT		0x21,AL
		NOP					;不能有兩個連續的OUT指令
		OUT		0xa1,AL

		CLI		                        ;禁止PIC工作要在CLI之前				



		CALL	waitkbdout                      ;等待鍵盤電路準備好,要設置A20使1MB以上內存能被訪問
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout


[INSTRSET "i486p"]				

		LGDT	[GDTR0]			        ;加載臨時的GDT表首地址到GDTR寄存器
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	
		OR		EAX,0x00000001	
		MOV		CR0,EAX                 ;設置CR0寄存器PE標誌位
		JMP		pipelineflush           ;設置標誌位之後馬上JMP
pipelineflush:                                          ;從此尋址方式變了
		MOV		AX,1*8                  ;段值的設置,用GDT中那個段(GDT+1段)			
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX



		MOV		ESI,bootpack	        ;將bootpack.c生成的目標代碼移動到0x00280000,乾坤大挪移
		MOV		EDI,BOTPAK		
		MOV		ECX,512*1024/4
		CALL	memcpy



		MOV		ESI,0x7c00              ;將啓動扇區複製到1MB以後的內存		
		MOV		EDI,DSKCAC		
		MOV		ECX,512/4
		CALL	memcpy


		MOV		ESI,DSKCAC0+512	        ;將0x00008200數據複製到0x00100200
		MOV		EDI,DSKCAC+512	
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	        ECX,512*18*2/4	
		SUB		ECX,512/4		
		CALL	memcpy
                ;至此內存中0x00100000部分與磁盤內容就一樣了
   
                ;調用bootpack.c的初始化操作,解析bootpack.hrb的header並傳入參數
		MOV		EBX,BOTPAK
		MOV		ECX,[EBX+16]
		ADD		ECX,3			
		SHR		ECX,2			
		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          ;跳到指定段中跳過可執行文件頭p421

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			
		RET


		ALIGNB	16
GDT0:                                                            ;臨時設計的GDT表
		RESB	8				
		DW		0xffff,0x0000,0x9200,0x00cf	
		DW		0xffff,0x0000,0x9a28,0x0047	

		DW		0
GDTR0:                                                           ;臨時設計的GDT選擇子
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:

6. C語言代碼如下bootpack.c

void io_hlt(void);
void write_mem8(int addr,int data);
void HariMain(void)
{
	int i;
	for(i=0xa0000;i<=0xaffff;i++)
	{
		write_mem8(i,15);        /*向內存的0xa0000~0xaffff位置寫入信息,這塊內存是顯存空間,15是白色*/
 	}
	for(;;)
	{
		io_hlt();
	}

}


7. C語言中調用的io_hlt和write_mem8函數放到了如下代碼中func.asm

[FORMAT "WCOFF"]				
[INSTRSET "i486p"]			
[BITS 32]						
[FILE "naskfunc.nas"]			
global _io_hlt,_write_mem8
[section .text]
;void io_hlt(void);
_io_hlt:
	HLT
	RET
	
;void write_mem8(int addr,int data);
_write_mem8:
	MOV ECX,[ESP+4]
	MOV AL,[ESP+8]
	MOV [ECX],AL
	RET

8. 在toolset文件夾內建立一個新文件夾,將上面所有的文件放在裏邊,編譯鏈接接上面的文件,寫個bat文件如下

nasm -o ipl10.bin ipl10.asm  ;生成引導扇區代碼
nasm -o img.img img.asm      ;生成軟盤鏡像文件
..\z_tools\nask.exe asmhead.nas asmhead.bin
..\z_tools\cc1.exe -I..\z_tools\haribote\ -Os -Wall -quiet -o bootpack.gas bootpack.c
..\z_tools\gas2nask.exe -a bootpack.gas bootpack.nas
..\z_tools\nask.exe bootpack.nas bootpack.obj
..\z_tools\nask.exe func.asm func.obj
..\z_tools\obj2bim.exe @..\z_tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map bootpack.obj func.obj
..\z_tools\bim2hrb.exe bootpack.bim bootpack.hrb 0
copy /B asmhead.bin+bootpack.hrb kernel.sys


9.這樣除了中間文件外,生成img.img文件和kernel.sys文件。使用winImage打開img.img文件將kernel.sys文件加入到該img文件中。

10. 啓動Bochs,呵呵看見屏幕白了,這可是從C代碼裏控制的啊!

11. asmhead中跳入保護模式的代碼慢慢在深入掌握,不然會掉入細節裏不能自拔了。

12. (這句很經典)asmhead和C代碼是通過copy /B進行鏈接的其中asmhead代碼最後留了個標號bootpack,在這個標號後面C的目標代碼被砍去文件頭直接將代碼鏈接到了這裏,所以能實現從彙編跳轉到C語言的目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章