はじめに

いわゆるVM床抜きをXenで試す.

Xenのインストール

いつかインストールしたXen 4.4.1を用いた.

  • 依存パッケージ

    1
    # sudo apt-get install wget git bcc bin86 gawk bridge-utils iproute libcurl3 libcurl4-openssl-dev bzip2 module-init-tools pciutils-dev build-essential make gcc libc6-dev libc6-dev-i386 linux-libc-dev zlib1g-dev python python-dev python-twisted python-gevent libncurses5-dev patch libvncserver-dev libssl-dev libsdl-dev iasl libbz2-dev e2fslibs-dev git-core uuid-dev ocaml libx11-dev bison flex ocaml-findlib xz-utils gettext libyajl-dev libpixman-1-dev libaio-dev libfdt-dev cabextract libglib2.0-dev autoconf automake libtool check libjansson-dev libfuse-dev
  • Xenのビルド

    1
    2
    3
    4
    5
    6
    7
    # wget http://bits.xensource.com/oss-xen/release/4.4.1/xen-4.4.1.tar.gz
    # tar xzvf xen-4.4.1.tar.gz
    # cd ./xen-4.4.1
    # export C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
    # ./configure --enable-systemd --enable-githttp
    # make -j4 dist-xen
    # make -j4 dist-tools
  • DomUの設定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # sudo su
    # make -j4 install-xen
    # make -j4 install-tools
    # echo "GRUB_CMDLINE_XEN_DEFAULT=\"dom0_mem=4096M,max:4096M dom0_max_vcpus=4 dom0_vcpus_pin=true hap_1gb=false hap_2mb=false\"" >> /etc/default/grub
    # echo "/usr/local/lib" > /etc/ld.so.conf.d/xen.conf
    # ldconfig
    # update-grub
    # echo "none /proc/xen xenfs defaults,nofail 0 0" >> /etc/fstab
    # echo "xen-evtchn" >> /etc/modules
    # echo "xen-privcmd" >> /etc/modules
    # update-rc.d xencommons defaults 19 18
    # update-rc.d xendomains defaults 21 20
    # update-rc.d xen-watchdog defaults 22 23
    # reboot
  • 動作確認

    1
    2
    # sudo xen-detect
    Running in PV context on Xen v4.4.

ハイパーコールの追加

予約済みの__HYPERVISOR_xc_reserved_opに代わって39番目のハイパーコールを定義する.

  • xen-4.4.1/xen/include/public/xen.h

    1
    2
    3
    4
    5
    6
    7
    8
    @@ -100,6 +100,7 @@
    #define __HYPERVISOR_domctl 36
    #define __HYPERVISOR_kexec_op 37
    #define __HYPERVISOR_tmem_op 38
    +#define __HYPERVISOR_rdtsc_hypercall 39
    #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
    /* Architecture-specific hypercall definitions. */
  • xen-4.4.1/xen/arch/x86/x86_64/entry.S

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @@ -757,6 +757,7 @@
    .quad do_domctl
    .quad do_kexec_op
    .quad do_tmem_op
    + .quad do_rdtsc_hypercall
    .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
    .quad do_ni_hypercall
    .endr
    @@ -805,6 +806,7 @@
    .byte 1 /* do_domctl */
    .byte 2 /* do_kexec */
    .byte 1 /* do_tmem_op */
    + .byte 1 /* do_rdtsc_hypercall */
    .rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
    .byte 0 /* do_ni_hypercall */
    .endr
  • xen-4.4.1/xen/include/asm-x86/hypercall.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @@ -110,4 +110,8 @@
    arch_compat_vcpu_op(
    int cmd, struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg);
    +extern int
    +do_rdtsc_hypercall(
    + char* str);
    +
    #endif /* __ASM_X86_HYPERCALL_H__ */
  • xen-4.4.1/xen/arch/x86/traps.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @@ -3762,6 +3762,14 @@
    __domain_crash_synchronous();
    }
    +int do_rdtsc_hypercall(char* str)
    +{
    + unsigned long long tsc;
    + __asm__ volatile("rdtsc" : "=A" (tsc));
    + printk("str: %s, tsc: %llu\n", str, tsc);
    + return 0;
    +}
    +
    /*
    * Local variables:
    * mode: C

このハイパーコールは引数として受け取った文字列をTSCの値とともにコンソールログに出力する.有効化するには再度make -j4 dist-xenして再起動するとよい.

ハイパーコールの呼び出し

ハイパーコールの呼び出しはlibxcやlibxlによって抽象化されているが,ここではそれらが内部で参照している/proc/xen/privcmdに対してioctlを発行してみる.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// rdtsc_hypercall.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <fcntl.h>
#include <string.h>
#include <xenctrl.h>
#include <xen/sys/privcmd.h>
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("input the param");
exit(1);
}
char *message = malloc(sizeof(char)*(strlen(argv[1])+1));
strcpy(message, argv[1]);
privcmd_hypercall_t my_hypercall = {
39, // __HYPERVISOR_rdtsc_hypercall
{(__u64)message, 0, 0, 0, 0}
};
int fd = open("/proc/xen/privcmd", O_RDWR);
if(fd < 0)
{
printf("cannot open /proc/xen/privcmd");
exit(1);
}
if(!ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, &my_hypercall))
{
printf("cannot call do_rdtsc_hypercall");
exit(1);
}
return 0;
}

このプログラムを実行するとハイパーコールが呼び出されたことが分かる.

1
2
3
4
# gcc -o rdtsc_hypercall rdtsc_hypercall.c
# sudo ./rdtsc_hypercall test
# sudo xl dmesg | less
(XEN) str: test, tsc: 2835883086

おわりに

Xenに追加したハイパーコールを呼び出すことができた.
さしあたってはMirage OSからこのハイパーコールを呼び出す方法を知りたいのだが.

参考文献