開發(fā)網(wǎng)站需要用到的專業(yè)技術(shù)知識地推的方法和技巧
接前一篇文章:QEMU源碼全解析33 —— Machine(3)
本文內(nèi)容參考:
《趣談Linux操作系統(tǒng)》 —— 劉超,極客時間
《QEMU/KVM》源碼解析與應(yīng)用 —— 李強(qiáng),機(jī)械工業(yè)出版社
特此致謝!
上一回圍繞DEFINE_I440FX_MACHINE宏進(jìn)行了詳細(xì)解析,本回講一下QEMU初始化中與有machine關(guān)的部分。
在QEMU老版本中,主函數(shù)main中會調(diào)用select_machine函數(shù),新版本中放到了main() -> qemu_main() ->?qemu_init() ->?qemu_create_machine ->?select_machine()。
我們從qemu_create_machine函數(shù)開始看起。qemu_create_machine函數(shù)在softmmu/vl.c中,代碼如下:
static void qemu_create_machine(QDict *qdict)
{MachineClass *machine_class = select_machine(qdict, &error_fatal);object_set_machine_compat_props(machine_class->compat_props);current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));object_property_add_child(object_get_root(), "machine",OBJECT(current_machine));object_property_add_child(container_get(OBJECT(current_machine),"/unattached"),"sysbus", OBJECT(sysbus_get_default()));if (machine_class->minimum_page_bits) {if (!set_preferred_target_page_bits(machine_class->minimum_page_bits)) {/* This would be a board error: specifying a minimum smaller than* a target's compile-time fixed setting.*/g_assert_not_reached();}}cpu_exec_init_all();page_size_init();if (machine_class->hw_version) {qemu_set_hw_version(machine_class->hw_version);}/** Get the default machine options from the machine if it is not already* specified either by the configuration file or by the command line.*/if (machine_class->default_machine_opts) {QDict *default_opts =keyval_parse(machine_class->default_machine_opts, NULL, NULL,&error_abort);qemu_apply_legacy_machine_options(default_opts);object_set_properties_from_keyval(OBJECT(current_machine), default_opts,false, &error_abort);qobject_unref(default_opts);}
}static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
{GlobalProperty *g;g = g_malloc0(sizeof(*g));g->driver = qemu_opt_get(opts, "driver");g->property = qemu_opt_get(opts, "property");g->value = qemu_opt_get(opts, "value");qdev_prop_register_global(g);return 0;
}
其中第1行代碼就是select_machine函數(shù),代碼片段如下:
MachineClass *machine_class = select_machine(qdict, &error_fatal);
顧名思義,select_machine函數(shù)的作用是選擇一個MachineClass,其可能由用戶指定,如果用戶未指定,則采用系統(tǒng)默認(rèn)。如果是后者,QEMU最新版本號對應(yīng)的機(jī)器類型為默認(rèn)設(shè)置。由于筆者的源碼為qemu-7.1.0,因此默認(rèn)機(jī)器類型是pc-i440fx-7.1-machine。
select_machine函數(shù)同樣在softmmu/vl.c中,代碼如下:
static MachineClass *select_machine(QDict *qdict, Error **errp)
{const char *optarg = qdict_get_try_str(qdict, "type");GSList *machines = object_class_get_list(TYPE_MACHINE, false);MachineClass *machine_class;Error *local_err = NULL;if (optarg) {machine_class = find_machine(optarg, machines);qdict_del(qdict, "type");if (!machine_class) {error_setg(&local_err, "unsupported machine type");}} else {machine_class = find_default_machine(machines);if (!machine_class) {error_setg(&local_err, "No machine specified, and there is no default");}}g_slist_free(machines);if (local_err) {error_append_hint(&local_err, "Use -machine help to list supported machines\n");error_propagate(errp, local_err);}return machine_class;
}
如上面所講,在select_machine函數(shù)中,有兩種方式可以生成MachineClass:一種方式是調(diào)用find_machine函數(shù),通過解析QEMU命令行參數(shù)生成MachineClass,即用戶指定方式;另一種方式是通過find_default_machine函數(shù)找一個默認(rèn)的MachineClass,即系統(tǒng)默認(rèn)方式。后文會分別解析這兩種方式的兩個函數(shù)。
在此之前,有一個函數(shù)值得先深入研究:object_class_get_list。無論是用戶指定還是系統(tǒng)默認(rèn)方式,都得先調(diào)用object_class_get_list函數(shù)獲得一個MachineClass列表,然后在里邊找。代碼片段如下:
GSList *machines = object_class_get_list(TYPE_MACHINE, false);
object_class_get_list函數(shù)在qom/object.c中,代碼如下:
GSList *object_class_get_list(const char *implements_type,bool include_abstract)
{GSList *list = NULL;object_class_foreach(object_class_get_list_tramp,implements_type, include_abstract, &list);return list;
}
object_class_foreach函數(shù)在同文件中,代碼如下:
void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),const char *implements_type, bool include_abstract,void *opaque)
{OCFData data = { fn, implements_type, include_abstract, opaque };enumerating_types = true;g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);enumerating_types = false;
}
從object_class_foreach函數(shù)的參數(shù)中可以看出,第1個參數(shù)是一個函數(shù)指針,指向了傳入的實(shí)參object_class_get_list_tramp。
現(xiàn)在有4個函數(shù)需要弄清楚:(1)object_class_get_list_tramp;(2)object_foreach_tramp;(3)type_table_get;(4)g_hash_table_foreach。
對于這4個函數(shù)的解析,請看下回。