题目是自己加的,因为膜拜了一篇介绍详细的技术贴,特转发。
原文地址:http://blog.csdn.net/sploving/article/details/5990507
在全虚拟化中,由于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