まりものメモ帳

なぐり書き

Ubuntu 18.04で30日OS自作入門をやりたい[3日目-1]

Ubuntu 18.04で「30日でできる!OS自作入門」をやりたい[2日目] - まりものメモ帳の続きです。
定期試験と文化祭とかいろいろ重なっていつの間にかこんな時期です。終わるのかこれ。まずいでしょ。
前回と間が空き過ぎてて「あっ…(察し)」と思った方もいるかと思いますが大丈夫です。俺は生きてる。
というわけで3日目やっていきます。

使ったツール

詳しくは二日目を参照して下さい。

アセンブリタイム

やることは特に変わらず、nasmくんが読んでくれるように頑張りながらアセンブリを写経します。

IPL作り

ipl.asm

;haribote-ipl
;TAB=4

CYLS EQU 10						;CYLS = 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 "	;11byte
		DB		"FAT12   "		;8byte
		TIMES	18	DB	0

entry:
		MOV		AX, 0
		MOV		SS, AX
		MOV		SP, 0x7c00		;0x7c00にブートセクタを読み込む
		MOV		DS, AX

;Read Disk
		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		;INT命令用
		MOV		AL, 1
		MOV		BX, 0
		MOV		DL, 0x00		;ドライブ番号0 <--①
		INT		0x13    		;disk BIOSコール(AH=0x02) <--②-1
		JNC		next			;エラーがなければnextへ
		ADD		SI, 1			;SIレジスタ(失敗回数) + 1
		CMP		SI, 5			;SIと5を比較
		JAE		error			;SI >= 5のときerrorへ
		MOV		AH, 0x00		;INT命令用
		MOV		DL, 0x00		;ドライブ番号0
		INT		0x13			;disk BIOSコール(AH=0x00) <--②-2
		JMP		retry

next:
		MOV		AX, ES			;アドレスを0x200(=512=1セクタ)進める
		ADD		AX, 0x20
		MOV		ES, AX			;ADD ES, 0x20という命令が無い
		ADD		CL, 1			;CL(セクタ番号)を1増やす
		CMP		CL, 18			;CLと18を比較
		JBE		readloop		;CL <= 18の時readloopへ
		MOV		CL, 1			;CL=1
		ADD		DH, 1			;DH(ヘッダ番号)を1増やす
		CMP		DH, 2			;DHと2を比較
		JB		readloop		;DH < 2の時readloopへ
		MOV		DH, 0			;DH=0
		ADD		CH, 1			;CH(シリンダ番号)を1増やす
		CMP		CH, CYLS		;CHとCYLS(=10)を比較
		JB		readloop		;CH < CYLSの時readloopへ

fin:
		HLT
		JMP		fin

error:
		MOV		SI, msg			;SIにmsgのメモリ番地を代入

putloop:
		MOV		AL, [SI]		;ALにSI番地の中身を渡す
		ADD		SI, 1			;SIを1増やす
		CMP		AL, 0			;ALと0を比較
		JE		fin				;AL=0のときfinへ
		MOV		AH, 0x0e
		MOV		BX, 15
		INT		0x10			;video BIOSのコール(AH=0x0e, BX=15)
		JMP		putloop

msg:
		DB		0x0a, 0x0a
		DB		"load error"	;エラーメッセージ
		DB		0x0a
		DB		0

		TIMES	0x7dfe-0x7c00-($-$$)	DB	0

		DB		0x55, 0xaa		;有効なブートセクタであることを示す

コメントアウトの作業が一番疲れた…
いきなり

  • エラーになったらやり直す
  • 18セクタ読む
  • 10シリンダ読む

所までやっちゃいました。
本との変更点を以下に記します。

  1. RESB命令をTIMES DB命令に
  2. 0x7dfe-$0x7dfe-0x7c00-($-$$)

調べたこととか

そもそもIPLってなんだ

IPL(Initial Program Loader)というのはまあ名前の通りで、コンピュータの電源をONにしたときに最初に実行されるプログラムのことです。今回はこれを作ってます。

ヘッダ・シリンダ・セクタの話

フロッピーディスクをパソコンで使用するには、記憶領域を部分ごとに分けて、どの部分に何を記録したかを管理するための領域を確保する必要があります。その「部分ごと」の単位がヘッダ・シリンダ・セクタです(多分)。
ディスクには表裏2つのヘッダがあって、1つのヘッダあたり80シリンダあって、1つのシリンダに18セクタあります。そんでもって1セクタは512バイトです。
なのでフロッピーディスクの記憶容量は
2 * 80 * 18 * 512 = 1474560バイト = 1440キロバイトとなります。

ソースコードについて

(大抵ソースコードコメントアウトでベタ書きしたんでそれを見て下さい)

CH, CL, DH, DLレジスタにはそれぞれシリンダ番号、セクタ番号、ヘッダ番号、ドライブ番号を代入しなければならないそうです。

INT 0x13はディスク関係のBIOSをコールする割り込み命令です。
例えば②-1を見るとAHレジスタ0x02を渡してます。これは、http://oswiki.osask.jp/?%28AT%29BIOS#q5006ed6を参照すると

AH = 0x02; (読み込み時)

よりディスクを読みこんでいることがわかります。

実行

お次はMakefileです。
Makefile

default:
	make img

ipl.bin: ipl.asm Makefile
	nasm ipl.asm -o ipl.bin -l ipl.lst
helloos.img: ipl.bin Makefile
	cat ipl.bin > helloos.img

asm:
	make -r ipl.bin
img:
	make -r helloos.img
run:
	make img
	qemu-system-i386 -fda helloos.img    #<- (1)

(1)でqemuに-fdaオプションをつけてますが、これはフロッピーディスクからの起動であることを明示してます。ないと動かないみたい。

何はともあれ実行してみましょう、当たって砕けろ。

$ make run
make img
make[1]: ディレクトリ '/home/admarimoin/project/os/day3' に入ります
make -r helloos.img
make[2]: ディレクトリ '/home/admarimoin/project/os/day3' に入ります
nasm ipl.asm -o ipl.bin -l ipl.lst
cat ipl.bin > helloos.img
make[2]: ディレクトリ '/home/admarimoin/project/os/day3' から出ます
make[1]: ディレクトリ '/home/admarimoin/project/os/day3' から出ます
qemu-system-i386 -fda helloos.img
WARNING: Image format was not specified for 'helloos.img' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.

で、結果はこんな感じ。
f:id:admarimoin:20181108030555p:plain
Boot failedとか言われてますけどエラーメッセージ出てないんで大丈夫っぽいです。よかったよかった。(エラーだったらload failedと表示される)

メッチャ疲れました。でもこれまだ3日目前半なんですよね……