1、进入main函数之前,会先注册所有的类,以spice为例
//定义结构
static struct QemuSpiceOps real_spice_ops = {.init = qemu_spice_init,.display_init = qemu_spice_display_init,.migrate_info = qemu_spice_migrate_info,.set_passwd = qemu_spice_set_passwd,.set_pw_expire = qemu_spice_set_pw_expire,.display_add_client = qemu_spice_display_add_client,.add_interface = qemu_spice_add_interface,.qmp_query = qmp_query_spice_real,
};//添加参数
static void spice_register_config(void)
{qemu_spice = real_spice_ops;qemu_add_opts(&qemu_spice_opts);
}//注册spice_register_config
opts_init(spice_register_config);//宏替换
#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
#define xen_backend_init(function) module_init(function, MODULE_INIT_XEN_BACKEND)
#define libqos_init(function) module_init(function, MODULE_INIT_LIBQOS)
#define fuzz_target_init(function) module_init(function, MODULE_INIT_FUZZ_TARGET)
#define migration_init(function) module_init(function, MODULE_INIT_MIGRATION)//定义调用函数
#define module_init(function, type) \
static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
{ \register_dso_module_init(function, type); \
}
#else
/* This should not be used directly. Use block_init etc. instead. */
#define module_init(function, type) \
static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
{ \register_module_init(function, type); \
}
#endif//将函数和类型插入到相应类型的列表中
void register_module_init(void (*fn)(void), module_init_type type)
{ModuleEntry *e;ModuleTypeList *l;e = g_malloc0(sizeof(*e));e->init = fn;e->type = type;l = find_type(type);QTAILQ_INSERT_TAIL(l, e, node);
}//保存的列表
static ModuleTypeList init_type_list[MODULE_INIT_MAX];
static bool modules_init_done[MODULE_INIT_MAX];
2、main函数,定义在softmmu/main.c, main() -> qemu_main() -> qemu_init() ->qemu_init_subsystems() -> module_call_init(MODULE_INIT_QOM)。
int qemu_default_main(void)
{int status;status = qemu_main_loop();qemu_cleanup();return status;
}int (*qemu_main)(void) = qemu_default_main;
int main(int argc, char **argv)
{qemu_init(argc, argv);return qemu_main();
}
3、qemu初始化,定义在softmmu/vl.c
void qemu_init(int argc, char **argv)
{QemuOpts *opts;QemuOpts *icount_opts = NULL, *accel_opts = NULL;QemuOptsList *olist;int optind;const char *optarg;MachineClass *machine_class;bool userconfig = true;FILE *vmstate_dump_file = NULL;//添加参数列表qemu_add_opts(&qemu_drive_opts);qemu_add_drive_opts(&qemu_legacy_drive_opts);...module_call_init(MODULE_INIT_OPTS);error_init(argv[0]);qemu_init_exec_dir(argv[0]);//初始化CPU架构qemu_init_arch_modules();//初始化网络等qemu_init_subsystems();//第一次参数解析optind = 1;while (optind < argc) {if (argv[optind][0] != '-') {/* disk image */optind++;} else {const QEMUOption *popt;popt = lookup_opt(argc, argv, &optarg, &optind);switch (popt->index) {case QEMU_OPTION_nouserconfig:userconfig = false;break;}}}machine_opts_dict = qdict_new();if (userconfig) {qemu_read_default_config_file(&error_fatal);}//第二次参数解析optind = 1;for(;;) {if (optind >= argc)break;if (argv[optind][0] != '-') {loc_set_cmdline(argv, optind, 1);drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);} else {const QEMUOption *popt;popt = lookup_opt(argc, argv, &optarg, &optind);if (!(popt->arch_mask & arch_type)) {error_report("Option not supported for this target");exit(1);}switch(popt->index) {case QEMU_OPTION_cpu:/* hw initialization will check this */cpu_option = optarg;break;...}}}/** Clear error location left behind by the loop. Best done right after the loop. Do not insert code here!*/loc_set_none();qemu_validate_options(machine_opts_dict);qemu_process_sugar_options();/** These options affect everything else and should be processed before daemonizing.*/qemu_process_early_options();qemu_process_help_options();qemu_maybe_daemonize(pid_file);/** The trace backend must be initialized after daemonizing.* trace_init_backends() will call st_init(), which will create the* trace thread in the parent, and also register st_flush_trace_buffer()* in atexit(). This function will force the parent to wait for the* writeout thread to finish, which will not occur, and the parent* process will be left in the host.*/if (!trace_init_backends()) {exit(1);}trace_init_file();qemu_init_main_loop(&error_fatal);cpu_timers_init();user_register_global_props();replay_configure(icount_opts);configure_rtc(qemu_find_opts_singleton("rtc"));/* Transfer QemuOpts options into machine options */parse_memory_options();qemu_create_machine(machine_opts_dict);suspend_mux_open();//禁用默认设备qemu_disable_default_devices();//创建默认设备qemu_create_default_devices();//创建最近backendsqemu_create_early_backends();//应用遗留参数qemu_apply_legacy_machine_options(machine_opts_dict);//应用其他参数qemu_apply_machine_options(machine_opts_dict);//释放machine_opts_dictqobject_unref(machine_opts_dict);phase_advance(PHASE_MACHINE_CREATED);/** Note: uses machine properties such as kernel-irqchip, must run* after qemu_apply_machine_options.*/configure_accelerators(argv[0]);phase_advance(PHASE_ACCEL_CREATED);/** Beware, QOM objects created before this point miss global and* compat properties.** Global properties get set up by qdev_prop_register_global(),* called from user_register_global_props(), and certain option* desugaring. Also in CPU feature desugaring (buried in* parse_cpu_option()), which happens below this point, but may* only target the CPU type, which can only be created after* parse_cpu_option() returned the type.** Machine compat properties: object_set_machine_compat_props().* Accelerator compat props: object_set_accelerator_compat_props(),* called from do_configure_accelerator().*/machine_class = MACHINE_GET_CLASS(current_machine);if (!qtest_enabled() && machine_class->deprecation_reason) {warn_report("Machine type '%s' is deprecated: %s",machine_class->name, machine_class->deprecation_reason);}/** Note: creates a QOM object, must run only after global and compat properties have been set up.*/migration_object_init();qemu_create_late_backends();/* parse features once if machine provides default cpu_type */current_machine->cpu_type = machine_class->default_cpu_type;if (cpu_option) {current_machine->cpu_type = parse_cpu_option(cpu_option);}/* NB: for machine none cpu_type could STILL be NULL here! */qemu_resolve_machine_memdev();parse_numa_opts(current_machine);if (vmstate_dump_file) {/* dump and exit */module_load_qom_all();dump_vmstate_json_to_file(vmstate_dump_file);exit(0);}if (!preconfig_requested) {qmp_x_exit_preconfig(&error_fatal);}//显示系统初始化,包括VNC和spiceqemu_init_displays();accel_setup_post(current_machine);os_setup_post();resume_mux_open();
}
4、qemu事件循环
int qemu_main_loop(void)
{int status = EXIT_SUCCESS;
#ifdef CONFIG_PROFILERint64_t ti;
#endifwhile (!main_loop_should_exit(&status)) {
#ifdef CONFIG_PROFILERti = profile_getclock();
#endifmain_loop_wait(false);
#ifdef CONFIG_PROFILERdev_time += profile_getclock() - ti;
#endif}return status;
}