忍者ブログ

Cyber Bird

   

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

OS自作入門 onLinux 3日目

文化祭関連の準備で忙しい。。。
10月が終われば大分楽になりそう。



3日目には手こずらされました。
何かって、まずasmhead.nasの内容が難解なのと、
筆者作の.hrbフォーマットの構造を知らずに適当に書いてたことかな。

でも、なんとか頑張ってGASに移植できました。
勿論、筆者作のedimg.exeや.hrb形式や.bim形式は一切利用しませんでした。

ちょっと4日目の内容に食い込んでますが、ここまでやらないと
成功したか確認できなかったので。

f81a6253.png

自作本中ではカラーコード15(白)でしたが、適当に10にしたら緑でした。

続きからどうぞ。

.equ CYLS, 10

.text
.code16
	jmp entry

	.byte 0x90
	.ascii "HELLOIPL"		# ブートセクタの名前
	.word 512			# 1セクタの大きさ
	.byte 1				# クラスタの大きさ
	.word 1				# FATがどこから始まるか
	.byte 2				# FATの個数
	.word 224			# ルートディレクトリのサイズ
	.word 2880			# このドライブの大きさ
	.byte 0xf0			# メディアのタイプ
	.word 9				# FAT領域の長さ
	.word 18			# 1トラックにいくつのセクタがあるか
	.word 2				# ヘッドの数
	.int 0				# 必ず0
	.int 2880			# ドライブのサイズ
	.byte 0, 0, 0x29
	.int 0xffffffff			# ボリュームシリアル番号
	.ascii "HELLO-OS   "		# ディスクの名前
	.ascii "FAT12   "		# フォーマットの名前
.skip 18, 0x00				# 18バイト空ける

# プログラム本体
entry:
	movw $0, %ax			# レジスタ初期化
	movw %ax, %ss
	movw $0x7c00, %sp
	movw %ax, %ds
	movw %ax, %es
	
	movw $0x0820, %ax
	movw %ax, %es
	movb $0x00, %ch			# シリンダ0
	movb $0x00, %dh			# ヘッド0
	movb $0x02, %cl			# セクタ2

readloop:
	movw $0x00, %si			# 失敗回数のカウンタ
retry:
	movb $0x02, %ah			# ディスク読み込み
	movb $0x01, %al			# 1セクタ
	xorw %bx, %bx
	movb $0x00, %dl			# Aドライブ
	int $0x13
	jnc next
	addw $0x01, %si
	cmpw $0x05, %si			# 5回失敗したらエラー
	jae error
	movb $0x00, %ah
	movb $0x00, %dl			# Aドライブ
	int $0x13			# ドライブのリセット
	jmp retry

next:
	movw %es, %ax
	addw $0x0020, %ax		# アドレスを0x0200進める
	movw %ax, %es
	addb $0x01, %cl
	cmpb $18, %cl			# 18セクタまで読み込む
	jbe readloop

	movb $0x01, %cl
	addb $0x01, %dh
	cmpb $0x02, %dh			# 裏ヘッダを読み込む
	jb readloop
	movb $0x00, %dh
	addb $0x01, %ch
	cmpb $CYLS, %ch			# CYLSシリンダまで読み込む
	jb readloop

_load_fin:
	movb $CYLS, (0x0ff0)

	jmp 0xc200

error:
	movw $load_err, %si
	call print
_error_fin:
	hlt
	jmp _error_fin

# %si = string adress
print:
	movb (%si), %al
	addw $1, %si
	cmpb $0, %al
	je _print_fin
	movb $0x0e, %ah			# 一文字表示BIOSコール
	movw $15, %bx			# カラーコード
	int $0x10			# ビデオBIOS呼び出し
	jmp print
_print_fin:
	ret

.data
load_err:	.string "load error\n"
IPL(ipl.s)です。前回からの変更点は、FDイメージを10シリンダまで
読み込んでいることと、最後に0xc200にジャンプしていることです。
詳細は自作本をご覧ください。

また、_load_finでCYLSの値、つまり読み込んだシリンダ数を
0x0ff0に格納しています。0x0ff0はシリンダ数を格納するようになっています。

.equ BOTPAK,	0x00280000
.equ DSKCAC,	0x00100000
.equ DSKCAC0,	0x00008000

.equ CYLS,		0x0ff0
.equ LEDS,		0x0ff1
.equ VMODE,		0x0ff2
.equ SCRNX,		0x0ff4
.equ SCRNY,		0x0ff6
.equ VRAM,		0x0ff8

.text
.code16
head:
	movb $0x13, %al
	movb $0x00, %ah
	int $0x10

	movb $0x08, (VMODE)
	movw $320, (SCRNX)
	movw $200, (SCRNY)
	movl $0x000a0000, (VRAM)

	movb $0x02, %ah
	int $0x16
	movb %al, (LEDS)

