Friday, February 7, 2020
kvm_all.c - kvm_init, kvm_init_vcpu
继续接着前面的东西来,了解QEMU如何在KVM虚拟化环境中创建和初始化虚拟机和vCPU。
1. kvm_init
kvm_init函数用于打开KVM设备文件,如下所示,它还填充KVMState的fd和vmfd:
static int kvm_init(MachineState *ms) { …… KVMState *s; …… s = KVM_STATE(ms->accelerator); …… s->vmfd = -1; s->fd = qemu_open("/dev/kvm", O_RDWR); if (s->fd == -1) { fprintf(stderr, "Could not access KVM kernel module: %mn"); ret = -errno; goto err; } …… do { ret = kvm_ioctl(s, KVM_CREATE_VM, type); } while (ret == -EINTR); if (ret < 0) { fprintf(stderr, "ioctl(KVM_CREATE_VM) failed: %d %sn", -ret, strerror(-ret)); goto err; } s->vmfd = ret; …… ret = kvm_arch_init(ms, s); if (ret < 0) { goto err; } …… return ret; }
如上所示,带有KVM_CREATE_VM参数的ioctl将返回vmfd。一旦QEMU有了fd和vmfd,就必须再填充一个文件描述符,即kvm_fd或vcpu fd。
2. kvm_init_vcpu
int kvm_init_vcpu(CPUState *cpu) { …… KVMState *s = kvm_state; int ret; …… ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu)); if (ret < 0) { goto err; } cpu->kvm_fd = ret; cpu->kvm_state = s; …… ret = kvm_arch_init_vcpu(cpu); err: return ret; }
一些内存页在qemu-kvm进程和KVM内核模块之间共享。你可以在kvm_init_vcpu()函数中看到这样的映射。也就是说,每个vCPU的两个主机内存页为QEMU用户空间进程和KVM内核模块之间的通信提供了通道:kvm_run和pio_data。
还要理解,在执行这些返回前面fd的ioctl期间,Linux内核会分配一个文件结构和相关的匿名节点。
vCPU是QEMU-KVM创建的线程,要运行来自guest代码,这些vCPU线程需要使用KVM_RUN作为参数执行ioctl,即第一篇文章(http://www.qemu.world/?x=entry:entry200206-201418)的:
run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);