记录一段代码,从中可以很清晰的看出qemu-kvm的初始化以及虚拟机的运行过程。原文见参考资料链接,这里记录阅读过程中的一些批注和总结。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <pthread.h>
#include <sys/mman.h>
#include <linux/kvm.h>
#include <linux/errno.h>
#define KVM_API_VERSION 12
#define RAM_SIZE 128000000
#define VCPU_ID 0
#define DPRINTF(fmt, ...) \
do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
// accel/kvm/kvm-all.c KVMState
struct KVMState {
int fd;
int vmfd;
};
// include/sysemu/kvm_int.h KVMSlot
typedef struct KVMSlot
{
uint64_t start_addr;
uint64_t memory_size;
void *ram;
int slot;
int flags;
} KVMSlot;
// include/qom/cpu.h CPUState
// target/i386/cpu.h X86CPU
typedef struct CPUState {
int kvm_fd;
struct kvm_run *kvm_run;
} X86CPU;
struct KVMState *kvm_state;
// target/i386/kvm.c kvm_put_sregs
static int kvm_put_sregs(X86CPU *cpu) {
struct kvm_sregs sregs;
if (ioctl(cpu->kvm_fd, KVM_GET_SREGS, &sregs) < 0) {
fprintf(stderr, "KVM_GET_SREGS failed\n");
exit(1);
}
sregs.cs.base = 0x1000;
if (ioctl(cpu->kvm_fd, KVM_SET_SREGS, &sregs) < 0) {
fprintf(stderr, "KVM_SET_SREGS failed\n");
exit(1);
}
}
// target/i386/kvm.c kvm_getput_regs
static int kvm_getput_regs(X86CPU *cpu, int set) {
if(set) {
struct kvm_regs regs;
regs.rflags = 0x2;
if (ioctl(cpu->kvm_fd, KVM_SET_REGS, ®s) < 0) {
fprintf(stderr, "KVM_SET_REGS failed\n");
exit(1);
}
}
}
// target/i386/kvm.c kvm_arch_put_registers
int kvm_arch_put_registers(struct CPUState *cpu) {
int ret = 0;
kvm_put_sregs(cpu);
kvm_getput_regs(cpu, 1);
return ret;
}
/********************************************************************/
/*kvm-all*/
/********************************************************************/
// accel/kvm/kvm-all.c kvm_init_vcpu
int kvm_init_vcpu(struct CPUState *cpu) {
int ret = 0;
long mmap_size;
// ### 6. 创建vcpu,并为vCPU分配内存空间。
cpu->kvm_fd = ioctl(kvm_state->vmfd, KVM_CREATE_VCPU, VCPU_ID);
if (cpu->kvm_fd < 0) {
fprintf(stderr, "kvm_create_vcpu failed\n");
ret = -1;
goto err;
}
// ### 获取kvm为vCPU分配的内存空间
mmap_size = ioctl(kvm_state->fd, KVM_GET_VCPU_MMAP_SIZE, 0);
if (mmap_size < 0) {
ret = mmap_size;
fprintf(stderr, "KVM_GET_VCPU_MMAP_SIZE failed\n");
goto err;
}