# 32ビットプロテクトモードへ移行
	# PICへの割り込み禁止
	movb $0xff, %al
	outb %al, $0x21
	nop
	outb %al, $0xa1
	cli				# CPUレベルでも割り込み禁止

	# A20信号線をON
	call waitkbdout
	movb $0xd1, %al
	outb %al, $0x64
	call waitkbdout
	movb $0xdf, %al
	outb %al, $0x60			# enable A20
	call waitkbdout

.arch i486				# 32bitネイティブコード
	lgdtl (GDTR0)			# 暫定GDTを設定
	movl %cr0, %eax
	andl $0x7fffffff, %eax		# bit31を0に(ページング禁止)
	orl $0x00000001, %eax		# bit0を1に(プロテクトモード移行)
	movl %eax, %cr0
	jmp pipelineflash
pipelineflash:
	movw $1*8, %ax			# 読み書き可能セグメント32bit
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movw %ax, %ss

# bootpackの転送
	movl $bootpack, %esi
	movl $BOTPAK, %edi
	movl $512*1024/4, %ecx
	call memcpy

# ブートセクタの転送
	movl $0x7c00, %esi
	movl $DSKCAC, %edi
	movl $512/4, %ecx
	call memcpy

# 残り
	movl $DSKCAC0+512, %esi
	movl $DSKCAC+512, %edi
	movl $0x00, %ecx
	movb (CYLS), %cl
	imull $512*18*2/4, %ecx
	subl $512/4, %ecx
	call memcpy

# start bootpack
	movl $BOTPAK, %ebx
	movl $0x11a8, %ecx
	addl $3, %ecx
	shrl $2, %ecx
	jz skip
	movl $0x10c8, %esi
	addl %ebx, %esi
	movl $0x00310000, %edi
	call memcpy
skip:
	movl $0x00310000, %esp
	ljmpl $2*8, $0x00000000

###########################
# function

waitkbdout:
	inb $0x64, %al
	andb $0x02, %al
	inb $0x60, %al
	jnz waitkbdout
	ret

memcpy:
	movl (%esi), %eax
	addl $4, %esi
	movl %eax, (%edi)
	addl $4, %edi
	subl $1, %ecx
	jnz memcpy
	ret

##########################
# GDT
.align 8
GDT0:
.skip 8, 0x00
	.word 0xffff, 0x0000, 0x9200, 0x00cf	# 読み書き可能セグメント32bit
	.word 0xffff, 0x0000, 0x9a28, 0x0047	# 実行可能セグメント32bit

	.word 0x0000

GDTR0:
	.word 8*3-1
	.int GDT0

.align 8
bootpack:
asmhead.nasを改良して、head.sとしました。
大きな変更点は、
.arch i486で32bitコードになる
・#start bootpackの部分でレジスタに即値を代入している
・far jump(ljmp)で第2セグメントの0x00番地にジャンプしている

さて、1つ目はGASの仕様なので置いておきます。
2つ目と3つ目ですが、ともにhrbフォーマットに関わることです。
hrbフォーマットは以下のようになっています。

[ .hrbファイルの構造 ]

+ 0 : stack+.data+heap の大きさ(4KBの倍数)
+ 4 : シグネチャ "Hari"
+ 8 : mmarea の大きさ(4KBの倍数)
+12 : スタック初期値&.data転送先
+16 : .dataのサイズ
+20 : .dataの初期値列がファイルのどこにあるか
+24 : 0xe9000000
+28 : エントリアドレス-0x20
+32 : heap領域(malloc領域)開始アドレス

参考URL:http://blogs.dion.ne.jp/kazuu/archives/3051835.html

元々レジスタに代入しているのは、hrbのヘッダ部分の値です。
これは固定値なので、即値代入します。値は自作本P.170の通りです。

そして、0x00番地へのジャンプについてですが、元々は0x1bにジャンプしています。
第2セグメントはbootpack.hrbがあるわけですが(そうなるようhead.sでコピーした)、
bootpack.hrbの0x1bとは、ヘッダ部分です。

0xe9 0x90 0x00 0x00 0x00
⇒ jmp [エントリーアドレス]


つまり、bootpack.hrbのエントリーポイント、自作本ならばbootpack.cの
HariMain関数に飛んでいます。
ならば、始めからbootpack.hrbの中身に飛ばせばいいんです。
バイナリフォーマットなら、0x00番地から実行データなので、
直接0x00番地に飛ばします。

OSNAME=os

ASRC=./src/asm
CSRC=./src/c
OBJ=./obj
LS=./ls

