0から作るソフトウェア開発

日々勉強中。。。

0から作るOS開発

環境準備

環境設定

ブートローダ

カーネルローダ

GRUB

カーネル

ドライバーその他

0から作るOS開発 カーネルローダその4 カーネルをロードする

前回までの内容

これまでで、 ということがわかりました。それではカーネルローダの開発を進めていきましょう!

今回はブートローダとカーネルローダの総まとめです

カーネルローダ メインを作っていく

カーネルローダその1 で紹介しましたカーネルローダメインにモジュールを追加していく形で進めていきます

最初のカーネルローダは”Starting.asm”で作成しました

最初に作成したStarting.asmファイル


[BITS 16]
ORG 0x500
	JMP	MAIN2


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Preprocessor directives
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
%include "Print.inc"


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Data Section 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
msgphello		DB 0x0D, 0x0A, "Hello", 0x0D, 0x0A, 0x00


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Kernel Procedure
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:
; 汎用レジスタ初期化
	XOR	AX, AX
	XOR	BX, BX
	XOR	CX, CX
	XOR	DX, DX
; データセグメント初期化
	MOV	DS, AX
	MOV	ES, AX
; メッセージ表示
	MOV	SI, msgphello
	CALL	DisplayMessage
	
	HLT



でした。ここではPrint.incは割愛させていただきます

スタックの初期化とGDTの設定を追加する

スタックの初期化とGDTの設定を追加します。スタックはリアルモードで使用可能な

最大メモリ(0x0009FFFCあたり)をスタックとして使用します

使用メモリについてはカーネルローダその1を参照してください

スタックについてはブートローダその8を参照してください

また、GDTについてはカーネルローダその2を参照してください

Starting.asmファイル

処理を追加していきます


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Kernel Procedure
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:
	
	; MAIN2の続き
	
	MOV	AX, 0x9000		; スタックポインタを0x0009FFFCに設定する
	MOV	SS, AX
	MOV	SP, 0xFFFC
	
	CALL	_setup_gdt		; GDT設定処理関数をコール
	
	; MAIN2が続いていく
	
[BITS 16]

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Set up IDT
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_setup_idt:				; GDT設定処理
	CLI
	PUSHA
	LIDT	[idt_toc]		; GDTを読み込む
	STI
	POPA
	RET

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Global Descriptor Table
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
gdt_toc:
		DW 4*8
		DD _gdt	

_gdt:		
		DW 0x0000		; Null descriptor
		DW 0x0000		
		DW 0x0000		
		DW 0x0000		

		DB 0xFF			; Code descriptor
		DB 0xFF
		DW 0x0000
		DB 0x00
		DB 10011010b
		DB 11001111b
		DB 0

		DB 0xFF			; Data descriptor
		DB 0xFF
		DW 0x0000
		DB 0x00
		DB 10010010b
		DB 11001111b
		DB 0
	
		DW 0x0000		; TEMPORARY - don't use
		DW 0x0000		
		DW 0x0000		
		DW 0x0000		



次にカーネルを読み込んでいきます

カーネルのロード

カーネルのロードには

を行います。ほとんどブートローダその11ででやった内容ですが、少しパワーアップしています

ルートディレクトリ領域でカーネルイメージファイルを探す

カーネルを読み込む前に時間がかかるのでローディングメッセージを表示させています

Starting.asmファイル


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Preprocessor directives
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
%include "Print.inc"
%include "common.inc"
%include "Fat12.inc"

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Data Section 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
LoadingMsg		DB 0x0D, 0x0A, "Searching for System...", 0x00

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Kernel Procedure
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:

	; MAIN2の続き

	MOV	SI, LoadingMsg			; ローディングメッセージ表示
	CALL	DisplayMessage
	
	CALL	Find_File			; Find_File関数をコール
	CMP	AX, 0				; カーネルイメージが見つかったかどうかチェック
	
	; MAIN2が続いていく
	



カーネルイメージを探すFind_File関数は”Fat12.inc”で定義しています

ブートローダその11での復習のつもりで”Fat12.inc”を見て行きましょう

Fat12.incファイル

