系列文章目录
第十一章 QEMU系统仿真的机器创建分析实例
文章目录
- 系列文章目录
- 第十一章 QEMU系统仿真的机器创建分析实例
- 前言
- 一、QEMU是什么?
- 二、QEMU系统仿真的机器创建分析实例
- 1.系统仿真的命令行参数
- 2.完成默认设备的设置工作
- qemu_create_default_devices()
- 总结
前言
本文以 QEMU 8.2.2 为例,分析其作为系统仿真工具的工作过程,并为读者展示各种 QEMU 系统仿真的启动配置实例。
本文读者需要具备一定的 QEMU 系统仿真使用经验,并对 C 语言编程有一定了解。
一、QEMU是什么?
QEMU 是一个通用且开源的机器模拟器和虚拟机。
其官方主页是:https://www.qemu.org/
二、QEMU系统仿真的机器创建分析实例
1.系统仿真的命令行参数
QEMU 作为系统仿真工具,其入口代码在 system/main.c 文件中,初始化函数 qemu_init() 的实现在 system/vl.c 文件中。
前文完成创建目标机器的过程分析,本文将继续后续运行过程的分析,读者需要对 QEMU 系统启动过程的程序代码有所了解,相关内容可以参考《QEMU系统分析之启动篇》系列文章。
..\qemu\8.2.2-qkd\qemu-system-x86_64.exe -cpu "Penryn" -M "q35,accel=whpx" -m "6G" -nodefaults
2.完成默认设备的设置工作
这部分代码在 system/vl.c 文件中,实现如下:
int qemu_init(int argc, char **argv)
{
...
qemu_disable_default_devices();
qemu_setup_display();
qemu_create_default_devices();
...
}
前文分析了创建显示设备的过程,本文将分析创建默认设备的过程。
qemu_create_default_devices()
完成显示设备的设置后,系统将创建默认设备,包括默认监视器、串口、并口以及网卡设备,代码如下:
static void qemu_create_default_devices(void)
{
MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
const char *vc = qemu_display_get_vc(&dpy);
if (is_daemonized()) {
/* According to documentation and historically, -nographic redirects
* serial port, parallel port and monitor to stdio, which does not work
* with -daemonize. We can redirect these to null instead, but since
* -nographic is legacy, let's just error out.
* We disallow -nographic only if all other ports are not redirected
* explicitly, to not break existing legacy setups which uses
* -nographic _and_ redirects all ports explicitly - this is valid
* usage, -nographic is just a no-op in this case.
*/
if (nographic
&& (default_parallel || default_serial || default_monitor)) {
error_report("-nographic cannot be used with -daemonize");
exit(1);
}
}
if (nographic) {
if (default_parallel) {
add_device_config(DEV_PARALLEL, "null");
}
if (default_serial && default_monitor) {
add_device_config(DEV_SERIAL, "mon:stdio");
} else {
if (default_serial) {
add_device_config(DEV_SERIAL, "stdio");
}
if (default_monitor) {
monitor_parse("stdio", "readline", false);
}
}
} else {
if (default_serial) {
add_device_config(DEV_SERIAL, vc ?: "null");
}
if (default_parallel) {
add_device_config(DEV_PARALLEL, vc ?: "null");
}
if (default_monitor && vc) {
monitor_parse(vc, "readline", false);
}
}
if (default_net) {
QemuOptsList *net = qemu_find_opts("net");
qemu_opts_parse(net, "nic", true, &error_abort);
#ifdef CONFIG_SLIRP
qemu_opts_parse(net, "user", true, &error_abort);
#endif
}
/* If no default VGA is requested, the default is "none". */
if (default_vga) {
vga_model = get_default_vga_model(machine_class);
}
if (vga_model) {
select_vgahw(machine_class, vga_model);
}
}
此操作首先获取虚拟控制台设备的设置,然后根据命令行参数完成默认监视器、并口、串口和虚拟控制台的搭配,再获取默认网卡设置,最后配置 VGA 模型。我们添加跟踪调试代码,最终代码如下:
void qemu_display_early_init(DisplayOptions *opts)
{
assert(opts->type < DISPLAY_TYPE__MAX);
if (opts->type == DISPLAY_TYPE_NONE) {
return;
}
if (dpys[opts->type] == NULL) {
Error *local_err = NULL;
int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
if (rv < 0) {
error_report_err(local_err);
}
}
if (dpys[opts->type] == NULL) {
error_report("Display '%s' is not available.",
DisplayType_str(opts->type));
exit(1);
}
HUEDBG("\n");
huedbg_dump_DisplayType(1);
HUEDBG("\n");
huedbg_dump_QemuDisplay(dpys[opts->type], 3);
HUEDBG("\n");
if (dpys[opts->type]->early_init) {
dpys[opts->type]->early_init(opts);
}
}
...
static void qemu_setup_display(void)
{
if (dpy.type == DISPLAY_TYPE_DEFAULT && !display_remote) {
if (!qemu_display_find_default(&dpy)) {
dpy.type = DISPLAY_TYPE_NONE;
#if defined(CONFIG_VNC)
vnc_parse("localhost:0,to=99,id=default");
display_remote++;
#endif
}
}
if (dpy.type == DISPLAY_TYPE_DEFAULT) {
dpy.type = DISPLAY_TYPE_NONE;
}
huedbg_dump_DisplayOptions(&dpy, 3);
qemu_display_early_init(&dpy);
}
调试输出如下:
[4464]../system/vl.c/qemu_init(3799):
[4464]../system/vl.c/qemu_create_default_devices(1399):vc=vc:80Cx24C
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(238):<<<deep>>>=[1]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(240):type=[2]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(241):has_full_screen=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(242):full_screen=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(243):has_window_close=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(244):window_close=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(245):has_show_cursor=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(246):show_cursor=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(247):has_gl=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(248):gl=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(272):u.egl_headless=[00007ff763fdefe0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayEGLHeadless(156):<<<deep>>>=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayEGLHeadless(158):rendernode=[(null)]
[4464]../util/huedbg-display.c/huedbg_dump_DisplayOptions(286):u.sdl=[00007ff763fdefe0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplaySDL(195):<<<deep>>>=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplaySDL(197):has_grab_mod=[0]
[4464]../util/huedbg-display.c/huedbg_dump_DisplaySDL(198):grab_mod=[0]
[4464]../system/vl.c/qemu_create_default_devices(1457):vga_model=std
[4464]../qom/object.c/object_class_by_name(1095):enter
[4464]../qom/object.c/type_table_lookup(103):lookup type(VGA) in hash table
[4464]../qom/object.c/object_class_by_name(1105):class(VGA) return
[4464]../system/vl.c/qemu_init(3801):
根据调试的输出信息可知:
1、虚拟控制台设备为 ”vc:80Cx24C“
[4464]../system/vl.c/qemu_create_default_devices(1399):vc=vc:80Cx24C
总结
以上分析了系统初始化过程中创建默认设备的过程。