PPC の KVM 準仮想化インターフェース

PowerPC 上の KVM が動作する基本原則は、カーネル空間のコードをすべて PR=1(ユーザ空間)で実行することである。こうすると特権命令をすべて トラップでき、それに応じてエミュレーションできる。

残念ながらこれが欠点でもある。本来なら別の方法で扱えるはずの特権命令が かなりあり、それらは不要にハイパーバイザへ戻ってしまう。

これを助けるのが PPC PV インターフェースである。特権命令を、ハイパーバイザの 助けを借りて非特権命令に変換する。これにより、私のベンチマークのいくつかでは 仮想化のコストが約 50% 減る。

このインターフェースのコードは arch/powerpc/kernel/kvm* にある。

存在の確認

KVM 上で動作しているかどうかを調べるために、デバイスツリーを利用する。 Linux が KVM 上で動作しているときは、ノード /hypervisor が存在する。 そのノードには値 "linux,kvm" を持つ compatible プロパティがある。

PV 対応の KVM 上で動作していると分かったら、以下に述べるハイパーコールを 使えるようになる。

KVM ハイパーコール

デバイスツリーの /hypervisor ノードの中に 'hypercall-instructions' という プロパティがある。このプロパティには、ハイパーコールを構成する最大 4 個の オペコードが入っている。ハイパーコールを呼ぶには、単にこれらの命令を 呼べばよい。

パラメータは次のとおりである:

レジスタ

入力

出力

r0

volatile

r3

第 1 パラメータ

戻り値

r4

第 2 パラメータ

1 番目の出力値

r5

第 3 パラメータ

2 番目の出力値

r6

第 4 パラメータ

3 番目の出力値

r7

第 5 パラメータ

4 番目の出力値

r8

第 6 パラメータ

5 番目の出力値

r9

第 7 パラメータ

6 番目の出力値

r10

第 8 パラメータ

7 番目の出力値

r11

ハイパーコール番号

8 番目の出力値

r12

volatile

ハイパーコールの定義は汎用コードで共有される。そのため、KVM ハイパーコール ごとに KVM ベンダコード (42 << 16) との OR を取る必要がある点を除けば、 x86 と powerpc で同じハイパーコール番号が使える。

戻り値は次のとおりである:

コード

意味

0

成功

12

ハイパーコールが実装されていない

<0

エラー

マジックページ

ハイパーバイザとゲストの間の通信を可能にするため、スーパバイザに見える レジスタ状態の一部を含む新しい共有ページがある。ゲストは KVM ハイパーコール KVM_HC_PPC_MAP_MAGIC_PAGE を使ってこの共有ページをマップできる。

このハイパーコールを発行すると、ゲストは常にマジックページを望みの位置に マップできる。第 1 パラメータは MMU が有効なときの実効アドレスを示す。 第 2 パラメータは、対象に当てはまるなら、リアルモードでのアドレスを示す。 今のところ、常にページを -4096 にマップする。こうすると絶対ロード命令と 絶対ストア命令でアクセスできる。次の命令はマジックページの先頭フィールドを 読む:

ld      rX, -4096(0)

このインターフェースは、後でマジックページにレジスタを追加する必要が 生じたときに拡張できるように設計されている。マジックページにフィールドを 追加するなら、ホストがより多くのレジスタを渡せることを示す新しい ハイパーコール機能も定義すること。ホストがその追加機能をサポートする 場合にのみ、それを使うこと。

マジックページのレイアウトは、arch/powerpc/include/uapi/asm/kvm_para.h の struct kvm_vcpu_arch_shared で記述されている。

マジックページの機能

KVM ハイパーコール KVM_HC_PPC_MAP_MAGIC_PAGE でマジックページをマップすると、 2 番目の戻り値がゲストに渡される。この 2 番目の戻り値には、マジックページ内で 利用できる機能のビットマップが入っている。

現在、マジックページには次の拡張が利用できる:

KVM_MAGIC_FEAT_SR

マジックページ内で SR レジスタを読み書きできるようマップする

KVM_MAGIC_FEAT_MAS0_TO_SPRG7

MASn、ESR、PIR、高位の SPRG をマップする

マジックページの拡張機能を使う前に、その機能が存在するかを確認すること!

マジックページのフラグ

ホストが特定の機能に対応しているかを示す機能フラグに加えて、ゲストが 何かに対応しているかをホストに伝えるチャネルもある。これを「フラグ」と呼ぶ。

