複数の引数を持つkvmハイパーコール


8

私は現在、kvmを使用して小さなハイパーバイザーとカーネルを構築しようとしていますが、複数の引数を持つハイパーコールが正しく機能するように努力しています。

これが私が試したものです:

// guest.c

#define KVM_HYPERCALL vmcall
// #define KVM_HYPERCALL vmmcall
// #define KVM_HYPERCALL ".byte 0x0f,0x01,0xd9"
// #define KVM_HYPERCALL .byte 0x0f,0x01,0xc1"

static inline long kvm_hypercall4(int nr, unsigned long p1,
                  unsigned long p2, unsigned long p3,
                  unsigned long p4) {
    long ret;
    asm volatile(KVM_HYPERCALL
             : "=a"(ret)
             : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
             : "memory");
    return ret;
}

これらのハイパーコールのいずれかがvcpu->kvm_run->exit_reason6に等しくなり、これは私の驚きのKVM_EXIT_MMIO代わりにKVM_EXIT_HYPERCALL

switch (vcpu->kvm_run->exit_reason) {
  case KVM_EXIT_MMIO:
    printf("syscall: %lld\n", vcpu->kvm_run->hypercall.nr); // prints 0
    printf("arg 1: %lld\n",  vcpu->kvm_run->hypercall.args[1]); // prints 0
    printf("arg 2: %lld\n", vcpu->kvm_run->hypercall.args[2]); // prints 0
    printf("arg 3: %lld\n",  vcpu->kvm_run->hypercall.args[3]); // prints 0

    if(ioctl(vcpu->fd, KVM_GET_REGS, &regs)<0) exit 1;

    printf("rax: %lld\n", regs.rax); // prints 0
    printf("rbx: %lld\n", regs.rbx); // prints 0
    printf("rcx: %lld\n", regs.rcx); // prints 0

終了の理由とは別にKVM_EXIT_MMIO、regが設定されないのはなぜですか?複数の引数でKVM_EXIT_HYPERCALLをトリガーする正しい方法は何ですか?

前もって感謝します

編集:重要な場合:Linuxカーネル5.4でdebianを実行している第9世代Intel i7 CPUを使用しています

回答:


1

KVM_EXIT_HYPERCALLドキュメンテーションによると、もはや使用されていません:

/* KVM_EXIT_HYPERCALL */
      struct {
          __u64 nr;
          __u64 args[6];
          __u64 ret;
          __u32 longmode;
          __u32 pad;
      } hypercall;

未使用。これはかつて「ユーザー空間へのハイパーコール」に使用されていました。このような機能を実装するには、KVM_EXIT_IO(x86)またはKVM_EXIT_MMIO(s390を除くすべて)を使用します。注KVM_EXIT_IOは、KVM_EXIT_MMIOよりも大幅に高速です。

そして、それKVM_EXIT_HYPERCALLも実装されていないようです。grepによる素早い検索。定義されていますが、次のように割り当てられることはありませんexit_reason

user@host:~/Linux/src> grep -R KVM_EXIT_HYPERCALL
include/uapi/linux/kvm.h:#define KVM_EXIT_HYPERCALL        3
include/uapi/linux/kvm.h:               /* KVM_EXIT_HYPERCALL */
Documentation/virt/kvm/api.rst:         /* KVM_EXIT_HYPERCALL */
tools/include/uapi/linux/kvm.h:#define KVM_EXIT_HYPERCALL        3
tools/include/uapi/linux/kvm.h:         /* KVM_EXIT_HYPERCALL */
tools/testing/selftests/kvm/lib/kvm_util.c:     {KVM_EXIT_HYPERCALL, "HYPERCALL"},
user@host:~/Linux/src>

Linuxバージョン:

user@host:~/Linux/src> git-describe --tags
v5.6-10895-g4c205c84e249
user@host:~/Linux/src>

このサイトには、2つの答えがあるカスタムVMCALLを実装する方法に関する古い質問があります。それらを試しましたか?


答えは、kvm_hypercall0またはアセンブリを使用して、引数が0のハイパーコールを作成する方法を示しただけです。しかし、私はそれを複数の引数で動作させるようにしており、私のシステムで提供されるkvm_hypercallNが期待どおりに動作しないようです。たとえば、regs.raxには、ゲストプログラムで割り当てた値が含まれることを期待していました
Gaetano

0

カーネルのドキュメントからkvm / api

exit_reasonがKVM_EXIT_MMIOの場合、vcpuはkvmで満たすことができなかったメモリマップI / O命令を実行しました。'is_write'がtrueの場合、 'data'メンバーには書き込まれたデータが含まれ、それ以外の場合はアプリケーションコードで埋める必要があります。

トリガーしたハイパーコールがこのような失敗を引き起こしました。
これは、呼び出したハイパーコールのコードによって異なります。


1)IOではなくvmcallを実行しました2)レジスタとVMMを正しくセットアップして、複数の引数をレジスタからVMMに渡すことができますか?-ioctl(KVM_GET_REGS、&regs)を介してレジスタを読み取ることができると思いますが、すべてのregがゼロのようです
Gaetano

@Gaetano私はVMCALLはあなたがKVM_HYPERCALLをredefinngの代わりに定義を使用している理由はまだundersoodない、例外としてKVM_EXIT_MMIOを上げていると思いますkvm_para.hたり、対応するarchitechture中1
mpromonet

お返事をありがとうございます。私はkvm_para.hを使用していますが、トラブルシューティングの目的で、プロジェクトとここにコピー&ペーストして、kvm以外の背景を持つ他のユーザーがディスカッションに参加できるようにしています。最終的には、VT-X / AMD-Vを正しく使用することです
Gaetano
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.