Fat12.incではFAT12ファイルシステムのドライバを記述しています


;**********************************************************************************
; FAT12 filesystem read only function
;
;**********************************************************************************

%ifndef __FAT12_INC_INCLUDED__
%define __FAT12_INC_INCLUDED__

[BITS 16]
%include "BPB.inc"

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Variable 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
KernelImageCluster DW 0x0000	; 見つかったカーネルイメージの最初のクラスタ番号を保存します

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Define 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
%define ES_BASE_ADDR	0x07C0	; ブートローダのセグメント開始位置
%define RMODE_BASE_SEG	0x0800	; カーネルを読み込むセグメント開始位置(0x00008000)
%define	RMODE_BASE_ADDR 0x0000
%define BX_FAT_ADDR 	0x0200	; 0x000007C00をベースアドレスとしたBXに設定するアドレス
				; ブートローダが読み込んだFAT領域のアドレス 
%define BX_RTDIR_ADDR	0x2600	; 0x000007C00をベースアドレスとしたBXに設定するアドレス
				; ブートローダが読み込んだルートディレクトリ領域のアドレス

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Find Kernel File
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
Find_File:					; カーネルイメージを探索する
	
	PUSHA
	MOV	BX, ES_BASE_ADDR
	MOV	ES, BX
	MOV	BX, BX_RTDIR_ADDR
	MOV	CX, WORD [BPB_RootEntCnt]	; BPB.incに定義
	MOV	SI, KernelImageName		; common.incに定義
Finding_File:

	MOV	DI, BX
	PUSH	CX
	MOV	CX, 0x000B
	PUSH	DI
	PUSH	SI
REPE	CMPSB
	POP	SI
	POP	DI
	JCXZ	Found_File
	ADD	BX, 0x0020
	POP	CX
; 次のエントリへ
	LOOP	Finding_File
	JMP	FAILURE

FAILURE:
	POPA
	MOV	AX, -1				; 見つからなかったときは返り値としてAXに-1を返す

	RET

Found_File:
	POP	CX
	MOV	WORD [KernelImageCluster], BX	; 見つかったファイルの最初のクラスタ番号を保存
	POPA
	MOV	AX, 0				; 見つかった場合は返り値としてAXに0を返す
	
	RET

%endif



ブートローダその11からの変更点は

としています。ここでブートセクタのBPBを再定義している”BPB.inc”を見ていきます

(ブートローダが置いてあるアドレスを見に行くようにしてみるのも面白いと思います。ちょっとめんどくさいですが。。。)

BPB.incファイル

BPB.incではFAT12で使用するブートセクタのBPBを定義しています


;**********************************************************************************
; BIOS parameter block
;
;**********************************************************************************
%ifndef __BPB_INC_INCLUDED__
%define __BPB_INC_INCLUDED__


[BITS 16]
BS_OEMName	DB	"MyOS    "
BPB_BytsPerSec	DW	0x0200		;BytesPerSector
BPB_SecPerClus	DB	0x01		;SectorPerCluster
BPB_RsvdSecCnt	DW	0x0001		;ReservedSectors
BPB_NumFATs	DB	0x02		;TotalFATs
BPB_RootEntCnt	DW	0x00E0		;MaxRootEntries
BPB_TotSec16	DW	0x0B40		;TotalSectors
BPB_Media	DB	0xF0		;MediaDescriptor
BPB_FATSz16	DW	0x0009		;SectorsPerFAT
BPB_SecPerTrk	DW	0x0012		;SectorsPerTrack
BPB_NumHeads	DW	0x0002		;NumHeads
BPB_HiddSec	DD	0x00000000	;HiddenSector
BPB_TotSec32	DD	0x00000000	;TotalSectors

BS_DrvNum	DB	0x00		;DriveNumber
BS_Reserved1	DB	0x00		;Reserved
BS_BootSig	DB	0x29		;BootSignature
BS_VolID	DD	0x20090321	;VolumeSerialNumber
BS_VolLab	DB	"MyOS    "	;VolumeLabel
BS_FilSysType	DB	"FAT12   "	;FileSystemType

