プログラミング関連での備忘録なんかを載せています。
カレンダー
10 | 2024/11 | 12 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
プロフィール
HN:
たっく
年齢:
42
性別:
男性
誕生日:
1982/03/11
職業:
システムエンジニアなの?
おすすめ
最新コメント
最新記事
(11/15)
(11/15)
(11/15)
(11/08)
(11/07)
最新トラックバック
ブログ内検索
最古記事
(11/06)
(11/07)
(11/07)
(11/07)
(11/07)
アクセス解析
4日目 その2を始めます。
今回は、今までやってきたことの集大成とでも言うべき事をやります。
何をやるかというと、ついに、デスクトップ(っぽいもの)を描画します。
まずは、実行画面を。
いよいよ来ましたね!デスクトップですよ!
どう見てもデスクトップです。
まぁ、絵に描いた餅ですが・・・・・・
やっていることは単純で、4角形を書く関数で、14個の色違いの四角を描いているだけです。
でも、これから処理を書き込んでいけば、本物のOSになって行くはずです。
楽しみです。
次回は、5日目「構造体と文字表示とGTD/IDT初期化」です。
構造体は分かりますが、文字表示とGDT/IDT初期化の部分はなかなかにボリュームがありそうです。
気合を入れて頑張ります。
PR
4日目です。
内容は、「C言語と画面表示の練習」です。
3日目はかなり苦労しましたが、4日目は3日目を下地にしてC言語とアセンブラでサクサクと作っていくと言う内容なので、特に苦労する部分はありません。
今回は画面に色を塗ってみましょうと言う趣旨です。
やることもそんなに難しくなく、ビデオアクセス用アドレス空間に対し、色に対応する値を入れていくというものです。
C言語で直接ビデオアクセス様アドレス空間に値をセットすることは出来ないので、値をセットするところをアセンブラで作ります。
ソースは結構長いので割愛しますが、この章では「ポインタ」が出てきます。
書店でよく見かけるC言語の本よりも、アセンブラを下地にして説明している為、とてもわかりやすいと思います。
ちなみに、4日目 その1が終わったところで、画面はこんな感じになっています。
目がチカチカしますね。
次回は「4日目-その2」です。
いよいよ、OSっぽい画面が表示されます。
3日目 その2です。
更新が1週間空きましたが、別にサボっていたわけではありません。
著者製ツールを極力使わないという自分ルールに縛られていました。
具体的にいうと、ld等のリンカに当たる、obj2bim と bim2hrbというツールです。
このツールを使用せずに、アセンブラで作成したオブジェクトファイルと、
C言語で作成したオブジェクトファイルをリンクしようとしていました。
とりあえず、順番にいきます。
今までアセンブラのみでしたが、今回からC言語が加わっています。
それに伴って、OSの本体であるoslite.sysの作り方が大きく変わっています。
流れを書くと、
- アセンブラでOSのヘッダー部分を記述(asmhead.asm)
- C言語でOSの処理部分を記述(bootpack.c)
- アセンブラでC言語だけでは手に負えない部分を記述(nasmfanc.asm)
- 2と3ののファイルをリンカで結合してoslite.sysを作成
- 1のファイルと4で出来たファイルをcatコマンドで結合
- それを、フロッピーのイメージの中にファイルとして保存する
流れだけ書くとそんなに難しくない様に感じます・・・・・・が、
実際にやってみると、こんなに難しい物なのか!っていうのが分かりました。
※「30日でできる!OS自作入門」が難しいわけではありません。
私が変な部分にこだわっている事で難しくしてしまっただけの話です。
「30日でできる!OS自作入門」ではHRBという形式の、
独自の実行ファイル形式を作成していますが、
私はLinuxで使用されているELFという形式の実行ファイルを作りたくて、
調べたり、色々試してみたりしていたら、1週間たってしまいました。
結果としては、今の私では、手に負えませんでした。
HRB形式とELF形式の実行ファイルのヘッダ部分の取扱いの違いが
どうしても今の私には分かりませんでした。
と言うことで、落としどころとしてHRB形式の実行ファイルを使用するが、
著者製のツールは使用せず、ldにて出力する事にしました。
やり方は、すでに調べてくれている人がいた為、以下の方法で出力します。
まず初めに、startup.oというファイルを作成します。
これは、下にでてくるoslite.ldsに読み込まれせるもので、
どの関数が、最初に実行されるかを記述した物です。
(スタートアップルーチンって言う奴です。普段ならmainって書く関数です)
src/startup.cとして作成しました。
void LiteMain(void); void LiteStartup(void) { /* 将来LiteMainの実行に先立って何かしたくなったらここに書き足す*/ LiteMain(); /* 将来、LiteMainの終了後に何か処理をさせたくなったら、ここに書き足す*/ return; }
次に、ldsというディレクトリを作成し、
その中にoslite.ldsというファイルを作成する。
このファイルの中に「LONG(LiteStartup - 0x20)」と言う部分があり、上の「startup.c」とつながります。
oslite.ldsを開いて、以下のとおり記述します。
OUTPUT_FORMAT(binary) OUTPUT_ARCH(i386) INPUT(./bin/startup.o) SECTIONS { .head 0x0 : { LONG((ADDR(.bss) + SIZEOF(.bss) + 0xfff) & ~ 0xfff) BYTE(0x4f) BYTE(0x53) BYTE(0x4c) BYTE(0x69) LONG(0x0) LONG(ADDR(.data)) LONG(SIZEOF(.data)) LONG(LOADADDR(.data)) LONG(0xe9000000) LONG(LiteStartup - 0x20) LONG((ADDR(.bss) + SIZEOF(.bss) + 0xf) & ~ 0xf) } .text ADDR(.head) + SIZEOF(.head) : SUBALIGN (1) { *(.text) } .data 0x00000400 : AT ( LOADADDR(.text) + SIZEOF(.text) ) SUBALIGN (4) { *(.data) *(.rodata*) } .bss : AT ( LOADADDR(.data) + SIZEOF(.data) ) SUBALIGN (4) { *(.bss) } /DISCARD/ : { *(*) } }
で、保存をしたら、Makefileを以下の様に書き換えます。
Makefileは、「3日目 その1」からずいぶん色々な物が増えています
それと、フロッピーのイメージは「mformat」と「 mcopy」という
素敵なコマンドが見つかった為、そちらで作成することにしました。
(mformatがフロッピーのイメージを作成するコマンドで、
mcopyがフロッピーの中にファイルを入れるコマンドです)
NASM = nasm CC = gcc CFLAGS = -fno-builtin -fno-common -Os -Wall -nostdinc -I. -c SRC = ./src oslite.img : ./bin/ipl.bin ./bin/oslite.sys Makefile # フロッピーディスクのイメージを作成して、IPL部分を書き込む mformat -f 1440 -C -B ./bin/ipl.bin -i ./bin/fdimage/oslite.img :: # イメージファイルにoslite.sysを書き込み mcopy -i ./bin/fdimage/oslite.img ./bin/oslite.sys :: ./bin/ipl.bin : $(SRC)/ipl.asm Makefile $(NASM) -f bin -o ./bin/ipl.bin $(SRC)/ipl.asm -l ./lst/ipl.lst ./bin/oslite.sys : ./bin/asmhead.bin ./bin/oslite.bin Makefile cat ./bin/asmhead.bin ./bin/oslite.bin > ./bin/oslite.sys ./bin/oslite.bin : ./bin/bootpack.bin ./bin/nasmfunc.obj ./bin/startup.o Makefile ld -e LiteMain --Map ./map/oslite.map -n -Ttext 0xc200 -T ./lds/oslite.lds \ -static -o ./bin/oslite.bin ./bin/bootpack.bin ./bin/nasmfunc.obj ./bin/asmhead.bin : $(SRC)/asmhead.asm Makefile $(NASM) -f bin -o ./bin/asmhead.bin $(SRC)/asmhead.asm -l ./lst/asmhead.lst ./bin/bootpack.bin : $(SRC)/bootpack.c Makefile $(CC) $(CFLAGS) $(SRC)/bootpack.c -o ./bin/bootpack.bin ./bin/nasmfunc.obj : $(SRC)/nasmfunc.asm Makefile $(NASM) -f elf $(SRC)/nasmfunc.asm -o ./bin/nasmfunc.obj -l ./lst/nasmfunc.lst ./bin/startup.o : $(SRC)/startup.c Makefile $(CC) $(CFLAGS) $(SRC)/startup.c -o ./bin/startup.o clean : rm -f ./lst/*.lst rm -f ./bin/*.bin rm -f ./bin/*.o rm -f ./bin/*.obj rm -f ./bin/*.sys rm -f ./map/*.map rm -f ./bin/fdimage/*.img
これでmakeを実行してどうなるかを試します。
ちなみに、今までVMWareを使用していましたが、
今回からはqemuを使用します。
理由は、デバッグ出来るからです。
といっても、ソースレベルのデバッグではなく、
機械語(アセンブラ)レベルのデバッグです。
でも、これがあるのと無いのでは、大きく違います。
デバッグのやり方は、
$ qemu -s -S -fda ./bin/fdimage/oslite.img -redir tcp:5555:127.0.0.1:1234 &
でqemuを実行して、別のコンソールで
$ gdb
(gdb) target remote 127.0.0.1:1234
↑qemuに接続
(gdb) display/i $pc
↑アセンブリ言語に変換して表示
(gdb) break *0x00XXXXXX
↑メモリにブレークポイントをつける(XXXXの部分がアドレスになります)
(gdb) c
↑実行
(gdb) nexti
↑次のアドレスに移動
と言う感じです。
この方法が分かってから、一気にやりやすくなりました。
(同時に、ELF形式を使うのを諦められました)
ちなみに、実行している画面はというと・・・
まだ真っ黒なんです。これが。
と言う事で、3日目 その2は以上です。
ひじょ〜に難産でした。
次回は、4日目「C言語と画面表示の練習」です。
次は少し画面に色がつく予定です。
これから少しずつOSらしくなって行く様なので楽しみです。
3日目を始めます。
まずは2日目のおさらいですが、2日目はプログラム本体の部分をアセンブリ言語で記述したのと、ブートセクタのみをアセンブルするようにしました。
また、Makefileを作ってアセンブルからフロッピーディスクイメージ作成までをコマンド一発で行えるようにしました。
3日目の内容は、「32ビットモード突入とC言語導入」です。
まず、今まで作ったものは画面に文字を表示するだけで、他には何もしません。でも、本来はここからOSを読み出さなければいけないので、ブートセクタ以降のセクタを読み込んでいきます。
今回大きく変わったのは、以下の部分です。
; プログラム本体 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すすめる ADD AX, 0x0020 ; | MOV ES, AX ; | ADD ES, 0x020ができないからこうしている ADD 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へ飛ぶ ; ここまででフロッピーディスクの先頭から180KByteまでを読み込んだので、 ; 次はOS部分を実行させる MOV [0x0ff0], CH ; IPLがどこまで読んだのかをメモ JMP 0xc200
何をしているかというと、
- ブートセクタの部分(フロッピーの最初の512byte)は起動時にメモリに読み込まれているので、その次のセクタから、10シリンダ分(180kbyte)までをメモリに読み込む。
- 読み込んだ結果、メモリの0xc200にOS部分の先頭があるはずなので、そこにJMP命令で飛んでいよいよOS部分の処理を走らせる(ブートセクタ卒業)
これで、ブートセクタ部分の開発はひとまず終了の様です。
それと今回は、OSの本体部分の着手もしました。
以下がOS本体部分のソースです。
ファイル名は、「oslite.asm」です。
※「30日でできる!OS自作入門」ではhariboteOSという名前で開発を行っていますが、それじゃつまらないので、私はosliteと言う名前にしています。
; oslite-os ; TAB=8 ORG 0xc200 MOV AL, 0x13 ; VGAグラフィックス, 320x320x8bitカラー MOV AH, 0x00 INT 0x10 fin: HLT JMP fin
で、このOS部分をフロッピーにファイルとして保存するのですが、ここでまた著者製のedimg.exeでフロッピーに書き込むと言うことを行っています。
2日目では、catコマンドを使用してブートセクタとそれ以降のデータをくっつけてイメージファイルを作りましたが、今回は単純にくっつけるだけではなく、その中にOS部分を書き込まなければいけなくなりました。
色々と調べていたら、ddコマンドで既存のファイルの特定の場所を上書き出来るという事が分かった為、Makefileを以下の様に変更しました。
# フロッピーディスク作成 helloos.img : ./bin/ipl.bin ./bin/oslite.sys ./bin/initflpimg.bin Makefile # フロッピーディスクのイメージの元となるファイルをコピー cp ./bin/initflpimg.bin ./bin/fdimage/oslite.img # iplを書き込み dd if=./bin/ipl.bin of=./bin/fdimage/oslite.img count=1 bs=512 conv=notrunc # イメージファイルの0x002600以降にoslite.sysというファイル名を書き込み dd if=./bin/osname.bin of=./bin/fdimage/oslite.img count=1 bs=512 seek=19 conv=notrunc # イメージファイルの0x004200以降にOS部分を書き込み dd if=./bin/oslite.sys of=./bin/fdimage/oslite.img count=1 bs=512 seek=33 conv=notrunc ./bin/ipl.bin : ./src/ipl.asm Makefile nasm ./src/ipl.asm -o ./bin/ipl.bin -l ipl.lst ./bin/oslite.sys : ./src/oslite.asm Makefile nasm ./src/oslite.asm -o ./bin/oslite.sys -l oslite.lst clean : rm -f ipl.lst rm -f ./bin/ipl.bin rm -f ./bin/fdimage/*.img
なんか、FAT12のファイルフォーマットを結構無視している気がしてきましたが、困ってしまうまではこの方法で行きます。
※付属CDの中をよくみたら、edimg.exeのC言語のソースファイルがありました。本格的に困ったら、コンパイルして使わせてもらおうと思います。著者様、ありがとうございます。
ここまで出来たので、makeを実行しイメージファイルを作成しました。
で、出来たイメージファイルを早速VMWareに読み込ませて起動してみると・・・・
できました〜。
え?黒いのは正しいですよ。
OS部分でグラフィックモードと言う物に変更しているので、今まであったカーソルすら消えています。
さて、今回学んだことをまとめると、
ブートセクタ部分は結局512Byte分しかないので、複雑な事をやるのなら他のセクタも読み込まなければいけない。
その為、ブートセクタでは他のセクタを読み込んで、次のプログラムがある場所へ処理を移すと言うことをやる。
と言うことになりますね。
漠然としか分かっていなかったブートの仕組みが、実際作ってみて理解出来ました。
次回は、3日目 その2として、32bitモードへの移行と、C言語での開発を行います。
いよいよC言語がでてきます。
2日目 その2です。
2日目 その1までで、大分プログラムらしくなりましたが、
未だにブートセクタ以外の場所が残っています。
これは、調べてみるとどうやらFAT12フォーマットの仕様の部分を、アセンブラで直接書き込んでいるのが原因の様です。
1日目のソースの、
; 以下はブートセクタ以外の部分の記述 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 TIMES 4600 DB 0 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 TIMES 1469432 DB 0
の部分ですね。
これは何を意味しているのか分かりませんが、うちのPCのVMWareに入っているWIndows 7 RC版でフロッピーディスクのイメージをフォーマットして、バイナリエディタでそのイメージを開いて見たところ、512Byte目から「F0 FF FF 00」、5120Byte目から「F0 FF FF 00」がありました。
よくわからないけど、FAT12の仕様だと言うことで今のところは納得しようと思います。
で、この部分をわざわざアセンブラで記述しているのが無駄だと言うことで、今回はブートセクタ部分の最初の512Byteだけをアセンブラで作るように変更します。
ここでですが、私の環境は以前にも言いましたがUbuntuです。
「30日でできる!OS自作入門」はWindowsを想定して書かれていて、ちょくちょく作者が作ったWindowsのツールが出てきます。
今回も、読み進めて行ったところedimg.exeという作者が作ったツールを使っています。
ですが、私は使いたくありません。
一応、やっている事はブランクディスクのイメージを読み込んで、先頭の512byteの部分にアセンブラで作ったブートセクタを書き込むと言う説明が書いていましたが、その読み込み元のブランクディスクイメージが、59byteしかなく、中身をみてもFAT12フォーマットと言うわけでもなく、よく分かりませんでした。
と言うことで、以下の方法をとろうと思います。
- 2日目まででできているフロッピーイメージの512Byte未満の部分を削除して、このバイナリファイルをsrc.binとして保存します。(このファイルは今後も使うかもしれないのでとっておきます。)
- アセンブラでブートセクタをアセンブルします。(ipl.binという名前にします)
- catコマンドを使用して、アセンブル結果とsrc.binを結合します。(cat ipl.bin src.bin > helloos4.imgという感じです)
早速ソースの修正をします。
まぁ、やることはを上で書いたソース部分を削除するだけなんですが・・・・・
賛否両論あると思いますが、私の場合は、書いたソースをなかなか消す事ができません。
なので、今回はソースを消すのではなく、コメントアウトします。
※IBMの人とコードレビューをしたことがあるのですが、その人はいらない部分は削除するべきって言っていました。まぁ、反対はしません。ここでは、本当にいらなくなれば自然ときえるでしょ〜っていうスタンスで行きます。
これでアセンブルします。
そして、今回からのコマンド、
cat ipl.bin src.bin > helloos4.img
を実行します。
これで、 helloos4.imgが作成されたので、VMWareで実行してみます。
まぁ、大したことしていないので普通に実行できました。
とりあえずこれで、アセンブルするのはブートセクタの512Byteだけになったので、解析しやすいようにリストファイルと言うものを出します。
nasmに一つオプションをつけます。
$ nasm helloos3.asm -o ipl.bin -l ipl.lst
これを実行すると、ipl.lstと言うファイルが出来上がりました。
中身を覗いてみると・・・あれまー、超便利。
こ〜んな感じでどんな機械語に変換されたかが一目瞭然です。
最後にMakefileを作ります。
私の環境にはすでにmakeコマンドが入っているので、Makefileを作るだけでした。
どうせならディレクトリも分けておこうと思い、srcとかbinとかのディレクトリを作成し、Makefileを以下の様に作りました。
# フロッピーディスク作成 helloos.img : ./bin/ipl.bin Makefile cat ./bin/ipl.bin ./bin/src.bin >./bin/fdimage/helloos.img ./bin/ipl.bin : ./src/ipl.asm Makefile nasm ./src/ipl.asm -o ./bin/ipl.bin -l ipl.lst clean : rm -f ipl.lst rm -f ./bin/ipl.bin rm -f ./bin/fdimage/*.img
これで、makeを実行すればフロッピーディスクのイメージファイルが自動的にできます。
2日目の内容は以上です。
今回の内容としては難しいところはあまりありませんでした。
次回は、「32ビットモード突入とC言語導入」です。
いよいよC言語がでてきます。