livaの雑記帳

livaの雑記帳

OSとか作ってみたい

Toy OS meets Rump Kernel

Raphine(僕の自作OS)上でRump Kernelを立ち上げる事ができるようになった。

 

Rump Kernelとはなんぞやという話を簡単にすると、

 

  • NetBSDベースのLibraryOS
  • NetBSDカーネルとアプリケーションをstatic linkして1つのバイナリにできる。(Unikernel)
  • Linuxユーザーランドや、Xen、ベアメタル上で実行可能

 

Rump Kernelを使えば、どんな環境でもNetBSDアプリケーションが動かせるわけである。

 

さて、自作OS屋さんの悩みとして、以下のような物がある。

  • バイスを制御するためには自分でデバドラを書かなければならない。(デバドラを自分で書くのは大変なので、使いたいけども使えないデバイスが出てきたりする)
  • 互換性を持たない場合、既存のアプリケーションが動かせない。

 

これらの悩みに対する、ちょっとセコい解決策として、自作OS上でRump Kernelを起動できるようにする、というのを思いついたので、実装してみることにした。

 

これによってどんな事ができるようになるかというと、

とはいえ、NetBSDが諸々の大事な事をやり、自分のOSは特に仕事をしていないので、「自分のOSでいろいろやっている感」はない。

まあそうなると、「それってNetBSDで良くない?」って思う人もいると思うけど、これをどう活用するかは今回の話の趣旨から外れてしまうので、割愛。

 

 

話を戻して、とりあえずRump KernelがRaphine上で動きましたよ、という事なのだけども、軽くその実装について書いてみる。

 

全体構成はこんな感じ。

f:id:liva_h:20170810175344p:plain

Rump Kernelにはベアメタルで動かすためのバックエンドコードがあり、これを改造して、新しいバックエンドを作った。Rump Kernelがベアメタル上で動作する時はRing0なので、今回改造したRump KernelバックエンドコードもRing0で動く。

イメージ的にはRump KernelというカーネルモジュールがRaphineの中で動く、といった感じ。実際の実装としてはRing0上で動くアプリケーションという風に言う事もできるし、RaphineがRump Kernelのハイパーバイザとなっている、という事もできるかもしれない。

 

実装は割と荒削りなので、pciをサポートしていなかったり、タイマ周りが雑だったりするのだけど、とりあえず以下のようなコードをNetBSDアプリケーションにして、Rump Kernel内に組み込んで起動する事ができるようになった。

#include <stdio.h>

#include <unistd.h>

int main() {

  printf("test1\n");

  printf("test2\n");

  return 0;

}

 

起動画面はこんな感じ。

f:id:liva_h:20170810180544p:plain

load rump.binというコマンドでRump Kernelバイナリをロードする。

ELFの解析等をRaphine側でやった後でエントリポイントに飛ぶと、Rump Kernel(NetBSD)がCopyright表示を出して起動する。

初期化が終わると、上に貼ったコードの通りtest1、test2と表示して終了する、といった具合。

 

ソースへのリンクは以下の通り。

Rump Kernelが起動する自作OS

github.com

実装したRump Kernelバックエンド

github.com

 

 

尻切れトンボだけど、終わり。