qemu启动过程笔记

文章详细描述了QEMU内核中如何在main函数执行前进行类的注册,如Spice操作,以及如何初始化配置、处理参数和事件循环。重点介绍了`qemu_register_config`、`spice_register_config`和模块初始化机制的过程。
摘要由CSDN通过智能技术生成
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();

    //创建最近backends
    qemu_create_early_backends();

    //应用遗留参数
    qemu_apply_legacy_machine_options(machine_opts_dict);

    //应用其他参数
    qemu_apply_machine_options(machine_opts_dict);

    //释放machine_opts_dict
    qobject_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和spice
    qemu_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_PROFILER
    int64_t ti;
#endif
    while (!main_loop_should_exit(&status)) {
#ifdef CONFIG_PROFILER
        ti = profile_getclock();
#endif
        main_loop_wait(false);
#ifdef CONFIG_PROFILER
        dev_time += profile_getclock() - ti;
#endif
    }
    return status;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值