はい、miku_JK_Jbです
今回は自作OSを色々なPCに対応させるために行った作業を紹介していくよ

 

これまた久しぶりのブログ更新だな。いつも通り自作OSのエラーが多かったり私生活が忙しかったので投稿が遅くなった🥺

 

自作OSが起動したことが気になると思うので先に起動した画面を見せるとしよう

 

これが自作OSが起動した画面だ!!


まずは検証用のPC

 

前使っていたサブ機


CHUWIのミニPC

 

 

 

 

は??起動しているの??

 

っと見ている人は思っただろう。

 

 

大丈夫だ問題ない

 

これが正常だ。

 

理由はカーネルが起動した後にグラフィックを描画するようにしていないからだ。


じゃあこの - みたいなのは何だって?

これはUEFIブートローダーで設定されたフレームバッファの状態がそのまま表示されているのだ。

 

カーネルを起動したら画面をクリアするようにしたら消える。

 

ただ、私はカーネルが起動しているかを確認するために消していない

じゃあこの - みたいなのが無いのもあるって?


これはUEFIの仕様によって出るPCと出ないPCがある
ASRock
P67固有のUEFI仕様・制限・初期化順序がログ出力や描画を妨げている状態
 

さて、自作OSが起動した画面を見せたのでそろそろ開発記録を紹介していくとするか

 

まずは1日目

 

この日は前使っていたサブ機で自作OSが起動するかを試した

 

 

結果は

PCに自作OSの存在すら認識されなかった😭

原因はマザボのメーカーが違うので上手くELFを読めてない?

ちなみに前回自作OSが起動したときに使ったメーカーはASRock P67Pro3で
今回検証したPCのマザボのメーカーがASUS P8Z77-V

ELFを上手く読ませるためにUEFIアプリケーションで使用されるファイルを読み込んでメモリ上に展開する処理を追加し、カーネルに読み込む処理に統合した

 

これによりブートローダーがカーネルのバイナリを取得でき、
二日目に実装するELFヘッダを解析し、
セグメントをメモリに展開する処理の前提となる


処理の中身はこんな感じ
・ファイルサイズを取得する
・ファイルサイズ分のメモリを確保
・ファイル内容をメモリに読み込む
・読み込んだバッファとサイズを呼び出し元に返す

この処理をカーネルを読み込む処理と統合したことで、
カーネルの読み込み処理が、よりスムーズに行えるようになった

この日は二日目に実装するELFの解析まで実装したかったけど
風邪をひいて熱が出ていたので作業を中断した

 

 

 

 

 

 

 

2日目
 

この日はELFを解析する処理を追加し、BootServiceから抜ける処理と統合した


処理の流れはこんな感じ

 

・ELF形式のカーネルを読み込む
・プログラムヘッダーに従って必要なセグメントをメモリに配置
・BootServicesから抜ける処理を呼び出してUEFIの制御を終了


この処理を追加することで、ELF形式のバイナリを
実行可能なメモリレイアウトに変換しカーネルが実行可能な状態になる


これが2日目に行った作業だ

 

 

 

 

 

3日目


この日は自作OSが起動するかをリベンジした

結果は


BIOSに戻された😭😭
 

ちなみにBIOSから抜けると一瞬だけ画面が表示されて
またすぐにBIOSに戻される

 

原因を探っていくと以下のものが判明した
・ブートローダーに.relocセクションが無い
・ELFを解析する処理でPIEに対応していない


ブートローダーに.relocセクションが無いと、ブートローダーがPIE形式のカーネルが正しくリロケーションされず、ブートローダーがクラッシュする可能性がある

また、ELFを解析する処理でPIEに対応していないとそもそも、リロケーションの処理すらできない

PIEとは位置独立実行形式と言って、任意のメモリアドレスにロードされても正しく動作するバイナリ形式だ

ブートローダーに.relocセクションを追加するために行った作業はこんな感じ
・ブートローダーに.relocセクションを追加した

relocセクションを追加した理由は、カーネルをどこにロードされても動くようになるから
 

relocセクションを追加した作業は、使用するリンカを変更しリンカオプションの調整を行って追加した

ちなみに本来は.relocセクションを避けるのが一般的だが、.reloc特有のアドレスを補正を活用して、異なるUEFIでもブートローダーの挙動が安定するようにした
relocセクションが避けられる理由は、
本来のUEFIブートローダーは固定アドレスでロードされる設計なので
そもそもアドレスの補正が不要且つ、挙動が不安定になる場合があるからだ。

では何故避けられる.relocセクションを追加したのか?
UEFIの挙動はマザボやFWによって異なるので、万が一カーネルをロードするアドレスがずれた場合に.reloc特有のアドレス補正を使って、正しい場所にロードできるようにしたからだ
 

これは完全に.relocセクションの弱点を逆手にとって、 ブートローダーの安定性と柔軟性を高めた
 

次にELFを解析する処理でPIEに対応させた作業について
行った作業はこんな感じ
・カーネルをPIE形式でビルドされるように変更
・ELFファイル内に.relaセクションの追加
・ブートローダーに.relaをパースして再配置処理を追加
・仮想アドレスから実アドレスに補正させる処理を追加


この処理を追加することで万が一カーネルが違う場所にロードされても、正しいアドレスに補正してくれてるようになった
これが3日目に行った作業だ

 


4日目


この日は3日目に追加した処理がちゃんと動いて自作OSが起動するかを試した

結果は

ちゃんと起動した
画面が黒いのは序盤で説明したから説明は不要だよね

次にミニPCでも起動するかを試した


結果は

エラーが出て起動しなかった😭

原因はPCIを使用したGPUの特定とELFの解析でエラーが出ている


まずはPCIを使用したGPUの特定のエラーを修正していくぞ
エラーの原因はこんな感じ

・PCI上にGPUが無い場合は処理を中断していた


このせいでPCI上にGPUが無いPCでは内臓GPUを使うことができずに
ブートローダーがクラッシュしてしまう状態になっていた

エラーを修正するために行った作業はこんな感じ
・GPUが見つからなくても処理を中断しない
・見つからない場合はGOPを使用して描画

 

こうすることでPCI上にGPUが無くても、

内臓GPUを利用して画面を描画することができるようになり、グラボが無いPCにも対応させた
 

PCIを使用したGPUの特定のエラーを解決したので
起動するかを試した


結果はGPUの特定エラーが直り、ELFの解析のエラーだけ残った状態になった

それじゃあELFの解析のエラーを修正していくぞ
・.relaセクションの補足で0x25になっていたので正しい0x08に変更 
・セグメントマッピングの追加
・未確保領域への書き込みを防止追加
・セグメントごとの実アドレスを正確に算出するように変更


こうすることで未確保領域への書き込みを防止し、
どんなメモリ配置でも起動可能になり、再配置処理が設計に統合され実機に対する対応力が上がった

 

ELFの解析のエラーを修正したので起動するかを試した

結果は


ちゃんと起動した😉
画面が黒いのはさっきと同じ

 

これが自作OSを色々なPCで、起動するようにした作業だよ

次回はセキュアブートに対応させたいな

ということで以上miku_JK_Jbでした