【QEMU系统分析之实例篇(十四)】

2024-05-05 08:44

本文主要是介绍【QEMU系统分析之实例篇(十四)】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

系列文章目录

第十四章 QEMU系统仿真的机器创建分析实例


文章目录

  • 系列文章目录
    • 第十四章 QEMU系统仿真的机器创建分析实例
  • 前言
  • 一、QEMU是什么?
  • 二、QEMU系统仿真的机器创建分析实例
    • 1.系统仿真的命令行参数
    • 2.完成早期后端驱动的设置工作
      • qemu_create_early_backends()
        • configure_blockdev();
        • audio_init_audiodevs()
        • audio_create_default_audiodevs()
    • 3.调试输出
  • 总结


前言

本文以 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,smm=off" -m "6G" -display "sdl" -audio "sdl,model=hda" -vga "std" -L "data"

2.完成早期后端驱动的设置工作

这部分代码在 system/vl.c 文件中,实现如下:

int qemu_init(int argc, char **argv)
{
...qemu_create_early_backends();
...
}

前文分析了创建后端驱动过程中控制台和字符设备的创建过程,本文继续完成块设备和音频设备驱动的创建过程。


qemu_create_early_backends()

函数 qemu_create_early_backends() 代码如下:

static void qemu_create_early_backends(void)
{
.../** Note: we need to create audio and block backends before* setting machine properties, so they can be referred to.*/configure_blockdev(&bdo_queue, machine_class, snapshot);audio_init_audiodevs();if (default_audio) {audio_create_default_audiodevs();}
}

首先我们对块设备后端驱动进行配置。


configure_blockdev();

代码如下:

static void configure_blockdev(BlockdevOptionsQueue *bdo_queue,MachineClass *machine_class, int snapshot)
{/** If the currently selected machine wishes to override the* units-per-bus property of its default HBA interface type, do so* now.*/if (machine_class->units_per_default_bus) {override_max_devs(machine_class->block_default_type,machine_class->units_per_default_bus);}/* open the virtual block devices */while (!QSIMPLEQ_EMPTY(bdo_queue)) {BlockdevOptionsQueueEntry *bdo = QSIMPLEQ_FIRST(bdo_queue);QSIMPLEQ_REMOVE_HEAD(bdo_queue, entry);loc_push_restore(&bdo->loc);qmp_blockdev_add(bdo->bdo, &error_fatal);loc_pop(&bdo->loc);qapi_free_BlockdevOptions(bdo->bdo);g_free(bdo);}if (snapshot) {qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,NULL, NULL);}if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,&machine_class->block_default_type, &error_fatal)) {/* We printed help */exit(0);}default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2,CDROM_OPTS);default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);}

audio_init_audiodevs()

代码如下:

void audio_init_audiodevs(void)
{AudiodevListEntry *e;QSIMPLEQ_FOREACH(e, &audiodevs, next) {audio_init(e->dev, &error_fatal);}
}

对 audiodevs 中的每个音频设备调用函数 audio_init() 完成初始化。

函数 audio_init() 代码如下:

/** if we have dev, this function was called because of an -audiodev argument =>*   initialize a new state with it* if dev == NULL => legacy implicit initialization, return the already created*   state or create a new one*/
static AudioState *audio_init(Audiodev *dev, Error **errp)
{static bool atexit_registered;int done = 0;const char *drvname;VMChangeStateEntry *vmse;AudioState *s;struct audio_driver *driver;s = g_new0(AudioState, 1);QLIST_INIT (&s->hw_head_out);QLIST_INIT (&s->hw_head_in);QLIST_INIT (&s->cap_head);if (!atexit_registered) {atexit(audio_cleanup);atexit_registered = true;}s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);if (dev) {/* -audiodev option */s->dev = dev;drvname = AudiodevDriver_str(dev->driver);driver = audio_driver_lookup(drvname);if (driver) {done = !audio_driver_init(s, driver, dev, errp);} else {error_setg(errp, "Unknown audio driver `%s'", drvname);}if (!done) {goto out;}} else {assert(!default_audio_state);for (;;) {AudiodevListEntry *e = QSIMPLEQ_FIRST(&default_audiodevs);if (!e) {error_setg(errp, "no default audio driver available");goto out;}s->dev = dev = e->dev;QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);g_free(e);drvname = AudiodevDriver_str(dev->driver);driver = audio_driver_lookup(drvname);if (!audio_driver_init(s, driver, dev, NULL)) {break;}qapi_free_Audiodev(dev);s->dev = NULL;}}if (dev->timer_period <= 0) {s->period_ticks = 1;} else {s->period_ticks = dev->timer_period * (int64_t)SCALE_US;}vmse = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);if (!vmse) {dolog ("warning: Could not register change state handler\n""(Audio can continue looping even after stopping the VM)\n");}QTAILQ_INSERT_TAIL(&audio_states, s, list);QLIST_INIT (&s->card_head);vmstate_register_any(NULL, &vmstate_audio, s);return s;out:free_audio_state(s);return NULL;
}

audio_create_default_audiodevs()

最后,如果设置了 default_audio,调用函数 audio_create_default_audiodevs() 创建默认音频设备,代码如下:

void audio_create_default_audiodevs(void)
{for (int i = 0; audio_prio_list[i]; i++) {if (audio_driver_lookup(audio_prio_list[i])) {QDict *dict = qdict_new();Audiodev *dev = NULL;Visitor *v;qdict_put_str(dict, "driver", audio_prio_list[i]);qdict_put_str(dict, "id", "#default");v = qobject_input_visitor_new_keyval(QOBJECT(dict));qobject_unref(dict);visit_type_Audiodev(v, NULL, &dev, &error_fatal);visit_free(v);audio_define_default(dev, &error_abort);}}
}

3.调试输出

首先,添加跟踪调试信息,修改后的代码如下:

```c
static void qemu_create_early_backends(void)
{...huedbg_flag = 1;HUEDBG("\n");huedbg_dump_device_configs(2);HUEDBG("\n");qemu_create_early_backends();HUEDBG("\n");huedbg_dump_device_configs(2);HUEDBG("\n");huedbg_flag = 0;...
}

运行后,输出信息如下:



总结

以上分析了系统初始化过程中创建早期后端驱动的过程。

这篇关于【QEMU系统分析之实例篇(十四)】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/961280

相关文章

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

Apache Ignite缓存基本操作实例详解

《ApacheIgnite缓存基本操作实例详解》文章介绍了ApacheIgnite中IgniteCache的基本操作,涵盖缓存获取、动态创建、销毁、原子及条件更新、异步执行,强调线程池注意事项,避免... 目录一、获取缓存实例(Getting an Instance of a Cache)示例代码:二、动态

JSONArray在Java中的应用操作实例

《JSONArray在Java中的应用操作实例》JSONArray是org.json库用于处理JSON数组的类,可将Java对象(Map/List)转换为JSON格式,提供增删改查等操作,适用于前后端... 目录1. jsONArray定义与功能1.1 JSONArray概念阐释1.1.1 什么是JSONA

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

在Windows上使用qemu安装ubuntu24.04服务器的详细指南

《在Windows上使用qemu安装ubuntu24.04服务器的详细指南》本文介绍了在Windows上使用QEMU安装Ubuntu24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置... 目录1. 安装QEMU环境2. 准备Ubuntu 24.04镜像3. 启动QEMU安装Ubuntu4

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析

《Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析》InstantiationAwareBeanPostProcessor是Spring... 目录一、什么是InstantiationAwareBeanPostProcessor?二、核心方法解