はい、miku_JK_Jbです
今回は自作OSが画面描画をできるようにした作業を紹介していくよ。
先に見せておくとこんな感じだよ

図形なども描画できるようにしたよ
画面描画をできるようにする前に前回のブログで発生したカーネルパニックの修正について解説していこう
まずはカーネルパニックとは何なのかについて解説しよう
カーネルパニックとはカーネルが致命的なエラーを起こして、OSが正常に動作することができない状態のことだ
次にカーネルパニックが起こる原因について解説しよう
- メモリ管理のミス
- ハードウェアの故障
- ドライバのバグ
- 回復不可能なエラー
これが主にカーネルパニックを引き起こす原因である
簡単に言えばカーネルが予測していない例外が起こったと考えればいいだろう
それでは順番に解説していこうか
まずはメモリ管理のミスについて解説していこう
これはカーネルが使用できない未マップ領域にアクセスしてしまうと例外が発生してカーネルパニックを引き起こしてしまう。
次にドライバのバグについて解説していく
これは互換性のないドライバを使用したり、するとメモリ管理のミスと同様に未マップの領域にカーネルがアクセスしてしまう。その例外を処理することができないとカーネルパニックを引き起こす。
また、デバイスの初期化や解放処理が行われず、カーネルの状態が崩れてしまい、カーネルパニックを引き起こしてしまうことがある。
次にハードウェアの故障について解説しよう
これはメモリ、CPU、ストレージ、マザーボードや電源の故障などでもカーネルパニックを引き起こす。
そもそもカーネルはハードウェアが正常に動作するのが前提として開発されているので、故障したハードウェアが返す不正な値はカーネルが処理できずにパニックを起こす。
最後に回復不可能なエラーについて解説しよう
これはカーネルがこれは安全に復旧することができないと判断したエラーで、これ以上動作を続けてしまうと、データの破壊などと言った致命的なダメージが起こりうる際にもカーネルパニックが発動する
これがカーネルパニックの原因だな😁
それじゃあどうやってカーネルパニックを修正したかについて解説していこう
私の自作OSのカーネルパニックの原因はこんな感じだった
- bssセクション、dataセクションが正しくマップされていなかった
- ページングの初期化漏れ
- NULLやゴミアドレスに参照していた
それじゃあ順番修正内容を解説していくぜ
まずは未マップ領域のアクセスとページングの修正について解説しよう
これはリンカスクリプトとページングの初期化を修正した。
これにより、未マップ領域にアクセスしたりカーネルが使うメモリの範囲がページングされていないという問題は無くなった。
これがカーネルパニックの修正だ!!
ただ、カーネルパニックは直ったが、カーネルが起動しているかを一目で確認するのは難しいので、カーネルが起動かを確認する処理を追加した
それじゃあ解説していく
これはUEFIブートローダーから受け渡されたFrameBufferを使用して白い画面を映すようにした。これが成功するとカーネルが起動している且つカーネルにFrameBufferが受け渡されているということが分かる。他にも解像度や物理アドレス、ピクセルフォーマットも正常に受け渡されているということが分かる。
てことで見ていこう
結果は

変わらず起動しなかった
えーー( ゚Д゚)
原因を探ると

前回ブートローダーに搭載したMS x64 ABIからSysV ABIに変換する処理がカーネルにもあった
これがあるとカーネルがSysV ABIに変換する処理を行おうとするが、すでに変換されているので、MS x64 ABIが発見できずにパニックになってしまう
全く可愛い子だな🤭
ってことでカーネル側の変換処理を削除
すると