%endif



このように再定義しておけばプログラムから直ぐに利用できて便利です

(%defineでもよいかと思います)

次に”common.inc”を見ていきます

common.incファイル

common.incではカーネルローダで使用する共通変数などを定義しています


%ifndef	_COMMON_INC_INCLUDED
%define _COMMON_INC_INCLUDED

; プロテクティッドモードでカーネルイメージを置くアドレス
%define IMAGE_PMODE_BASE 0x100000

; リアルモードでカーネルイメージを置くアドレス
%define IMAGE_RMODE_BASE 0x8000

; カーネルイメージのファイル名(FAT12では11文字にしなければならない)
KernelImageName	DB "KIMAGE     "

; カーネルイメージのファイルサイズを格納する変数
ImageSize 	DD 0x00000000
ImageSizeBX	DW 0x0000
ImageSizeES	DW 0x0000

%endif



各定義は次のように使用しています

カーネルローダではリアルモードでBIOSを利用してカーネルイメージを読み込みます

ですので、このカーネルローダでは読み込めるカーネルイメージは600Kバイト程度となります

カーネルローダその1で説明したように、4GBのメモリ空間を利用できるようにして、

プロテクティッドモードでカーネルイメージを読み込みたいところなのですが、プロテクティッドモードではBIOSが利用できません

(INT命令で利用するBIOSの割り込み処理は16ビット命令ですので、プロテクティッドモードではもはや利用できません)

BIOSが利用できませんので、自前でフロッピーディスクドライバを作成する必要があります

自前で作成してもよいのですが、後でカーネルにフロッピーディスクドライバを組み込んでいきたいのと

世の中には賢い方がいっぱいいらっしゃって、GRUBというブートローダがあります

このサイトでも後々GRUBを利用していきますので、とりあえず今のところ、リアルモードでカーネルを読み込んでいきます

(とりあえずは600Kバイトほどのカーネルが読み込みできますので、相当困ることはありません。困る方はGRUBを導入していきましょう)



上記の理由から、まずリアルモードでカーネルイメージを一時領域(このサイトでは0x00008000)に読み込んでおき、

さしあたっては、プロテクティッドモードに移行してから一時領域にあるカーネルを0x00010000にコピーする方針をとります

カーネルイメージを読み込む

カーネルイメージが見つかりましたのでカーネルイメージを読み込んでいきます

まずはメイン処理の”Starting.asmです

Starting.asmファイルの続き


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Data Section 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
msgFoundFile	DB 0x0D, 0x0A, "System is found!!!", 0x00

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Kernel Procedure
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:
	
	; MAIN2の続き
	
Load_Kernel:				; カーネルをロードする処理
	MOV	SI, msgFoundFile	; カーネルが見つかったメッセージを表示
	CALL	DisplayMessage
	CALL	Load_File		; カーネルをロードする関数をコール
	
	; MAIN2が続く
	



カーネルをロードする処理を見ていきます。これも ブートローダその11 の内容から修正を加えて、

Fat12.inc”ファイルに追加しています

Fat12.incファイル


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Load Kernel File 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
Load_File:
	PUSHA
	MOV	WORD [datasector], 0x0021
	MOV	BX, ES_BASE_ADDR
	MOV	ES, BX
	MOV	BX, WORD [KernelImageCluster]	; カーネルイメージの開始クラスタ番号
	ADD	BX, 0x001A
	MOV	AX, WORD [ES:BX]
	MOV	BX, RMODE_BASE_SEG		; カーネルを読み込むセグメント
	MOV	ES, BX	
	MOV	BX, RMODE_BASE_ADDR 	    ; カーネルを読み込むアドレス
	PUSH	BX
	MOV	WORD [cluster], AX
	
Load_Image:
	MOV	AX, WORD [cluster]
	POP	BX
	XOR	BX, BX
	CALL	ClusterLBA

	XOR	CX, CX
	MOV	CL, BYTE [BPB_SecPerClus]

	CALL	ReadSector
	MOV	BX, ES				
	ADD	BX, 0x0020			; ESを0x200だけずらす
	MOV	ES, BX				; ESを更新する(ESは読み込んだバイト数になる)

