JavaScriptでVM作って「30日でできる!OS自作入門」をやってみた (2日目)
カーネル/VM Advent Calendar の40日目です。ごめんなさい1日遅れ。他の方のも面白いですよ!左のリンクからどうぞ。
私、JavaScriptでVM(仮装機械)を色々作ってきましたが、いつも、言語処理系のVMばかりで、VMwareのような、マシン自体のVMはやったことがなかったので、トライしてみました。
選んだテーマは、川合秀実さんの5年前の名著、「30日でできる! OS自作入門」。これ、凄くいい本ですね!読んでみてびっくりしました。かなりお勧めです。英訳は出ていないと思いますが、英訳を出すに値する本だと思います。でも、川合さんのOSASKは終了(中断?)しちゃっているみたいですね。
- 作者: 川合秀実
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/03/01
- メディア: 単行本
- 購入: 36人 クリック: 735回
- この商品を含むブログ (299件) を見る
どうやって、VMを作るか、何時間も悩みました。OS自作入門では、NASKという川合さん自作のアセンブラとC言語で書かれています。C言語で書かれたのも一度NASKのアセンブラに変換されて、最終的にバイト列に変換されるので、NASKをターゲットにすることにしました。というわけで、やることは、CPUとBIOSの作成です。
インタープリタ方式にするか、コンパイラ方式にするかも悩んだのですが、とりあえず、コンパイラ方式にしました。NASK は LIST ファイルという、左側にバイト列があって、右側にニーモニックが出る、扱いやすい出力を作ってくれます。これを、Groovyで x86 -> JavaScript のコンパイラを作り、JavaScript に変換することにしました。本当はコンパイラを JavaScript で書きたかったのですが、ごめんなさい、手抜きです。
やってみて思ったのですが、x86 のバイト列は、命令列とデータ列が混在になっていて、コンパイルがやっかいです。NASK のアセンブラなら、データ列の部分は DB などのデータ列を表現するニーモニックを使っているので、データ列を避けてコンパイルすることができます。今回はそれに逃げています。本当にコンパイルしようと思ったら、JavaScript でJITコンパイラを作り、x86 -> JavaScript のソースコードに変換して、それを eval() で読み込むロジックが必要そうです。データとプログラムが混在するバイト列の中で、実行しようとした番地はプログラムの始まりなので、そこからJITコンパイルしていけば良さそうです。ただし、プログラムの終わりがわからないので、適当なところで中断して、そこから先も実行しようとしたら、再度コンパイルすると言う処理が必要そうです。また、プログラムの自己書き換えとかがあると、やっかいかも。
OS自作入門は、1日目はビルド方法などなので、2日目から挑戦しました。2日目は、print "\n\nhello, world\n" を実行するだけのOSです。ちなみに、3日目から32ビットモードになり、VRAMの操作が必要で、ハードルがぐんと上がります。いつか機会があったら、3日目も挑戦したいです。
あと、もう一つ愚痴。x86 って命令数がなんか多いですね!Intel® 64 and IA-32 Architectures Software Developer Manuals | Intel® Software に命令セットのマニュアルがあり、なんか、わかりにくく、x86 -> JavaScript の変換はだいぶ想像で作ってしまいました。(追記:Resource & Design Center for Development with Intel に日本語マニュアルがあるんですね)
と言うわけで、作ったファイルやデモの一覧。
- helloos.nas - これが、元のアセンブラです。川合さんのコメントが大量に入っていてわかりやすいです。一文字ずつ読み込んで、INT 0x10 を使ってビデオBIOSを呼び出します。末尾に、RESB 1469432 という命令が入っていて、これは、サイズを1.4MBのフロッピーのサイズに揃えるために入っているのですが、これがあると次のLISTファイルの生成でエラーになるのでコメントアウトしました。
- helloos.lst - 付属の asm.bat を書き換え、nask.exe helloos.nas helloos.img helloos.lst で生成できます。左側に番地やバイト列がつきます。
- Compiler.groovy - これが、lst -> JavaScript のコンパイラです。前半の方で lst を読み込んで、後半の方で JavaScript を生成しています。170行程度ですし、たぶん、簡単に読めると思います。実行すると、helloos.js を生成します。
- videoBios.js - ビデオBIOSの部分です。id が stdOut のいうDIVタグに innerHTML で追加しています。
- helloos.js - これが、コンパイル結果です。素直にコンパイルしています。末尾に、全てのバイト列を含めていて、これを、一文字ずつ print する時に読み込んでいます。
以上により作られるデモがこれです〜!ちゃんと表示された!