フラグは実効アドレスの下位 12 ビットでホストに渡される。

現在、ゲストが公開できるフラグは次のとおりである:

MAGIC_PAGE_FLAG_NOT_MAPPED_NX ゲストがマジックページに対して NX ビットを正しく扱う

MSR ビット

MSR には、ハイパーバイザの介入が必要なビットと、直接の介入が不要なビットが ある。後者は、ゲストへ入るときにだけ解釈されるか、ハイパーバイザの動作に 影響しないためである。

ゲスト内で安全に設定できるビットは次のとおりである:

  • MSR_EE

  • MSR_RI

MSR で他のビットが変わる場合は、やはり mtmsr(d) を使うこと。

パッチを当てる命令

32 ビットシステムでは、"ld" 命令と "std" 命令がそれぞれ "lwz" 命令と "stw" 命令に変換され、ビッグエンディアンに対応するためにオフセット 4 が加えられる。

以下は、Linux カーネルがゲストとして動作するときに行うマッピングの一覧である。 命令トラップも共有ページに作用するため、これらのマッピングの実装は任意である。 つまり、特権命令の呼び出しはこれまでどおり動作する。

変換前

変換後

mfmsr rX

ld rX, magic_page->msr

mfsprg rX, 0

ld rX, magic_page->sprg0

mfsprg rX, 1

ld rX, magic_page->sprg1

mfsprg rX, 2

ld rX, magic_page->sprg2

mfsprg rX, 3

ld rX, magic_page->sprg3

mfsrr0 rX

ld rX, magic_page->srr0

mfsrr1 rX

ld rX, magic_page->srr1

mfdar rX

ld rX, magic_page->dar

mfdsisr rX

lwz rX, magic_page->dsisr

mtmsr rX

std rX, magic_page->msr

mtsprg 0, rX

std rX, magic_page->sprg0

mtsprg 1, rX

std rX, magic_page->sprg1

mtsprg 2, rX

std rX, magic_page->sprg2

mtsprg 3, rX

std rX, magic_page->sprg3

mtsrr0 rX

std rX, magic_page->srr0

mtsrr1 rX

std rX, magic_page->srr1

mtdar rX

std rX, magic_page->dar

mtdsisr rX

stw rX, magic_page->dsisr

tlbsync

nop

mtmsrd rX, 0

b <special mtmsr section>

mtmsr rX

b <special mtmsr section>

mtmsrd rX, 1

b <special mtmsrd section>

[Book3S only]

mtsrin rX, rY

b <special mtsrin section>

[BookE only]

wrteei [0|1]

b <special wrteei section>

命令によっては、ロード命令やストア命令では足りないほど、何が起きているかを 判断するロジックが必要になる。それらにパッチを当てられるようにするため、 命令をその場で変換して書き込める RAM をいくらか確保しておく。起きることは 次のとおりである:

  1. エミュレーションコードをメモリにコピーする

  2. そのコードを、エミュレートする命令に合うようにパッチする

  3. そのコードを、元の pc + 4 に戻るようにパッチする

  4. 元の命令を、新しいコードへ分岐するようにパッチする

こうすると、1 つの命令の代わりに任意の量のコードを注入できる。例えば EE=1 を 設定するときに、保留中の割り込みを確認できるようになる。

PowerPC 上の KVM におけるハイパーコール ABI

  1. KVM ハイパーコール(ePAPR)

これらは ePAPR 準拠のハイパーコール実装である(前述)。ePAPR の idle hcall の ように、汎用のハイパーコールもここで実装されている。これらはすべての ターゲットで利用できる。

  1. PAPR ハイパーコール

PAPR ハイパーコールは、サーバ PowerPC の PAPR ゲスト(QEMU の -M pseries)を 動作させるのに必要である。これらは POWER ハイパーバイザである pHyp が実装する ものと同じハイパーコールである。一部はカーネル内で処理され、一部はユーザ空間で 処理される。これは book3s_64 でのみ利用できる。

  1. OSI ハイパーコール

Mac-on-Linux も PowerPC 上の KVM の利用者であり、独自のハイパーコールを 持っている(KVM よりずっと前から)。これは互換性を保つためにサポートされる。 これらのハイパーコールはすべてユーザ空間へ転送される。これは book3s_32 でのみ 役に立つが、book3s_64 でも使える。