💻

WASMバイナリを実行する自作OS, mavisの紹介

2023/09/02に公開
2

mavisとは

mavisは私がフルスクラッチで開発している自作OSです。

https://github.com/RI5255/mavis

これをビルドしてmake runするとshellが立ち上がり、"hello"コマンドを実行すると"Hello World!"が表示されます。

wasm-shell

現状できることはたったこれだけですが、面白いのはその仕組みです。実は上の画像のshellとhello worldプログラムはどちらも WASMバイナリ です。そしてkernelは低レベルなメモリ管理機能とタスク管理機能を除くと、「WASMバイナリをタスクとして実行する」以外の機能を持ちません。つまりkernelがWASM Runtimeであり、それによって"ユーザーランド"を実現しているということです。

このOSは「仮想メモリ」を持ちません。なぜならWASMバイナリは位置独立だからです。WASMはスタックマシンベースの命令セットなので、スタックさえ用意すればどこでも、何度でも実行できます。ページテーブルの切り替えは重い処理なのでこれが必要なくなるのは魅力的です。

さらにこのOSは「システムコール」を持ちません。全てのプログラムがring0で動くので「システムコール」は全て関数呼び出しになります。ここでいう関数とは、ランタイム(kernel)が持つビルトイン関数のことです。関数の一覧は以下で定義されています。

https://github.com/RI5255/mavis/blob/main/kernel/env.h

WASIを実装することも考えましたが、WASIは「WASM Runtimeをkernelにする」という目的には合わないと考え、採用しませんでした。例えばfd_writeを実装するといっても、現状自作OSにはファイルシステムがありません。この目的には、WASIよりもさらに低レベルなインタフェースが適していると考え、このような実装にしました。これらはWASMバイナリから使用することができます。例を見てみましょう。以下は冒頭で実行されていたhello worldプログラムのソースコードです。

https://github.com/RI5255/mavis/blob/main/servers/hello/main.c

ここで使用されているprintf,そしてその中で使用されるputcharのソースコードは以下です。putcharの中でarch_serial_writeが使用されています。

https://github.com/RI5255/mavis/blob/main/lib/libc/printf.c

https://github.com/RI5255/mavis/blob/main/lib/libc/putchar.c

上のputchar.c, printf.c, main.cが WASMバイナリ にコンパイルされます。重要なのはアーキテクチャ依存の処理(この例でいうとシリアルポートの読み書き)がバイナリから取り除かれていることです。現状、kernelはriscv32しかサポートしていませんが、他のアーキテクチャでもarch_serial_writeという関数だけ用意すれば 同じhello worldバイナリ が動きます。この意味で、このhello worldバイナリは「世界一ポータブルなhello worldバイナリ」といえるかもしれません。

展望

WASM Runtimeをkernelとして用い、低レベルなインタフェースを提供することで、バイナリからアーキテクチャ依存の処理を取り除き、汎用的なバイナリを作ることができます。これは簡単に言うと、Cプログラムを書くときにどうしてもアセンブリで書かなければいけない部分を全てランタイム(kernel)のビルトイン関数として実装し、アーキテクチャ依存の部分をランタイム(kernel)に吸収させるということです。

例えば(セキュリティの問題はありますが)mmio registerを読み書きする関数をkenelに実装すれば、デバイスドライバをWASMバイナリにできます。さらにプロセス間通信の仕組みを用意してWASMバイナリ同士がやりとりできるようにすれば、「すべてのserverがWASMバイナリなmicrokernel」を作ることができます。(これが私がやろうとしていることです)

future

これが実現できれば、ライブラリを使うぐらいの気軽さで"OS"の機能を切り替えることができるようになるかもしれません。アプリケーションの汎用性を保ちながら低レベルの最適化もできるのは魅力的です。さらにすべてがWASMバイナリで、「どのようなアーキテクチャで実行されるのか」を意識する必要がなくなるため、分散システムへの応用もできるかもしれません。

参考文献

[1] Nullpo_head. カーネル空間ですべてのプロセスを動かすには. 2019

https://speakerdeck.com/nullpo_head/kanerukong-jian-desubetenopurosesuwodong-kasuniha-tal-sfi-wasmtoka

[2] 怒田 晟也. 自作OSで学ぶマイクロカーネルの設計と実装.秀和システム. 2023

https://www.shuwasystem.co.jp/book/9784798068718.html

[3] technohippy. 作って学ぶWebAssembly. 2021

https://booth.pm/ja/items/3159056

[4] ひたひた. WebAssemblyテキストフォーマットで読み解くコンピューティングの未来. 2021

https://techbookfest.org/product/4765275696136192?productVariantID=4701025602633728

[5] 怒田 晟也. Writting an OS in 1000 Lines. 2023

https://operating-system-in-1000-lines.vercel.app/ja/welcome

Discussion

ぶんちんぶんちん

非常に面白いと思いました。
k8sを積んでる無駄なマイクロサーバーは代替できそうですよね