借り初めのひみつきち

仮ブログです。移転先募集中

Rust 自作 OS 日記/Part 9 my new os...

2020 年を振り返ってみると、色々と検討した結果もう Rust を勉強するしかないなー ということになって春ごろから Rust の勉強を開始、そして myos の開発が始まりました。

さて、およそ半年開発を続けてきた「myos」ですが、

「私の OS」ってなんやねーん

という指摘があちこちから飛んでくるかと思ってましたが、そんなことはありませんでした( ˘ω˘ )

第一部、完。

すでに何度か触れているのでお気づきの方もいらっしゃるかと思いますが myos は moe の後継で、 最初のマイルストーンは C で記述された moe の機能を Rust で書き直すことでした。

まだ moe で実現されていた全ての機能を完全に置き換えることはできていませんが、当初のマイルストーンに到達し、 現在はアプリケーションの動作環境を整える段階になったと考えています。

UEFI / ACPI

UEFI は 2010 年代から使われ始めたファームウェア規格で、 ACPI はハードウェアの構成情報や電力制御に関するインターフェース規格です。 どちらも近年の PC では標準的に使われている規格です。 PC 以外の世界ではほとんど使われてませんが。

Rust で UEFI に対応するためには uefi-rs というライブラリを使うのが簡単です。

github.com

本来 UEFI で提供されている機能の一部がうまく扱えなかったりするのですが、今のところ myos の起動に支障はとくにないのでそのまま使っています。

また、同じところが提供している ACPI ライブラリも組み込んで使っていますが、こちらは不足している機能が多く moe の時に対応できていた機能の一部がまだ対応できていないので置き換えを検討しています。

マルチタスキング

myos では、タイマー割り込みによるオーソドックスなプリエンプティブマルチタスキング、 SMP や SMT によるハードウェアマルチスレッディング、 async + await による協調型マルチタスキングなど複数のマルチタスキングをサポートしています。

moe の SMP 対応は後から追加されたので実はオプションでした。 また、はじめて SMP 対応のコードを書いてみたので、コアごとに分離するべき情報がまとまってなかったり、色々中途半端なところがありました。

myos では最初から SMP 対応前提でスケジューラーなどが設計されました。 SMT (HTT) の割り当てはシステムの負荷が一定以上になるまでスケジューリングしないようになっています。 なお、 SMP 起動部分は古き良きリアルモードで起動する moe 時代のコードをほぼ踏襲することになりました。

ウィンドウシステム

moe では一時期ウィンドウシステムを実装していたものの GUI は不確定要素が大きくなるため、一時期悩んでいた不安定要素の原因になっているのではないかということで一旦削除されました。結果として犯人は別のところにいたことがわかりましたが、今更復活するのもめんどくさいのでなかったことにされてしまいました。

myos のウィンドウシステムは moe のコードを参考に開発されたのでアルファブレンドに対応しています。 moe の時代にあったカラーキーモードは myos ではアルファブレンド前提で完全に削除されました。 また、 moe の時代に実現予定だった機能としてウィンドウに影をつけることができるようになりました。

影をつけた代償として全てのウィンドウが半透過扱いになり、現状 SSE に対応していない事もあって描画は遅くなってしまった気がします。

メモリ管理

現状の myos はカーネルの配置以外にページングを使っていません。 厳密にはロングモードではページングを無効化できないので、物理アドレスと仮想アドレスが一致する Identity mapped という状態でページングを利用しています。

メモリ保護の観点では、開発言語として Rust を採用していること、アプリケーションの実行環境として Sandbox を想定していることなどから、ページングで保護する必要性があまりないのが現状です。

ページングの他の使い道としては、メモリ空間をアプリごとに分離して断片化に強くなるメリットがあります。 こちらはいずれ必要になってくるかもしれません。

なお、現状 4GB 以上の物理メモリが存在しても割り当てません。 これに関連して、メモリが 4GB 以上ある機種で 4GB 以上のメモリが割り当てられてうまく起動できない問題が一時期発生していました。

メモリアロケーターは Slab アロケーターを採用していますが、よくメモリが不足するようになってきたのでパラメータ調整中です。

ファイルシステム

起動時に initrd.img というファイルを読み込んで RAM ディスクとしてマウントしています。

ファイルシステム周りは将来非同期 I/O に対応するため仮実装の場所が多いです。

はりぼて OS エミュレーション

はりぼて OS の API の一部をエミュレーションで対応し、はりぼて OS のアプリがある程度動作します。 もともと initrd に対応してた時に、もしかして結構簡単に実装できるのではということで試験的に実装したものです。

はりぼて OS の 32bit アプリケーションを動かすためだけにカーネルに一部特殊なコードを実装しています。 将来は、エミュレーターやバイナリトランスレーションを導入してカーネル内部の特別扱いを辞めたいと考えています。

WebAssembly ランタイム

標準のアプリケーションバイナリ形式として WebAssembly を採用し、現在はインタプリタで実装しています。 やはり時々動作が遅いと感じることがあるので将来は JIT 対応したいです。

もともと moe でやりたかったのがこの WebAssembly 対応でしたが、諸般の事情で思うように実装が進まず、 myos で初めて実装する事ができました。

ここまでの機能が現状およそ2万行のコードで実現されています。 そのうち WebAssembly に関するコードが 1/4 程度あります。

本題

さて、 moe の後継ということは myos も megos ということになります。

megos はもともと独自の仮想機械を搭載していましたが、当時は色々と未成熟であまりうまく受け入れられませんでした。 一方、 WebAssembly は共通の仮想機械で将来性があります。 また、 WebAssembly で動くということは、ランタイムを移植すれば Web ブラウザでも同じアプリが実行できるということになります。

そんなわけで、世の中がもう少し落ち着いたら myos も megos としてリリースしたいと思っています。

f:id:neriring16:20201229143638p:plain

myos の益々の発展をお祈りします。