在kvm中实现自定义超级调用

时间:2015-11-08 04:47:29

标签: kernel ubuntu-14.04 virtualization kvm hypervisor

我对虚拟化非常陌生,最近我一直在努力熟悉VMM的运行方式以及如何进行超级调用。

谈论我打算在KVM中实现一个新的超级调用,它安装在我的Ubuntu桌面上,然后可以从访客环境中调用。通过这个超级调用,我打算只返回一个字符串说"你好世界&#34 ;.在这一点上,我对如何实现它毫无头绪。如果你能指导我如何实现这样的超级调用,那将非常有帮助。谢谢!

2 个答案:

答案 0 :(得分:2)

您可以在用户程序中使用vmcall指令在KVM中进行超级调用。您需要在kvm中为此VMCALL编写处理程序。如果您在guest中运行代码;

#define VMCALL_ID 100
do_vmcall ()
{
   asm volatile ("vmcall" : "eax"(VMCALL_ID));
}

它将导致KVM中的陷阱。 kvm将调用handle_vmcall函数。在handle_vmcall函数中,您需要编写与此对应的处理程序。

int handle_vmcall(struct kvm_vcpu *vcpu)
{
    unsigned eax = kvm_read_register(vcpu, VCPU_REGS_RAX);

    switch (eax) {
        case VMCALL_ID:
            BLAH; break;
        default: BLAH; BLAH;
    }
    return 0;
}

答案 1 :(得分:1)

下面的补丁实现了一个超级调用,trace_printk" Hello World"致主持人的ftrace。 (基本代码是Linux 4.10。)

  1. (在来宾内核源代码中)添加调用超级调用的系统调用:
  2. 
        diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
        index e93ef0b..2ff3b3f 100644
        --- a/arch/x86/entry/syscalls/syscall_64.tbl
        +++ b/arch/x86/entry/syscalls/syscall_64.tbl
        @@ -338,6 +338,7 @@
         329    common  pkey_mprotect       sys_pkey_mprotect
         330    common  pkey_alloc      sys_pkey_alloc
         331    common  pkey_free       sys_pkey_free
        +332    common  hello_hypercall     sys_hello_hypercall
    
        diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
        index 91a740f..19208d5 100644
        --- a/include/linux/syscalls.h
        +++ b/include/linux/syscalls.h
        @@ -902,5 +902,6 @@ asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len,
                          unsigned long prot, int pkey);
         asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
         asmlinkage long sys_pkey_free(int pkey);
        +asmlinkage long sys_hello_hypercall(void);
    
         #endif
    
        diff --git a/hello_hypercall/hello_hypercall.h b/hello_hypercall/hello_hypercall.h
        new file mode 100644
        index 0000000..cc727ee8
        --- /dev/null
        +++ b/hello_hypercall/hello_hypercall.h
        @@ -0,0 +1 @@
        +asmlinkage long sys_hello_hypercall(void);
    
        diff --git a/hello_hypercall/Makefile b/hello_hypercall/Makefile
        new file mode 100644
        index 0000000..6247351
        --- /dev/null
        +++ b/hello_hypercall/Makefile
        @@ -0,0 +1 @@
        +obj-y:=hello_hypercall.o
    
        diff --git a/Makefile b/Makefile
        index f1e6a02..6a84315 100644
        --- a/Makefile
        +++ b/Makefile
        @@ -910,7 +910,7 @@ export mod_sign_cmd
    
         ifeq ($(KBUILD_EXTMOD),)
        -core-y     += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
        +core-y     += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ hello_hypercall/
    
         vmlinux-dirs   := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
    
    1. (在来宾内核源代码中)实现系统调用以调用超级调用
    2. 
          diff --git a/hello_hypercall/hello_hypercall.c b/hello_hypercall/hello_hypercall.c
          new file mode 100644
          index 0000000..aa333f8
          --- /dev/null
          +++ b/hello_hypercall/hello_hypercall.c
          @@ -0,0 +1,17 @@
          +#include<linux/kernel.h>
          +#include<linux/syscalls.h>
          +#include<linux/init.h>
          +#include<linux/linkage.h>
          +#include "hello_hypercall.h"
          +#include<uapi/linux/kvm_para.h>
          +#include<linux/cpumask.h>
          +
          +asmlinkage long sys_hello_hypercall(void)
          +{
          +   kvm_hypercall0(KVM_HC_HELLO_HYPERCALL);
          +   return 0;
          +}
      

      kvm_hypercall0使用零参数调用X86_FEATURE_VMMCALL(其他kvm_hypercall函数最多可处理四个参数)。数字KVM_HC_HELLO_HYPERCALL(在include/uapi/linux/kvm_para.h中定义)作为超级调用号传入。在使用超级调用号和可能的参数调用X86_FEATURE_VMMCALL之后,执行将跳转到kvm_emulate_hypercall中的主机内核函数arch/x86/kvm/x86.c

      有关详细信息,请参阅https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/kvm_para.h#L21

      1. (在主机内核源代码中)定义超级调用号码(include/uapi/linux/kvm_para.h)并打印&#34; Hello World&#34;作为超级调用代码(arch/x86/kvm/x86.c
      2. 
            diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
            index bf6cd7d..67304a17 100644
            --- a/include/uapi/linux/kvm_para.h
            +++ b/include/uapi/linux/kvm_para.h
            @@ -23,6 +23,7 @@
             #define KVM_HC_MIPS_GET_CLOCK_FREQ 6
             #define KVM_HC_MIPS_EXIT_VM        7
             #define KVM_HC_MIPS_CONSOLE_OUTPUT 8
            +#define KVM_HC_HELLO_HYPERCALL     9
        
            diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
            index e52c908..b755ccf 100644
            --- a/arch/x86/kvm/x86.c
            +++ b/arch/x86/kvm/x86.c
            @@ -6151,6 +6209,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
                    kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);
                    ret = 0;
                    break;
            +   case KVM_HC_HELLO_HYPERCALL:
            +       trace_printk("Hello World");
            +       break;
                default:
                    ret = -KVM_ENOSYS;
                    break;
        

        KVM_HC_HELLO_HYPERCALL存储超级呼叫号码9(有关现有超级呼叫号码,请参阅here)。在arch/x86/kvm/x86.c中,在kvm_emulate_hypercall函数中,添加超级调用号与KVM_HC_HELLO_HYPERCALL匹配的大小写。

        在来宾内核中调用超级调用,以在主机的ftrace上查看其输出。