ES_ADDED:
	PUSH	BX
; 次のクラスタ番号取得
	MOV	AX, WORD [cluster]
	MOV	CX, AX
	MOV	DX, AX
	SHR	DX, 0x0001
	ADD	CX, DX				; 次のクラスタ番号オフセット取得
	PUSH	ES				; ESをスタックへ
	MOV	BX, ES_BASE_ADDR
	MOV	ES, BX	
	MOV	BX, BX_FAT_ADDR			; ブートローダが読み込んだFATを利用
	ADD	BX, CX				; 次のクラスタ番号のオフセットを足す
	MOV	DX, WORD [ES:BX]
	POP	ES				; ESを復帰(読み込んだバイト数)
	TEST	AX, 0x0001
	JNZ	ODD_CLUSTER
EVEN_CLUSTER:
	AND	DX, 0x0FFF
	JMP	LOCAL_DONE
ODD_CLUSTER:
	SHR	DX, 0x0004
LOCAL_DONE:
	MOV	WORD [cluster], DX
	CMP	DX, 0x0FF0
	JB	Load_Image
		
ALL_DONE:
	POP	BX	
	XOR	BX, BX
	MOV	WORD [ImageSizeBX], BX		; 0クリアしています(無駄な処理です)
	MOV	BX, ES
	SUB	BX, RMODE_BASE_SEG		; リードしたバイト数を計算
	MOV	WORD [ImageSizeES], BX		; 保存する
	POPA
	RET

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; ReadSector
; Read 1 Sector 
; Input: BX:address  
;      : AX:sector number
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
ReadSector:
	MOV	DI, 0x0005			; エラーがあった場合5回まで繰り返す
SECTORLOOP:
	PUSH	AX
	PUSH	BX
	PUSH	CX
	CALL	LBACHS
	MOV	AH, 0x02			; BIOSのリードセクタ
	MOV	AL, 0x01			; 1セクタ読み込み
	MOV	CH, BYTE [absoluteTrack]	; シリンダ
	MOV	CL, BYTE [absoluteSector]	; セクタ
	MOV	DH, BYTE [absoluteHead]		; ヘッド
	MOV	DL, BYTE [BS_DrvNum]		; ドライブ
	INT	0x13				; BIOS処理を呼出す
	JNC	SUCCESS				; エラーチェック
	MOV	AH, 0x01
	INT	0x13

	XOR	AX, AX				; フロッピーディスクをリセット
	INT	0x13				; BIOS処理を呼出す
	DEC	DI				; エラーカウンタを減らす
	POP	CX
	POP	BX
	POP	AX
	JNZ	SECTORLOOP			; 処理を繰り返す
	INT	0x18
SUCCESS:
	POP	CX
	POP	BX
	POP	AX
	RET

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA adressing scheme
; LBA = (cluster - 2 ) * sectors per cluster
; INPUT : AX : cluster number
; OUTPUT : AX : base image sector
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
ClusterLBA:
	SUB	AX, 0x0002
	XOR	CX, CX
	MOV	CL, BYTE [BPB_SecPerClus]
	MUL	CX
	ADD	AX, WORD [datasector]
	RET

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
; PROCEDURE LBACHS
; convert LBA addressing scheme to CHS addressing scheme
; absolutesector = (logical sector / setors per track) + 1
; absolute head  = (logical sector / sectors per track) MOD number of heads
; absolute track = (logical sector / ( sectors per track * number of heads ) )
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
LBACHS:
	XOR	DX, DX
	DIV	WORD [BPB_SecPerTrk]
	INC	DL
	MOV	BYTE [absoluteSector], DL
	XOR	DX, DX
	DIV	WORD [BPB_NumHeads]
	MOV	BYTE [absoluteHead], DL
	MOV	BYTE [absoluteTrack], AL
	RET	



ブートローダその11からの変更点は

となります。ESが読み込んだバイト数をあらわしていますがセグメントレジスタですので、ESの値×0x10が

読み込んだバイト数となることに注意してください(やけにややこしいプログラムしてます。。。)

