全虚拟化hypercall

在全虚拟化中,由于Guest OS 的代码没有被修改,因此Guest OS 的特权操作, 比如更新页表等主要通过VT 技术的VMX 操作来实现。敏感操作也不像半虚拟化那样通过超级调用来实现,也是通过VMX 的指令来实现。因此全虚拟化下的Guest OS 即HVM 很少使用超级调用。但是有时由于开发的需要,我们需要通过超级调用来实现一些功能。本报告的内容如下:添加一个hypercall, 并让HVM 像半虚拟化那样方便的调用该hypercall.


   1. 搭建实验环境

       机器是Fedora 8 作为dom0, xen 版本4.0.1, 需要创建一个HVM. 我们这里用ubuntu 作domU

步骤:

    a. 首先创建一个虚拟硬盘来安装hvm

    #mkdir hvm
    # dd if=/dev/zero of=/hvm/ubuntu.img bs=1k seek=10000k count=1

    b. 下载ubuntu 镜像文件ubuntu-9.04-desktop-i386.iso ,放到本地一个目录下,在这里我们放到/home/sploving/application/ 下

    c. 创建配置文件ubuntu.cfg ,用来安装domU, 如下:

           kernel = "/usr/lib/xen/boot/hvmloader"
        builder='hvm'

        memory = 1024
        vcpus=1
        name = "ubuntu"

        disk = [ 'file:/home/sploving/hvm/ubuntu.img,ioemu:hda,w ',

        'file:/home/sploving/application/ubuntu-9.04-desktop- i386.iso,ioemu:hdc:cdrom,r' ]


        vif = [ 'type=ioemu, bridge=virbr0' ]
        usbdevice='tablet'

        on_poweroff = 'destroy'
        on_reboot = 'destroy'
        on_crash = 'destroy'

         boot='d'
         vnc=1
         sdl=0

         vncdisplay=3

         import os, re
         arch = os.uname()[4]
         if re.search('64', arch):
         arch_libdir = 'lib64'
         else:
         arch_libdir = 'lib'
         device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'

    d. 安装domU

    #cd hvm
    #xm create ubuntu.cfg
    #vncviewer 127.0.0.1:3

    然后像平时安装操作系统的步骤来安装domU

    e. 安装完后,提示重启时,不要按“重启”,而是利用xm destroy ubuntu.
    然后修改配置文件ubuntu.cfg ,将boot='d' 该为boot='c'

    f. 启动hvm domU

    #xm create ubuntu.cfg
    #vncviewer 127.0.0.1:3


 2. xen 中添加超级调用
    该步骤的添加超级调用的方法和在半虚拟化添加超级调用的方式一样,具体如下:

    a. 首先注册一个hypercall 调用号。
    xen/include/public/xen.h
    #define __HYPERVISOR_tmem_op 38
    +#define __HYPERVISOR_create_sim 39

    b. 更新系统调用表
    /xen/arch/x86/x86_32/entry.S
    ENTRY(hypercall_table)
    .long do_tmem_op
    +.long do_create_sim

    ENTRY(hypercall_args_table)

    .byte 1 /* do_tmem_op */
    +.byte 2 /* do_create_sim */

    c. 定义函数头文件
    /xen/include/asm-x86/hypercall.h

    extern int
    do_kexec(
    unsigned long op, unsigned arg1, XEN_GUEST_HANDLE(void) uarg);
    +extern int

    +do_create_sim(
    + unsigned long paddr, int num);

    d. 定义函数( 函数定义在合适的文件中,这个例子采用mm.c)
    /xen/arch/x86/mm.c
    +int do_create_sim(unsigned long paddr, int num) {
    + printk("creat the sim space using shadow page!/n");
    +}


  3. HVM domU 中使用该 hypercall
    
    a. 首先在xen/arch/x86/hvm/hvm.c 中添加该hypercall

    static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = {
    [ __HYPERVISOR_memory_op ] = (hvm_hypercall_t *)hvm_memory_op,
    [ __HYPERVISOR_grant_table_op ] = (hvm_hypercall_t *)hvm_grant_table_op,
    [ __HYPERVISOR_vcpu_op ] = (hvm_hypercall_t *)hvm_vcpu_op,
    HYPERCALL(xen_version),
    HYPERCALL(event_channel_op),
    HYPERCALL(sched_op),
    HYPERCALL(set_timer_op),
    HYPERCALL(hvm_op),
    HYPERCALL(tmem_op),
    + HYPERCALL(create_sim)

    };


    b. 在HVM domU 中写一个模块sim.c ,来调用该hypercall, 如下:
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/vmalloc.h>
    #include <linux/mm.h>
    #include <asm/pgtable.h>
    #define __HYPERVISOR_create_sim 39
    
    char *hypercall_stubs;

    /* 下面两个define 可以参考文件asm/hypercall.h */

    #define _hypercall2(type, name, a1, a2) /
    ({ /
    type __res; /
    long __ign1, __ign2; /
    asm volatile ( /
    HYPERCALL_STR(name) /
    : "=a" (__res), "=D" (__ign1), "=S" (__ign2) /
    : "1" ((long)(a1)), "2" ((long)(a2)) /
    : "memory" ); /
    __res; /
    })

    #define HYPERCALL_STR(name) /
        "mov $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "/
        "add hypercall_stubs,%%eax; " /
        "call *%%eax"

    static int init_hypercall(void)
    {
        uint32_t eax, ebx, ecx, edx, pages, msr, i;
        char signature[13];
    
    /* 通过cpuid 指令获取当前操作系统的状态 */

    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
    *(uint32_t*)(signature + 0) = ebx;
    *(uint32_t*)(signature + 4) = ecx;
    *(uint32_t*)(signature + 8) = edx;
    signature[12] = 0;

    /* 判断是不是运行在Xen VMM 上 */
    if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
    printk(KERN_WARNING
        "Detected Xen platform device but not Xen VMM?"
    " (sig %s, eax %x)/n",signature, eax);
    return -EINVAL;
    }

    /* 获取xen 的版本号 */
    cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
    printk(KERN_INFO "Xen version %d.%d./n", eax >> 16, eax & 0xffff);
    
    /* 获取超级调用页的数目pages,( 一般情况下只有一页) 以及相应的寄存器值msr */
    cpuid(0x40000002, &pages, &msr, &ecx, &edx);
    printk(KERN_INFO"there are %u pages/n", pages);

    /* 分配超级调用页 */
    hypercall_stubs = __vmalloc(pages * PAGE_SIZE,GFP_KERNEL,
                        __pgprot(__PAGE_KERNEL & ~_PAGE_NX));

    if (hypercall_stubs == NULL)
        return -ENOMEM;


    /* 将超级调用页的物理页框号写到MSR 中 */
    for (i = 0; i < pages; i++) {
        unsigned long pfn;
        pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
        wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
    }

    printk(KERN_INFO "Hypercall area is %u pages./n", pages);
    _hypercall2(unsigned long, create_sim, 1,3);
    return 0;
    }
    module_init(init_hypercall);

    Make 文件如下:

    obj-m := sim.o
    all:
        make -C /lib/modules/`uname -r`/build M=`pwd` modules
    clean:
        make -C /lib/modules/`uname -r`/build M=`pwd` clean

    c. 编译,加载模块

    #make

    #insmod sim.ko

    切换到dom 0 中,利用xm dm 查看日志

    (XEN) creat the sim space using shadow page
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值