IMG=$(OSNAME).img
OSSYS=$(OBJ)/$(OSNAME).sys
IPL=$(OBJ)/ipl.bin

BINOPT=-nostdlib -Wl,--oformat=binary
QEMUOPT=-m 32 -localtime -vga std -fda

$(IMG) : $(OSSYS) $(IPL)
    mformat -f 1440 -C -B $(IPL) -i $(IMG) ::
    mcopy $(OSSYS) -i $(IMG) ::

$(OSSYS) : $(ASRC)/head.s $(ASRC)/func.s $(CSRC)/bootpack.c
    gcc $(ASRC)/head.s -nostdlib -T$(LS)/head.ls -o $(OBJ)/head.bin
    gcc $(CSRC)/*.c $(BINOPT) -c -o $(OBJ)/boot.o
    as $(ASRC)/func.s -o $(OBJ)/func.o
    ld -o $(OBJ)/boot.bin -e Main --oformat=binary $(OBJ)/boot.o $(OBJ)/func.o
    cat $(OBJ)/head.bin $(OBJ)/boot.bin > $(OSSYS)

$(IPL) : $(ASRC)/ipl.s
    gcc $(ASRC)/ipl.s -nostdlib -T$(LS)/ipl.ls -o $(IPL)

run        : $(IMG)
    qemu $(QEMUOPT) $(IMG)
debug    : $(IMG)
    qemu -s -S $(QEMUOPT) $(IMG) -redir tcp:5555:127.0.0.1:1234 &
img        :;    make $(IMG)
clean    :;    rm $(OBJ)/*
Makefileです。今回は色々追加しました。

ファイル名はちょっと個人的にいくつか変えているので、対応を以下に示します。
ipl10.nas ⇒ ipl.s
asmhead.nas ⇒ head.s
naskfunc.nas ⇒ func.s
bootpack.c そのまま
asmhead.bin ⇒ head.bin
bootpack.hrb ⇒ boot.bin
haribote.sys ⇒ os.sys
haribote.img ⇒ os.img

$(IMG)、つまりイメージファイルの作成ルールでmcopyコマンドを使っています。
これはedimgにあたるもので、FDイメージにファイルを書き込みます。

$(OSSYS)の作成ルールのコマンド4行目で、自分でld(リンカ)にオブジェクトファイルを
通しています。
-eオプションでエントリポイントを選択できます。デフォルトは勿論mainですよね。
ここで、オブジェクトファイルを通す順番も変えてはいけません。
なぜなら、boot.oを最初に通さなければ、boot.oの始めに入ってくる
エントリポイントのMain関数がboot.binの0x00に来ないからです。


あとは、debugコマンドを入れておきました。
これで、gdb経由でqemuをデバッグできます。この詳細は後日。
正直、これにはとても助けられました^^;


make runを実行すると、以下のようにファイルが作成されます。

head.s ⇒ head.bin
bootpack.c ⇒ boot.o
func.s ⇒ func.o
boot.o + func.o ⇒ boot.bin
head.bin + boot.bin ⇒ os.sys

ipl.s ⇒ ipl.bin

ipl.bin + os.sys ⇒ os.img

そして、qemuにos.imgを通します。



ちょっと複雑になったので、ソースをアップしておきます。
os03.tar.gz ⇒ こちら

説明が不足しているかもしれないので、質問は遠慮なくどうぞー。
PR

COMMENT

NAME
TITLE
MAIL(非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS(コメント編集に必須です)
SECRET
管理人のみ閲覧できます

無題

  • by NONAME
  • 2011/10/27(Thu)21:08
  • Edit
pipelineflash → pipelineflush
0xc700 → 0x7c00

無題

  • by levelfour
  • 2011/10/29(Sat)22:14
  • Edit
ご指摘ありがとうございます。
まさかアドレスを間違えていたとは…。
今後とも気をつけていきます><

No Title

  • by 菜々氏
  • 2012/09/27(Thu)19:35
  • Edit
os03.tar.gzをダウンロードさせて頂きましたが、その中のhead.sも0xc700のままになっていませんか?

Re:No Title

  • by levelfour
  • 2012/09/30 20:26
遅くなりました。
ご指摘のとおりです。ご迷惑をおかけしてすみません。
すぐに修正します。

ブログ内検索

プロフィール

HN:
levelfour
性別:
男性
自己紹介:
ぼちぼち更新を再開する予定です。

twitter

最新コメント

[09/27 菜々氏]
[06/17 NONAME]
[04/30 mithril]
[04/29 Liva]
[01/30 NONAME]

最新トラックバック

コガネモチ

Copyright ©  -- Cyber Bird --  All Rights Reserved
Design by CriCri / Photo by Geralt / powered by NINJA TOOLS / 忍者ブログ / [PR]