if (machine_class->hw_version) {
qemu_set_version(machine_class->hw_version);
}
cpudef_init
初始化支持的cpu feature,可以通过如下命令查询当前qemu支持的cpu feature/usr/bin/qemu-system-x86_64 -cpu help
if (cpu_model && is_help_option(cpu_model)) {
list_cpus(stdout, &fprintf, cpu_model);
exit(0);
}
data_dir_idx 遗留 怀疑是bios文件路径
smp_parse(qemu_opts_find(qemu_find_opts("smp-opts"), NULL));
machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */#未配置cpu情况下 默认配置一个
#校验参数合法性
if (smp_cpus > machine_class->max_cpus) {
fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
"supported by machine `%s' (%d)\n", smp_cpus,
machine_class->name, machine_class->max_cpus);
exit(1);
}
if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
exit(1);
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0)
!= 0) {
exit(0);
}
machine_opts = qemu_get_machine_opts();
if (qemu_opt_foreach(machine_opts, object_set_property, current_machine,
1) < 0) {
object_unref(OBJECT(current_machine));
exit(1);
}
configure_accelerator
。这里的作用其实就是配置一些qemu与hypervisor层的交互接口。qemu通过一些句柄以ioctl的方式与kmod交互,完成虚拟化相关的操作。在qemu中维护的句柄包括:在qemu中维护了一个结构体数组,用于记录各种虚拟化方案下的加速器初始化入口:
accel_list[] = {
{ "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
{ "xen", "Xen", xen_available, xen_init, &xen_allowed },
{ "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
{ "qtest", "QTest", qtest_available, qtest_init, &qtest_allowed },
};
kvm_init
作为初始化入口。ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
s->nr_slots = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
int ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
ret = kvm_ioctl(s, KVM_CREATE_VM, type);
linux kernel
static long kvm_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
static int kvm_dev_ioctl_create_vm(unsigned long type)
kvm = kvm_create_vm(type);
missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
在kvm_arch_init
中初始化硬件架构相关的一些特性,比如e820表,中断路由表等
检查kvm是否支持MSR(model specific register,用于标识cpu的工作环境和工作状态),通常为一组寄存器,分别表示不同的标志位。其中一些要求必须存在,否则无法正常启动。
ret = kvm_ioctl(s, KVM_GET_MSR_INDEX_LIST, &msr_list);
初始化e820 entry,以及e820 table。(e820表用于维护机器的物理内存布局)
创建中断管理单元kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
通过vmfd在kmod中创建一个虚拟pic
初始化中断路由表(irqrouting 中断路由,与中断亲和性等相关。kvm通过该表可以知道将某一个中断路由到哪一个具体的vcpu上处理)
machine_opts = qemu_get_machine_opts();
kernel_filename = qemu_opt_get(machine_opts, "kernel");
initrd_filename = qemu_opt_get(machine_opts, "initrd");
kernel_cmdline = qemu_opt_get(machine_opts, "append");
bios_name = qemu_opt_get(machine_opts, "firmware");
os_set_line_buffering
qemu_init_cpu_loop
int net_init_clients(void)
net_init_netdev
net_client_init1
net_init_tap
net_init_tap_one
后端tap设备初始化
(vhost即虚拟机网卡IO数据通过一个内核线程在内核中直接处理而不需要经过qemu)
vhost设备初始化--与内核交互,拉起vhost内核线程。
On 32-bit hosts, QEMU is limited by virtual address space
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
&machine_class->block_default_type, 1) != 0) {
exit(1);
}
-drive file=rbd:switch01_sas_vms/493c6d20-3329-480f-ad6e-391d9e997f52_disk.config:auth_supported=none:mon_host=10.180.0.32\:6789\;10.180.0.49\:6789\;10.180.0.161\:6789,format=raw,if=none,id=drive-virtio-disk25,readonly=on,cache=none
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x7,drive=drive-virtio-disk25,id=virtio-disk25
if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) {
exit(1);
}
25.初始化主板(VCPUbios北桥内存南桥,外围设备,中断等初始化)
current_machine->ram_size = ram_size;
current_machine->maxram_size = maxram_size;
current_machine->ram_slots = ram_slots;
current_machine->boot_order = boot_order;
current_machine->cpu_model = cpu_model;
machine_class->init(current_machine);
pc_init1
pc_cpus_init 创建vcpu线程
pc_memory_init 创建虚拟机内存
kvm_pc_setup_irq_routing 创建中断路由表
i440fx_init 初始化北桥
kvm_i8259_init 初始化中断控制器
pc_vga_init 初始化显卡设备
pc_basic_device_init 初始化基础设备(一些默认的设备,如IDE总线,ISA总线,USB总线等)
pc_cmos_init 初始化bios
qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1)
int rom_load_all(void)
main_loop
中。main_loop
是一个死循环,通过内核的epoll机制监听上面创建的所有fd,包括设备,vcpu等。虚拟机内部所有对设备的读写/对vcpu的操作都会触发句柄改变状态并被main_loop循环监听到,分发给注册好的回调函数处理这些事件。处理完成之后继续进入wait状态等待下一次触发。以上就是qemu进程启动的主要流程,接下来启动虚拟机操作系统的流程为:
main_loop
中捕获qemu monitor句柄事件相关阅读:虚拟机创建流程-qemu篇(上)
本文来自网易实践者社区,经作者岳文远授权发布。