C言語でカーネルを書き始める
前回はIPLを書いたので,いよいよカーネルを書き始めることが出来る。
今回からはC言語を使ってOSの開発を行う。
普段私たちは,C言語でアプリケーションプログラムの開発を行うとき,main関数からプログラムを書き始める,これはmain関数からプログラムが実行されるをこと知っているためだ(多くのC言語の教科書でそう説明されているので)。しかし実際には一番初めに実行されるのはコンパイラが暗黙のうちにプログラムの先頭にリンクしたcrt(C RunTime startup)と呼ばれるアセンブリで記述されたプログラムである。crtはCプログラム本体が実行に必要な環境(シェルから渡される引数や環境変数など)を整えた後,main関数をコールする。*1
そのため私たちはcrtを意識することなく,プログラムを書くことが出来た。しかし,OSの開発ではこのcrtを環境に合わせて用意する必要がある。
head.S
main関数へジャンプするだけの簡単なcrtプログラムを用意した:
.text .code32 // 32bit-protectmode .intel_syntax noprefix // I hate AT&T-style .global _start _start: jmp main // jmp kernel main
C言語でディスプレイに文字を表示する
文字を出力するデバイス(ここでは以下ターミナルと呼ぶ)はいくつかの種類があり,私たちが普段使っている,ビデオカードに直接ディスプレイが接続されいるメモリマップ型ターミナル。RS-232インターフェースを用いたターミナル。ネットワークを経由するXターミナルなどがある。*2
今回は,一番馴染み深いメモリマップ型ターミナルの操作について述べる。
メモリマップ型ターミナルにはビデオRAM(VRAM)と呼ばれる特別なメモリ領域があり,これを介しディスプレイの操作を行う。
VRAMはメインメモリと同じアドレス空間の一部であり,メインメモリの操作と同様に操作可能である。(最近のビデオカードには高速化された専用のRAMが搭載されている。)*3
ビデオカードにはビデオコントローラーと呼ばれるチップが搭載されていて,VRAMから必要な情報を取り出しディスプレイへ信号を送り,VRAMの操作をディスプレイに反映させる。ビデオコントローラーはいくつかの表示モードを持っており,大きく分けて,次の二種類がある。
- グラフィック表示用の,メモリとディスプレイのピクセルを対応させるグラフィックモード
- テキスト表示用の,メモリ上のASCIIコードとディスプレイの文字を対応させるテキストモード
今回は簡単に文字を表示可能なテキストモードを使う。
ビデオコントローラーは初期設定でテキストモードになっており,これは80文字x25行の文字を表示可能である。
テキストモードで使われるVRAMはメインメモリの0xB8000にあり,画面上の一文字はメモリ上では二文字分(2バイト)を占めていて,下位バイトはASCIIコードで上位バイトは文字の色を表す値である。つまり,メモリの0xB8000に書き込んだASCIIコードは画面左上の一番目の文字と対応し,0xB8002のASCIIコードは二番目の文字に対応する。
文字の色を指定するカラーコードは次の通りである*4:
Value | Color |
---|---|
0x00 | Black |
0x01 | Blue |
0x02 | Green |
0x03 | Cyan |
0x04 | Red |
0x05 | Magenta |
0x06 | Brown |
0x07 | Gray |
0x08 | Dark gray |
0x09 | Bright blue |
0x0A | Bright green |
0x0B | Bright cyan |
0x0C | Pink |
0x0D | Bright magenta |
0x0E | Yellow |
0x0F | White |
kernel.c
したがって,画面左上から黄色い文字でhello,worldを表示するプログラムは次のようになる:
void main() { unsigned short *video = (unsigned short *)0xb8000; unsigned char *str = "hello,world"; unsigned char c; while(c = *str++) { *video++ = (0x0E << 8) | c; } while(1) ; }
コンパイルとFDイメージの作成
ipl.bin
前回作ったIPL:
gcc -pipe -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o ipl.o ipl.S ld -nostdlib -Ttext=0x7c00 --oformat binary -o ipl.bin ipl.o
kernel.bin
今回作ったhead.Sとkernel.cをリンクしkernel.binを作成する:
gcc -pipe -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -masm=intel -o kernel.o kernel.c gcc -pipe -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o head.o head.S ld -nostdlib -Ttext=0x4000 --oformat binary -o kernel.bin head.o kernel.o
fd.img
イメージファイルの作成。先頭セクタにipl.bin,ルートフォルダにkernel.binを書き込む。
mformat -f 1440 -C -B ipl.bin -i fd.img :: mcopy kernel.bin -i fd.img ::
参考サイト・文献
*1:西田亙 「BIOS版「Hello,World!」プログラムの作成」『インターフェース』2002年7月号 pp.69-70
*2:アンドリュー・S・タネンバウム,アルバート・S・ウッドハル 『オペレーティングシステム 第3版 設計と実装』 吉澤康文,木村信二,永見明久,峯博史訳 p.321-324
*3:VRAM 【Video RAM】 (Video Random Access Memory) | パソコン用語辞典
*4:Nätcasino för kräsna - Konsumentråd om svenska casinon | Passagen