これでカーネルイメージの読み込みは完了しました。次にプロテクティッドモードへ移行します

プロテクティッドモードへの移行


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Preprocessor directives
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
%include "Print.inc"
%include "common.inc"
%include "Fat12.inc"
%include "A20.inc"

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Define Section 
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
%define	NULL_DESC	0
%define CODE_DESC	0x8
%define	DATA_DESC	0x10

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Kernel Procedure
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
MAIN2:
	
	; MAIN2の続き
	
EnableA20:
	CALL	Enable_A20
	
Enter_pmode:

	CLI
	MOV	EAX, CR0
	;without paging 
	OR	EAX, 0x00000001
	MOV	SI, msgpmode
	CALL	DisplayMessage
	MOV	CR0, EAX
	JMP	CODE_DESC:Pmode_start

;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Protected Mode
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
[BITS 32]
Pmode_start:
	MOV	AX, DATA_DESC
	MOV	SS, AX
	MOV	ES, AX
	MOV	FS, AX
	MOV	GS, AX
	MOV	DS, AX

	MOV	ESP, 90000h
	
	; MAIN2が続く
	



ここではA20を有効にしてプロテクティッドモードへ移行しています

A20を有効にするソースはカーネルローダその3と同様となりますので割愛させていただきます

カーネルイメージのコピーとカーネル起動

カーネルの読み込みが終わったので、カーネルを0x00010000へコピーし、カーネルを起動します

Starting.asmファイル


;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
;
; Starting Protected Mode
;
;/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
[BITS 32]
Pmode_start:					; プロテクティッドモード開始
	MOV	AX, DATA_DESC			; セグメントセレクタを初期化
	MOV	SS, AX
	MOV	ES, AX
	MOV	FS, AX
	MOV	GS, AX
	MOV	DS, AX

	MOV	ESP, 90000h

CopyKernelImage:				; カーネルイメージを0x00010000へコピー
; get kernel image size
	XOR	EAX, EAX
	MOVZX	EAX, WORD [ImageSizeES]		; 読み込んだバイト数を取得
	SHL	EAX, 0x4			; 読み込んだバイト数(セグメントレジスタの値)
						; から実バイト数を計算(0x10をかける)
	MOV	DWORD [ImageSize], EAX		; カーネルイメージのサイズを保存
; copy
	CLD					; ディレクションフラグをクリア
	MOV	ESI, IMAGE_RMODE_BASE		; 読み込んだカーネルイメージの先頭アドレス
	MOV	EDI, IMAGE_PMODE_BASE		; コピー先のアドレス(0x00010000)
	MOV	ECX, EAX
REP	MOVSD					; ESIからEDIのアドレスに1バイトずつコピー
						; (ECXのバイト数分繰り返す)
	JMP	EXECUTE				; カーネル実行処理へジャンプ


Failure2:					; 失敗時の処理。無限ループ
	HLT
	JMP	Failure2

EXECUTE:
	;-------------------------------------------
	; Execute Kernel
	;-------------------------------------------	
	MOV	EBX, IMAGE_PMODE_BASE		; カーネルの先頭アドレスをEBXに入れる
	MOV	EBP, EBX			; そしてEBPに入れる

	XOR	EBX, EBX
	CLI					; 割り込み禁止
	CALL	EBP				; カーネルのエントリを関数コールします
	ADD	ESP, 4
	JMP	Failure2



プロテクティッドモードに入ってからの処理を行っています

ここの処理では

となります。少しあほな処理となっていますが、もっときちんとした処理を実装していただければとおもいます

また、アセンブラ言語かC言語かでフロッピーディスクドライバを実装して、プロテクティッドモードでカーネルを

読み込めるようにして、大きなカーネルでもロードできるようにしても面白いとおもいます

また、今後はこの方法とは別にGRUBでのカーネル起動も紹介していきたいと思います

(ちょっと後になりますが。。。)

以上でブートローダからカーネルローダを読み込み、カーネルローダからカーネルを読み込んで実行することが

できました。次回はいよいよカーネルの実装へいきたいと思います

inserted by FC2 system