はい、miku_JK_Jbです
今回は自作OSを起動させることができたので、起動させるまでの開発記録を紹介していく
これまた久しぶりのブログ更新だな。自作OSのエラーが多かったり私生活が忙しかったので投稿が遅くなった🥺
自作OSが起動したことが気になると思うので先に起動した画面を見せるとしよう。

これが自作OSが起動した画面だ!!
は??起動しているの??
っと見ている人は思っただろう。
大丈夫だ問題ない。
これが正常だ。
理由はカーネルが起動した後にグラフィックを描画するようにしていないからだ。
じゃあこの - みたいなのは何だって?
これはUEFIブートローダーで設定されたフレームバッファの状態がそのまま表示されているのだ。
カーネルを起動したら画面をクリアするようにしたら消える。
ただ、私はカーネルが起動しているかを確認するために消していない
動画でも自作OSが動いているのを見ることができるよ
https://youtube.com/shorts/PlddQI49z7I
さて、自作OSが起動した画面を見せたのでそろそろ開発記録を紹介していくとするか
まずは1日目
この日は以前ビルドしていたブートローダーとカーネルを実機で起動するかを検証した
↓検証した際の動画
https://youtube.com/shorts/kqJcFWZcu1Y
ちなみになぜ実機で検証しているのかと言うと、QEMUなどの仮想マシンとかを使うよりも開発している雰囲気が出るじゃん?笑
検証結果はPCにそもそも自作OSの存在を認識されなかった🤪
クソが😮💨
ってことでエラーの理由を探っていくとすぐにエラーの原因を発見
あとRootを開く処理を実装していなかった😱
Rootを開く処理とはOSがファイルを操作する下準備といった感じ
処理の流れはYoutubeにて解説しているよ
こんな大事な処理を実装していなかったのは自分でも謎である
そしてRootを開く処理を実装中に気づく
ExitBootServiceの前に最新のメモリマップを取得していない
これの何が問題かというと古いメモリマップを使用してしまうとカーネルが誤ったメモリ領域にアクセスしてしまうのでクラッシュやフリーズが起きてしまう
ってことですぐに修正と再ビルド
これ1日目に行った作業の内容
結構抜けがあった感じだな
2日目
2日目は1日目に修正したブートローダーが動くかをテスト
↓検証した動画
https://youtube.com/shorts/UvWolbnV2oo
ちなみに1日目とは違うPCを使って検証している
理由は1日目の検証で使用したPCは設定が面倒なため
考えられる原因はフレームバッファの描画処理で問題が起こっている?
もしくはカーネルのビルド設定に問題がある?
写真にもデカデカと書かれているがカーネルを静的リンクではなく動的リンクにしていた
はぁ😮💨このお馬鹿さんは一体何をやっているのか😩
ってことでカーネルを静的リンクで再ビルド
全く変わらず黒い画面上部に赤い点線が出る状態に
ってことで別の方法で試すことに
考えられる原因は検証用PCにグラボが刺さっているから、GPUを特定してGOPを取得する幅を広げればいいのではと考えた
GOPを超簡単に説明するとOSがグラフィックを描くようにする奴
処理の流れはこんな感じ
PCIデバイスのスキャン
↓
スキャンで取得したクラスコードを元に手動で検出
↓
GPUを見つけたらBARを読み込みメモリを初期化
流れとしては最初にPCIデバイスのスキャンを行い、取得したクラスコードもとに手動で検出、GPUを見つけたらBARを読み込み、メモリを初期化といった流れ
こうすることで内蔵GPUと外部GPUの両方が存在しても、それぞれを識別して任意に選べて、複数のGPUがぶら下がってても、優先順位を決めて描画デバイスを選べるはず!!
中々実装も大変で1週間以上かかった。PCIのクラスコードの取得やBARを取得の機能自体は元々実装してあったのでそこだけは唯一の救いだった
だが、結果は全く変わらなかった
次にカーネルのようにブートローダーにもビルドミスが無いかをチェックした
ブートローダーがEFI形式ではなく、ELF形式でビルドされていた\(^o^)/
ってことで修正していく
修正した内容は以下の通り
・コンパイラ g++からclang++に変更
・リンカ ldからld.lldに変更
・リンカスクリプトを独自に変更
・ターゲット形式 .EFI固定から elfからEFI形式に変換するように変更
こうすることでしっかりとブートローダーをEFI形式でビルドすることができた

ちなみにコンパイラの変更やリンカの変更を行ったので3週間近く掛かってしまった
だが、それでも変わらなかった。
次に描画設定を詰め込む処理を修正した
詰め込んでいる描画処理の設定はこんな感じ
・ピクセルの書き込み先アドレス
・解像度
・1ラインあたりのピクセル数
・ ピクセルの並び順
ピクセルの書き込み先アドレスや1ラインあたりのピクセル数が分からない人向けに説明すると
ピクセルの書き込み先アドレス = 画面
1ラインあたりのピクセル数 = ピッチ
ピクセルの並び順 = RGBなど
修正した内容は以下の通り
・戻り値をvoid型からEFI_STATUSを返すように修正
・GOP, FBC に対してNULLチェックをするように修正
・汎用ポインタで扱えるように修正
修正内容をざっくりと伝えると
戻り値をVOID型からEFI_STATUSを返すように修正して関数の呼び出し元が、
「何が悪かったか」を明確に検出できるようになった
GOP, FBCにたいしてNULLチェックを行うことでクラッシュした時の耐性を向上させた
汎用ポインタで扱えるようにして、読み書き型依存性をなくすようにした
尚、結果は変わらない模様
では、なぜフルスクリーンロゴを有効にしたら起動したのだろうか?
原因は主に2つ
・GOPが初期化されていない
・コンソールモードの初期状態が異なる
GOPが初期化されていない点について解説していくと
フルスクリーンロゴが有効な場合だと、UEFIが自動的にGOPを初期化してくれ、画面を表示する準備をしてくれるので、先にGOPの初期化が済んでいる状態になる
ちなみにフルスクリーンロゴが無効な場合だと、UEFIがGOPの初期化をしないことがあるので、ブートローダーでもGOPの取得に失敗することがある
コンソールモードの初期状態が異なる点ついて解説していくと
フルスクリーンロゴを有効にすると、UEFIが最初にコンソール出力を非表示にして、ロゴを表示させるので、
文字出力やフォントの扱いに独特な状態遷移が起こる
ちなみにフルスクリーンロゴを無効にすると、設定が異なるので、コンソールの出力ポインタであるConOutと、コンソールの出力モードのSetModeの呼び出しが崩れてしまう
そう考えると意外とフルスクリーンロゴを有効にすることって大事なんだな
尚、EFI形式でビルドした後のソースコードを修正を行わずに、フルスクリーンロゴの設定を有効にした状態で、起動するか検証したが、起動することはなかった。
これが自作OSのカーネルを起動するまでの作業内容だったよ
これでようやくスタートラインに立った
次回はブートローダーの開発で大変だったことを上げていくよ
ということで以上miku_JK_Jbでした







