前置き
本記事は「ゼロからのOS自作入門」のメモになります。
仕事上OSの知識があってもいいなと思って、取り組むことにしました。
各章に対し、1記事をOutputする予定です。
前記事:https://qiita.com/fuji3195/items/516c3f07bb3f08faba0e
参考として,以下のように章を学んでいます.
2~3周くらいは読まないと,中身の理解はできないです.
- まず章を全部読む
- 読み返しつつ手を動かす
- 書籍に載っている部分はプログラムをコメントアウトして書籍のコードを写経する
学ぶこと
- 文字の表示
- 分割コンパイル
- コンソールでの文字の処理
-
sprintf()
,printk()
の実装
分割コンパイル
main.cpp
だけだと長くなってきたから,機能ごとにファイル分けようね,というお話.
C/C++で開発した経験があるなら大体知っていると思う.
文字の表示
文字を表示する.
8x16 pixelを,バイナリで記述する.
最初はA
の文字を以下のようにしてあらわしている.
const uint8_t kFontA[16] = {
0b00000000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00100100,
0b00100100,
0b00100100,
0b00100100,
0b01111110,
0b01000010,
0b01000010,
0b01000010,
0b11100111,
0b00000000,
0b00000000,
};
1が文字の線の部分で0が何も表示しない部分になっている.
これを前章でやった1pixelごとの表示を応用して,適当な場所に文字を表示させることができる.
以下は実際に動かしてみた結果になる.
ここまでが,文字の表示方法のお話.
これを何個も作るのは非常に手間がかかるので,オープンソースの「東雲フォント」を使うようにする.
東雲フォントのバイナリの生成は著者がpythonスクリプトを用意してくれているので,そこからバイナリを作成する.
binaryは16byte x 256 (0x00~0xFFまで) = 4096 byte用意する必要がある.
さらに,リンクに必要な情報を付け加える必要があり,objcopy
というコマンドを使う.
これにより,binaryはリンクに必要な情報を持つobjectファイルに変更することができる.
なお,各オプションの意味は以下の通り.
option | 意味 |
---|---|
-I | 入力ファイルのフォーマット.今回はバイナリ |
-O | 出力ファイルのフォーマット.今回はelfファイルなのでelf64-x86-64
|
-B | 出力ファイルのターゲットアーキテクチャ.入力ファイルがバイナリの場合もとのアーキテクチャがないため,このオプションで明示的に設定する. |
sprintfとprintkの実装
sprintf実装
書式なしバージョン
非常に簡単.
今回はWriteString()
関数を実装して使ってみる.
書式ありバージョン
Newlib
という標準Cライブラリを使う.
Newlib
の特徴は以下の通り
- OSが入っていない組み込み機器などでも簡単に使えるようになっている
- printfやmallocなどのOSが必須な機能は自分で実装するように空の実装になっている
makeの際にCPPFLAGSとLDFLAGSを書き換える.これはosbook/devenv下にあるbuildenv.shで変更できる.
そのあとにmakeしたら以下のように正しく起動した.
コンソール実装
コンソールの仕様は以下のようなイメージ
- 改行文字で改行するだけの機能
- 文字列を先頭から見ていって,改行文字に出会ったらX座標を0に戻し,Y座標を+16する
- スクロール機能
- 画面を一度塗りつぶしてメッセージを消す
- 改めて一行ずらして今までのメッセージを表示する
- 今までのメッセージ(最低でも1画面分)は記憶しておく必要がある
これをC++のクラスを用いてコンソールクラスとして実装する.
コンソールクラスでは画面サイズは25*80固定.qemuで出力されるWindowはそれ以上の領域を有しているが,25行以上表示すると改行される.
また,普段使っているイメージのものとは異なり,80文字を超えたら表示されないようになっている.
コンソールに普段イメージしているような以下の機能を付け加えるのはまだしばらくなさそうに見える.
改行文字は別で実装している.Newline()
で実装されている.
Newline()
の中で,上記の2パターンそれぞれ実装している.
実際に実装して,27行表示した結果が以下.実際に,25行しか表示されておらず,最初の3行(0~2 line)は消えてしまっている.
printkの実装
printk()
はカーネルからメッセージを出すためのprint文.printfと同じ書式を持つ.
通常のOSには実装されているため,デバッグ用にここで実装する.
printk()の実装により,先ほど出力した「line xx」はすべてprintkで出力が可能になる.
ポイントはC言語の可変長引数のva_list
型.
vsprintf()
を使うときに必須になり,可変長の引数...
を受け取り,そのままvsprintfに渡す.
va_start
とva_end
で挟むことで使える.
出力は上の画像とだいたい同じなので省略.
まとめ
Consoleの作成及び,文字の出力について学んだ.
Console自体はほんとに基本的な機能しかないが,printできればOK,みたいな感じ.
次はマウス入力とPCIについて学ぶ.