はい、miku_JK_Jbです。
今回は高校生の間に自作OSの開発はどこまで進んだのかについて話していくよ
前回のブログやYouTubeで紹介したように、起動した後にライブラリの改変を一切していないFreeTypeが起動して、多言語で「こんにちは 世界」が描画されるようになっているよ。また、高校生の間にxHCIのUSBドライバを自作した
今の自作OSの処理の流れはこんな感じ
まずはブートローダーの処理の流れから
ブートローダーが起動
↓
Simple File Systemを開いて起動ドライブのルートを取得
↓
起動ドライブの BlockIo を取得
↓
FAT32 を読んで自作OSのRootの位置を特定
↓
起動ボリュームの内容をスナップショット(1GB, 512MB, 386MB, 256MBと段階的にフォールバック)
↓
GOP を取得して、画面情報 FrameBufferConfig を作成
↓
必要なら BltOnly ではない描画可能モードへ切り替え
↓
自作OSのカーネルを読み込む
↓
ELF を解析して、high-half カーネルセグメントを物理メモリ上に展開
↓
カーネルのエントリポイント、配置先物理アドレス、仮想ベースアドレス、サイズを確定
↓
handoff バッファを作成
↓
handoff バッファにUEFIメモリマップ, BootVolume, UefiMemoryMap, BootFileTable
↓
プリロードの設定ファイルを読み込んで、必要な共有ライブラリなどを読み込んで、BootFileTableに登録
↓
新しいページテーブルを作成
↓
物理メモリの identity map と high-half direct map を作る
↓
カーネル本体、フレームバッファ、handoff 領域もそのページテーブルにマップ
↓
カーネル用の一時スタックを確保
↓
ExitBootServices を実行して UEFI のブートサービスを終了
↓
CR3 を新しいページテーブルへ切り替える
↓
handoff の high-half アドレスを引数にして、カーネルエントリへジャンプ
↓
カーネル側が handoff を読んで初期化開始
これがブートローダーの処理の流れだ
次はカーネルの処理の流れを紹介する
ブートローダーから handoff を受け取ってカーネルメインが開始
↓
シリアル初期化
↓
handoff のアドレスを検証
↓
HandoffHeader を読み取り、マジック番号とバージョンを検証
↓
handoff から以下の情報を復元(UEFIメモリマップ, FrameBufferConfig, BootVolume, UefiMemoryMap, BootFileTable)
↓
ブートローダーが作ったページテーブル情報を引き継ぐ
↓
BootVolume.snapshot の領域を identity map + linear map する
↓
IDT を再初期化
↓
FPU / SSE / XCR0 を初期化
↓
システムコールテーブルを初期化
↓
自作の動的リンカーの IRELATIVE 再配置を確定
↓
syscall 機構を初期化
↓
glibc / FreeType 用の TLS 領域を確保して FS ベースを設定
↓
VFS(仮想ファイルシステム) を初期化
↓
PCI を初期化
↓
VFS のディスクルートを自作OSのRootに設定
↓
BootVolume を使ってディスクバックド VFS を接続
↓
フレームバッファを初期化
↓
自作の動的リンカーを初期化
↓
ブートローダーから渡された BootFileTable を自作の動的リンカーに登録
↓
システムライブラリをロード
↓
ユーザー空間や必要な共有ライブラリが使えるか確認
↓
ユーザー空間のグラフィックを初期化
↓
GUI が使える場合はデスクトップ環境を初期化
↓
設定されているデスクトップUIのモードを呼ぶ
↓
デスクトップUIの描画
↓
多言語デモの実行
これがカーネルの処理の流れだ
ブートローダーは高校1~高3まで
ブートローダーはセキュアブートに対応している。
カーネルも高1~高3まで開発してここまで出来た。
とはいってもカーネルの開発は主に高3だったけどね
xHCIのUSBドライバは合間に作ってた感じだね
通信制の高校だったので、かなり時間には余裕があった
特にブートローダーと動的リンカーの作成で気が狂いそうになった。
ブートローダーでは、スナップショットを取得してカーネル側で1次キャッシュ(L1)として使用するのだが、EFIのメモリやスタック不足による start_image() Out of Resourcesに悩まされた。今では1GB, 512MB, 386MB, 256MBに段階的にフォールバックするようにしている。
また、ブートローダーの機能を盛り込み過ぎてもstart_image() Out of Resourcesが出てしまうので、どこを消そうか、どこを残そうかの取捨選択で迷った。
動的リンカーでは、FreeTypeはLinux上で動く前提で作られているので、mallocもerrnoも当然あるものとして呼んでくる。なので自作OSに自前で実装したが、動かせるまでが大変だった。さらにglibcが使っているIFUNCという仕組みがあり、CPUの環境に応じて最適な実装を実行時に切り替える機能があるのだが、これをカーネル環境でそのまま呼ぶとクラッシュするので、安全な実装に差し替える処理を実装したり、FreeTypeだけじゃなく、FreeTypeの依存ライブラリlibz, libpng, brotli, harfbuzzをロード順を間違えただけでもクラッシュする。などといった。Linux互換の壁を非常に感じた。
今後は自作OSに高校の間に作成したxHCIのUSBドライバをぶち込んで、マウスやキーボードに対応したり、Linuxアプリなどを動かせるようにしていきたい。
あとはインターネットに接続できるようにしたりとかね
これが高校生の間に自作OSの開発がどこまで進んだのかについて解説するブログでした
と言うことで以上miku_JK_Jbでした
