为了实现一个虚拟机,我们首先需要打开/dev/kvm:
kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
在使用kvm之前,需要使用KVM_GET_API_VERSION ioctl()去检查下kvm的版本是否正确,看看是否为api12,是才可以继续运行
ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);
if (ret == -1)
err(1, "KVM_GET_API_VERSION");
if (ret != 12)
errx(1, "KVM_GET_API_VERSION %d, expected 12", ret);
检查完api版本后,可以使用KVM_CHECK_EXTENSION ioctl()去检查其它extensions是否可用,比如KVM_SET_USER_MEMORY_REGION,用来检查kvm是否支持硬件影子页表(http://royluo.org/2016/03/13/kvm-mmu-virtualization/):
ret = ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
if (ret == -1)
err(1, "KVM_CHECK_EXTENSION");
if (!ret)
errx(1, "Required extension KVM_CAP_USER_MEM not available");
然后再创建一个虚拟机vm,这个vm和内存,设备,所有的vCPU相关,在host系统中对应一个进程:
vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0);
虚拟机需要一些虚拟物理内存,用来存放guest os。当guest os进行内存访问时,如果缺页,kvm会根据KVM_SET_USER_MEMORY_REGION的设置,去尝试解决缺页的问题,如果kvm无法解决,就会退出,退出原因是KVM_EXIT_MMIO,然后由qemu或者其它东西去进行设备的模拟(《android qemu-kvm内存管理和IO映射》)。
我们先在host中申请一页内存,然后把guest os裸奔的代码拷贝过去:
mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
memcpy(mem, code, sizeof(code));
然后我们需要把host 虚拟空间的内存和guest os虚拟物理内存的映射关系使用KVM_SET_USER_MEMORY_REGION ioctl()告知kvm:
struct kvm_userspace_memory_region region = {
.slot = 0,