ちゃんとカーネルが起動した!!
これでカーネルパニックの修正は終了!!
次はカーネルのシリアル出力の対応化解説していくぜ
まずはシリアル出力に対応させるために行った作業を紹介しよう
- IOポートにアクセスする処理の実装
- シリアルの初期化処理の実装
- 文字列などの送信処理の実装
それじゃあ順番に解説していこうか
まずはIOポートにアクセス処理の実装について解説する
これはマザボのなどのUSBやらシリアルポートの端子やらにアクセスする処理だ
これを行わないとそもそもカーネルがシリアルにアクセスすることすらできない。
なのでx86_64アーキテクチャのCPUではメモリ空間とは別でIOポートの空間があるので、そこにアクセスを行うように処理を実装したというわけだ
アクセス方法はinとoutでinがデバイスにデータを読み込む命令、outがデバイスにデータを書き込む命令となっている
名前通りだな😁
次にシリアルの初期化の実装について解説しよう
これは通信速度、データビット数、パリティ、ストップビットを設定したり、FIFOバッファや制御信号線を正しく立てて、送受信できる状態にする、UARTを有効化する処理だ
初期化の手順は、最初に割り込みを無効化してボーレート(周波数)を115200bpsに設定し、通信フォーマットの設定を8ビットに設定してFIFOを有効化して受信と送信をクリアにして、モデム制御でDTR RTS OUT2を有効化する
かなり手順が多いがこれらを行うことによってシリアルを初期化できるってわけだ😁
次に文字列などの送信処理の実装について解説する
これはシリアルポートから文字列を送信して、受信側に文字列が映るようにする処理だ
送信処理の手順は、送信レジスタが空いているかをLSRで確認、文字化け防止のためにビットを5に設定して送信バッファを空にするぜ
これで文字が送信されるってわけだな😁
それじゃあシリアル出力がでるかを見ようか
結果は

やったね!!ちゃんと表示された!!
ちなみに環境は自作OSの動作確認用のPCとノートPCを繋いでノートPC側のTeraTermを使っている
これでシリアル出力の対応化は終了!!
最後に図形の描画を行うようにした作業を紹介するぜ
まずは行った作業を紹介する
- 長方形、正方形、三角系、円形、線の描画対応
- 色補正処理の実装
- 描画処理の高速化
これは図形を描画できるようにしたって感じだ
描き方としては、画面を一個一個塗って点を描き、直線を隣り合うマスを順に決めて塗っていき、四角や三角は高さを計算して一個一個塗っていく描き方で、図形を描画させた
まあチマチマと描かせている感じだ😫
それじゃあ図形を描画できるようになったから見ていこう

こんな感じでしっかりと描画ができている!!
次に色補正処理の実装だ
色補正とは人によって色の見え方は違うから、それに合わせてOSの表示する色も変えるといった感じだ。画面一つ一つのピクセルはRGB、赤(R)、緑(G)、青(B)の組み合わせで色を表している。色補正処理ではそれを特別なルールで混ぜ直している。そして画面を混ぜ直した色で描画するといった処理だ
実装のやり方は、さっきも言ったが、画面一つ一つのRGB、赤(R)、緑(G)、青(B)の組み合わせの色を混ぜ直している感じだな。
色補正を行ったので見ていこうか

分かりにくいが、右側のほうが色が暗い!!
しっかりと色補正も効いているな
最後に画面描画の高速化について解説する
これは今まではチマチマと一個一個ピクセルを塗っていったが、高速化するために横一列を筆で一気に描くようにまとめて塗り、図形は横直線の集合として一気に描画するようにして、バックバッファ(画面の裏)で先に描画し、画面の幅や内部幅が一致したなら描画した物を一気にまとめてコピーし、表示するようにした
これによってカーネルの命令量が少なくなり、メモリの効率化ができて結果的に描画が早くなるわけだ
つまり三菱ラリーアートのアートバージョンってとこだな😁(自分でも何言ってんのか分かんなくなってきたわ)
結果はさっき見せた画像と変わらないので省略する。
ただ、これはあくまでもテストだ!!
FrameBufferがカーネルに受け渡されているかのテストだ!!
えーー( ゚Д゚)
実はカーネル側でUIなどを描くとセキュリティや安定性の面で劣るのだ!!
これじゃあ安心と愉しさが無いじゃないか!!ってことで
UIなどはユーザーランド側で描き、カーネル側ではFrameBufferの管理とさっき解説した描画処理の高速化のバックバッファのコピー作業だけを行うということにする。
こうすることで安定性とセキュリティを保てるのだ!!
設計は次回に紹介する
ということで以上miku_JK_Jbでした