bobuhiro11/gokvm - GitHub

2021/2/24 WSL2 サポート 4f6b785

WSL2(Windows Subsystem for Linux 2)のUbuntu 20.04で gokvm を実行すると、 IOポート 0x64 への出力が無限に繰り返され、Initプロセスの起動まで到達しなかった。 どうやら PS/2 キーボード周りの挙動が原因のようだ。

kvmtool では in (0x61) に対して 0x20 を返している 1 のでそれを踏襲する形で対応した。 IOポート 0x61は NMI (Non-Maskable Interrupt)のステータスとコントロールレジスタとして使われているようだ 2。 このステータスレジスタの内容を調べると、bit 5はmirrors timer 2 output condition を意味するが、 これ以上は解釈できず。 理解できていない部分はあるが、結果として WSL2 での ゲストVMの起動もできるようになった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
0061 r KB controller port B control register (ISA, EISA)
       system control port for compatibility with 8255
       bit 7  parity check occurred
       bit 6  channel check occurred
       bit 5  mirrors timer 2 output condition
       bit 4  toggles with each refresh request
       bit 3  channel check status
       bit 2  parity check status
       bit 1  speaker data status
       bit 0  timer 2 gate to speaker status

出典:XT, AT and PS/2 I/O port addresses

2021/2/27 Fedora標準のカーネルでゲストを起動 a86d86b

gokvm 内でビルドしたカーネルだけでなく、広く使われているカーネルにも対応したい。 単純に起動してみると以下のようにカーネルパニックとなった。 KVM API の KVM_SET_MEMORY_REGION には1GBメモリを渡しているので、 下の出力を見ると明らかにそのサイズが小さいように思う。

1
2
3
4
5
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] BIOS-88: [mem 0x0000000000000000-0x000000000009efff] usable
[ 0.000000] BIOS-88: [mem 0x0000000000100000-0x00000000002fa7ff] usable
[ 0.020431] Kernel panic - not syncing: initrd too large to handle,
            disabling initrd (33769847 needed, 22421504 available)

どうやら e820 エントリの指定が不正で、メモリが枯渇しているのかもしれない。 ちなみに、e820はメモリマップを管理するテーブルで、メモリ開始位置・メモリ終了位置・フラグの組みをエントリとして持つ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
struct e820_entry {
	u64 addr;
	u64 size;
	enum e820_type type;
} __attribute__((packed));

struct e820_table {
	__u32 nr_entries;
	struct e820_entry entries[E820_MAX_ENTRIES];
};

出典:linux/arch/x86/include/asm/e820/types.h#L55-L97

2021/2/28 e820のセットアップ 6712e09

e820 をどうやって設定すれば良いのか。 ブート時の挙動だろうということでx86のBoot周りのドキュメントを見直し、 Zero Page 3と呼ばれる領域の中にe820_entriesとe820_tableを見つけた。 Zero Pageに記載されたオフセットは、前回の記事で触れた Boot Protocol Real-Mode Kernel Header 4 と同じように解釈できる。 そこで、リファクタリングを施しe820 entry も自由に操作できる構造にした。 実際に登録すべきエントリの内容についてはkvmtool 5 を参考にした。 最終的に、Fedora標準のカーネルを使ってゲストを起動できるようになった。

これから

ディスクやNICのデバイスエミュレーションに手を出そうかと模索中。 NICであれば e1000(Intel Intel 8254x)とvirtio-net だとどちらが簡単だろうか。 ナイーブな実装で良いので動くところまで持っていきたい。 いずれにしてもPCIデバイスのConfiguration Spaceの初期化周りのエミュレーションは必要になるだろう。


  1. kvmtool/hw/i8042.c#L312 ↩︎

  2. Re: question: i/o port 0x61 on x86 archs, LKML ↩︎

  3. Zero Page, kernel.org ↩︎

  4. The Real-Mode Kernel Header ↩︎

  5. kvmtool/x86/bios.c#L66-L86 ↩︎