読者です 読者をやめる 読者になる 読者になる

はわわーっ

はわわわわっ

xenのハイパーコールを呼んでみる

linuxカーネルモジュールからxenのハイパーコールを呼んでみる。
とりあえず、実行中のドメインの情報をとってみる。

#include <linux/module.h>
#include <asm/xen/hypercall.h>

MODULE_LICENSE("GPL");

typedef uint8_t xen_domain_handle_t[16];
struct xen_domctl_getdomaininfo {
        domid_t domain;
        uint32_t flags;
        uint64_t tot_pages;
        uint64_t max_pages;
        uint64_t outstanding_pages;
        uint64_t shr_pages;
        uint64_t paged_pages;
        uint64_t shared_info_frame;
        uint64_t cpu_time;
        uint32_t nr_online_vcpus;
        uint32_t max_vcpu_id;
        uint32_t ssidref;
        xen_domain_handle_t handle;
        uint32_t cpupool;
};
typedef struct xen_domctl_getdomaininfo xen_domctl_getdomaininfo_t;
DEFINE_GUEST_HANDLE(xen_domctl_getdomaininfo_t);

struct xen_sysctl_getdomaininfolist {
        domid_t first_domain;
        uint32_t max_domains;
        struct {
                xen_domctl_getdomaininfo_t *p;
        } buffer;
        uint32_t num_domains;
};
typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t;
DEFINE_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t);

#define XEN_SYSCTL_getdomaininfolist 6
#define XEN_SYSCTL_INTERFACE_VERSION 0x0000000A
struct xen_sysctl {
        uint32_t cmd;
        uint32_t interface_version;
        union {
                struct xen_sysctl_getdomaininfolist getdomaininfolist;
                uint8_t pad[128];
        } u;
};
typedef struct xen_sysctl xen_sysctl_t;
DEFINE_GUEST_HANDLE(xen_sysctl_t);

#define __HYPERVISOR_sysctl 35
static long get_dominfolist(void)
{
        long ret = 0;
        xen_sysctl_t sysctl;
        xen_domctl_getdomaininfo_t info[5];
        int i;

        sysctl.cmd = XEN_SYSCTL_getdomaininfolist;
        sysctl.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
        sysctl.u.getdomaininfolist.first_domain = 0;
        sysctl.u.getdomaininfolist.max_domains = 5;
        sysctl.u.getdomaininfolist.buffer.p = info;

        ret = _hypercall1(long, sysctl, &sysctl);
        if (ret)
                printk(KERN_EMERG "===== HYPERVISOR_sysctl failed. ret=%ld\n", ret);

        printk(KERN_EMERG "num=%u\n", sysctl.u.getdomaininfolist.num_domains);
        for (i = 0; i < sysctl.u.getdomaininfolist.num_domains; i++)
                printk(KERN_EMERG "===== domid=%u flag=%x cpu=%u\n", info[i].domain, info[i].flags, info[i].nr_online_vcpus);

        return ret;
}

static int __init dominfo_init(void)
{
        long ret;

        printk(KERN_EMERG "===== dominfo init.\n");

        ret = get_dominfolist();
        return 0;
}

static void __exit dominfo_exit(void)
{
        printk(KERN_EMERG "===== dominfo exit.\n");
}

module_init(dominfo_init);
module_exit(dominfo_exit);

最初の構造体とかマクロ定義とかはxenのコードにあったのをそのまま持ってきた。

hvm_opとかはHYPERVISOR_hvm_opとかいう関数があってそれをそのまま使えばよさそう。
sysctlはそれらしいのがなかったので_hypercall1を使った。

実行結果。

$ sudo insmod dominfo.ko
$ sudo rmmod dominfo.ko
$ dmesg | tail
...
[ 1337.239688] ===== dominfo init.
[ 1337.240255] num=2
[ 1337.240436] ===== domid=0 flag=ffff0020 cpu=4
[ 1337.240827] ===== domid=1 flag=ffff0012 cpu=2
[ 1342.504445] ===== dominfo exit.
$ sudo xl list
Name                                        ID   Mem VCPUs      State   Time(s)
Domain-0                                     0 14477     4     r-----      25.3
u01                                          1  1023     2     -b----       5.4

動いてるっぽい。