ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机

2020-02-03 14:39:55王振洲

为了实现一个虚拟机,我们首先需要打开/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,