BitVisor でブートオプションっぽく文字列を取得してみる

# はじめに
BitVisor には元々，ブート時にオプションを受け取る機能を持っていませんが．
しかし，少し設定を変えるためだけにdefconfigやコードの中にあるパラメータを書き換えてビルドし直すのは大変です．
そこで，Linux のようにブート時にオプションを受け取れるようにしてみたいと思います．

この記事では，オプションとして渡す文字列をBitVisor で受け取るところまでやってみたいと思います．
また，この記事の方法は，BitVisor を Multiboot で起動する場合のみ使える方法になります．

# BitVisor のブートについて
BitVisor をブートする方法はいくつかあります．
そのうちの一つに Multiboot によるブートがあります．
Grub や iPXE のようなブートローダから起動する場合がこれにあたります．
詳しくは@hdk_2 さんのこちらの記事で　http://qiita.com/hdk_2/items/b73161f08fefce0d99c3

# BitVisor のMultiboot について
Multiboot の仕様には古いバージョン(< ver2.x)と新しいバージョン(ver2.x)の2つのメジャーバージョンがあります．
その中で，BitVisor は 古い仕様に沿って起動するようになっています．

どちらのバージョンの仕様でもそうですが， Multiboot で起動する場合，ブートローダから起動するカーネルへ情報を渡すためのデータ構造が定義されています(ここで渡す情報を multiboot infomation と呼ぶみたいです)．
ブートローダは仕様で定められたデータ構造に従って，メモリ上に情報を格納します．
その後，情報を格納した先の物理メモリアドレスを **EBX** レジスタに格納し，カーネルを起動します．
ですので，起動されるカーネルからは，EBXに格納されている物理アドレスをたどることで，ブートローダから情報を受け取ることができます．
ブートオプション(仕様では command line という用語になっています)もこれに含まれています．

このデータ構造については，https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format から見ることができます (@hdk_2さんに教えていただきました，ありがとうございます．)

# 実際にやってみた
## ブートオプションを取得するための処理を書く

以下のような変更を加えます(このパッチは 118:cc32c7634f7e のコミットにあてられると思います)
~~~ソースコードの細かい説明は省略します．~~~
~~~気になるところがあれば，コメントいただければ答えると思います．~~~
(追記 2015/12/20: さすがに説明なさすぎるので説明書きました)


```diff
diff -r 1c2f54453f09 core/main.c
--- a/core/main.c	Wed Dec 02 00:36:55 2015 +0900
+++ b/core/main.c	Sat Dec 19 23:46:13 2015 +0900
@@ -101,6 +101,30 @@
 	}
 }
 
+#define MAX_CMDLINE_SIZE 1024
+char cmdline_str[MAX_CMDLINE_SIZE];
+
+static void
+get_cmdline_params(struct multiboot_info *mi)
+{
+        char *addr;
+        int i;
+        
+        if(!mi->flags.cmdline){
+                printf("no cmdline\n");
+                return;
+        }else{
+		addr = mapmem (MAPMEM_HPHYS, mi->cmdline,
+                               MAX_CMDLINE_SIZE);
+                for(i = 0; i < MAX_CMDLINE_SIZE; i++){
+                        cmdline_str[i] = addr[i];
+                        if(addr[i] == '\0')
+                                break;
+                }
+                printf("cmdline:%s\n", cmdline_str);
+        }
+}
+
 static void
 copy_minios (void)
 {
@@ -302,6 +326,7 @@
 
 	if (!uefi_booted)
 		bios_boot_drive = detect_bios_boot_device (&mi);
+　　　　　　get_cmdline_params(&mi);
 	save_bios_data_area ();
 	callrealmode_usevcpu (current);
 	if (minios_startaddr) {


```

## パッチの説明(2015/12/20 に追記)
### core/multiboot.h に multiboot infomation を格納する構造体が定義されてるぞ!
BitVisor はもともと multiboot infomation の一部を用いて処理をしているようです．
このために，BitVisor はすでに multiboot infomation を取得するようになっています．
そのために書かれている構造体が `core/multiboot.h` にあります．

`struct multiboot_info` という構造体が multiboot infomation のデータの構造を示しています．
また， このデータ構造の先頭には，どのデータフィールドは有効で，どのデータフィールドが無効なのかを示すフラグが入っています．
これに対応するのが，`struct multiboot_info_flags` という構造体になります．

### mi って変数は何?
ブートオプションを取得する関数である `get_cmdline_params()` に引数として `&mi` を渡しています．
この変数は，`core/main.c` の中で， `static struct multiboot_info mi;` と定義されています．
これに，ブートローダからの情報が格納されています(`vmm_main()`関数で格納しています)．

### get_cmdline_params()
ここまで説明したところで，`get_cmdline_params()` を見てみましょう．
`if(!mi->flags.cmdline)` では，multiboot infomation の中の cmdline (ブートオプション) のフィールドが有効か否かを見ています．
もしも有効ならば，mi->cmdline にブートオプションの文字列があるアドレスの物理アドレスが入っているので，それをマップして，そこから文字列を　`cmdline_str` へコピーします．
文字列はC言語っぽく，終端がnull文字になるように格納されています．
文字列をコピーし終えたら，その文字列をprintしてこの関数は処理を戻します．


## ブートローダからブートオプションとなる文字列を渡す設定
例えば，http://tokikane-tec.blogspot.jp/2015/02/ipxe-bitvisor.html の方法での iPXE ブートするときは，以下のようにブートオプションを渡します．

```
  boot head_bitvisor.elf This is command line parameters
```

## 動作結果
dbgsh の log コマンドで確認してみると以下のようになるかと思います．

```
Using VMX.
Processor 0 3998900544 Hz (Invariant TSC)
Processor 2 3998901440 Hz (Invariant TSC)
Processor 3 3998900160 Hz (Invariant TSC)
Processor 1 3998899008 Hz (Invariant TSC)
BIOS boot device detection failed. Using 0x80.
cmdline:tftp://10.90.1.51/head_bitvisor.elf This is command line parameters
Loading drivers.
Intel PRO/1000 driver registered
PCI device concealer registered
PCI: finding devices...
PCI: 25 devices found
MCFG [0] 0000:00-7F (F0000000,8000000)
Starting a virtual machine.
Loading MBR.

```

`cmdline:tftp://10.90.1.51/head_bitvisor.elf This is command line parameters` とちゃんと取得できています． 最初のtftp://.... っていうのは bitvisor.elf を置いている場所へのパスのようですね．きっと grub で起動しても同じようなのが入るのではないのでしょうか．
実際にブートオプションだけ取り出したければ，スペース区切りで最初のものを無視するようにすればいいかと思います．


# おわりに
multiboot でBitVisor をブートするときにブートローダからブートオプションのように文字列を渡す方法を示しました．
BitVisor の挙動をリビルドなしで変えるのに役立ちそうです．
例えば，vmm.driver.pci の設定やログ出力先のアドレスをこうやって渡してみたりすると便利かもしれません．

 
#