【QEMU系统分析之启动篇(十五)】

系列文章目录

第十五章 QEMU系统仿真的导出虚拟机分析


文章目录

  • 系列文章目录
    • 第十五章 QEMU系统仿真的导出虚拟机分析
  • 前言
  • 一、QEMU是什么?
  • 二、QEMU系统仿真的启动分析
    • 1.系统仿真的初始化代码
    • 2.主循环数据初始化
    • 3. module_load_qom_all()
      • module_check_arch()
      • module_load()
    • 4.dump_vmstate_json_to_file(vmstate_dump_file)
  • 总结


前言

本文以 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 虚拟机的内存设备及NUMA初始化后,系统将处理导出信息的设置,本篇文章将完成以下代码部分的分析。

2.主循环数据初始化

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

void qemu_init(int argc, char **argv)
{
...if (vmstate_dump_file) {/* dump and exit */module_load_qom_all();dump_vmstate_json_to_file(vmstate_dump_file);exit(0);}
...
}

3. module_load_qom_all()

此函数在 /util/module.c 文件中,定义如下:

void module_load_qom_all(void)
{const QemuModinfo *modinfo;Error *local_err = NULL;if (module_loaded_qom_all) {return;}for (modinfo = module_info; modinfo->name != NULL; modinfo++) {if (!modinfo->objs) {continue;}if (!module_check_arch(modinfo)) {continue;}if (module_load("", modinfo->name, &local_err) < 0) {error_report_err(local_err);}}module_loaded_qom_all = true;
}

module_check_arch()

函数 module_check_arch() 定义如下:

static bool module_check_arch(const QemuModinfo *modinfo)
{if (modinfo->arch) {if (!module_arch) {/* no arch set -> ignore all */return false;}if (strcmp(module_arch, modinfo->arch) != 0) {/* mismatch */return false;}}return true;
}

module_load()

函数 module_load(),定义如下:

int module_load(const char *prefix, const char *name, Error **errp)
{int rv = -1;
#ifdef CONFIG_MODULE_UPGRADESchar *version_dir;
#endifconst char *search_dir;char *dirs[5];char *module_name;int i = 0, n_dirs = 0;bool export_symbols = false;static GHashTable *loaded_modules;const QemuModinfo *modinfo;const char **sl;if (!g_module_supported()) {error_setg(errp, "%s", "this platform does not support GLib modules");return -1;}if (!loaded_modules) {loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);}/* allocate all resources managed by the out: label here */module_name = g_strdup_printf("%s%s", prefix, name);if (g_hash_table_contains(loaded_modules, module_name)) {g_free(module_name);return 2; /* module already loaded */}g_hash_table_add(loaded_modules, module_name);search_dir = getenv("QEMU_MODULE_DIR");if (search_dir != NULL) {dirs[n_dirs++] = g_strdup_printf("%s", search_dir);}dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);#ifdef CONFIG_MODULE_UPGRADESversion_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",'_');dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
#endifassert(n_dirs <= ARRAY_SIZE(dirs));/* end of resources managed by the out: label */for (modinfo = module_info; modinfo->name != NULL; modinfo++) {if (modinfo->arch) {if (strcmp(modinfo->name, module_name) == 0) {if (!module_check_arch(modinfo)) {error_setg(errp, "module arch does not match: ""expected '%s', got '%s'", module_arch, modinfo->arch);goto out;}}}if (modinfo->deps) {if (strcmp(modinfo->name, module_name) == 0) {/* we depend on other module(s) */for (sl = modinfo->deps; *sl != NULL; sl++) {int subrv = module_load("", *sl, errp);if (subrv <= 0) {rv = subrv;goto out;}}} else {for (sl = modinfo->deps; *sl != NULL; sl++) {if (strcmp(module_name, *sl) == 0) {/* another module depends on us */export_symbols = true;}}}}}for (i = 0; i < n_dirs; i++) {char *fname = g_strdup_printf("%s/%s%s",dirs[i], module_name, CONFIG_HOST_DSOSUF);int ret = access(fname, F_OK);if (ret != 0 && (errno == ENOENT || errno == ENOTDIR)) {/** if we don't find the module in this dir, try the next one.* If we don't find it in any dir, that can be fine too: user* did not install the module. We will return 0 in this case* with no error set.*/g_free(fname);continue;} else if (ret != 0) {/* most common is EACCES here */error_setg_errno(errp, errno, "error trying to access %s", fname);} else if (module_load_dso(fname, export_symbols, errp)) {rv = 1; /* module successfully loaded */}g_free(fname);goto out;}rv = 0; /* module not found */out:if (rv <= 0) {g_hash_table_remove(loaded_modules, module_name);g_free(module_name);}for (i = 0; i < n_dirs; i++) {g_free(dirs[i]);}return rv;
}

函数 module_load(),定义如下:

/* Load a module from a DSO */
static CONF_MODULE *module_load_dso(const CONF *cnf,const char *name, const char *value)
{DSO *dso = NULL;conf_init_func *ifunc;conf_finish_func *ffunc;const char *path = NULL;int errcode = 0;CONF_MODULE *md;/* Look for alternative path in module section */path = _CONF_get_string(cnf, value, "path");if (path == NULL) {path = name;}dso = DSO_load(NULL, path, NULL, 0);if (dso == NULL) {errcode = CONF_R_ERROR_LOADING_DSO;goto err;}ifunc = (conf_init_func *)DSO_bind_func(dso, DSO_mod_init_name);if (ifunc == NULL) {errcode = CONF_R_MISSING_INIT_FUNCTION;goto err;}ffunc = (conf_finish_func *)DSO_bind_func(dso, DSO_mod_finish_name);/* All OK, add module */md = module_add(dso, name, ifunc, ffunc);if (md == NULL)goto err;return md;err:DSO_free(dso);ERR_raise_data(ERR_LIB_CONF, errcode, "module=%s, path=%s", name, path);return NULL;
}

4.dump_vmstate_json_to_file(vmstate_dump_file)

函数 dump_vmstate_json_to_file() 定义如下:

void dump_vmstate_json_to_file(FILE *out_file)
{GSList *list, *elt;bool first;fprintf(out_file, "{\n");dump_machine_type(out_file);first = true;list = object_class_get_list(TYPE_DEVICE, true);for (elt = list; elt; elt = elt->next) {DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,TYPE_DEVICE);const char *name;int indent = 2;if (!dc->vmsd) {continue;}if (!first) {fprintf(out_file, ",\n");}name = object_class_get_name(OBJECT_CLASS(dc));fprintf(out_file, "%*s\"%s\": {\n", indent, "", name);indent += 2;fprintf(out_file, "%*s\"Name\": \"%s\",\n", indent, "", name);fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",dc->vmsd->version_id);fprintf(out_file, "%*s\"minimum_version_id\": %d,\n", indent, "",dc->vmsd->minimum_version_id);dump_vmstate_vmsd(out_file, dc->vmsd, indent, false);fprintf(out_file, "\n%*s}", indent - 2, "");first = false;}fprintf(out_file, "\n}\n");fclose(out_file);g_slist_free(list);
}

函数 dump_vmstate_vmsd() 定义如下:

static void dump_vmstate_vmsd(FILE *out_file,const VMStateDescription *vmsd, int indent,bool is_subsection)
{if (is_subsection) {fprintf(out_file, "%*s{\n", indent, "");} else {fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description");}indent += 2;fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name);fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",vmsd->version_id);fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "",vmsd->minimum_version_id);if (vmsd->fields != NULL) {const VMStateField *field = vmsd->fields;bool first;fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, "");first = true;while (field->name != NULL) {if (field->flags & VMS_MUST_EXIST) {/* Ignore VMSTATE_VALIDATE bits; these don't get migrated */field++;continue;}if (!first) {fprintf(out_file, ",\n");}dump_vmstate_vmsf(out_file, field, indent + 2);field++;first = false;}assert(field->flags == VMS_END);fprintf(out_file, "\n%*s]", indent, "");}if (vmsd->subsections != NULL) {const VMStateDescription **subsection = vmsd->subsections;bool first;fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, "");first = true;while (*subsection != NULL) {if (!first) {fprintf(out_file, ",\n");}dump_vmstate_vmss(out_file, subsection, indent + 2);subsection++;first = false;}fprintf(out_file, "\n%*s]", indent, "");}fprintf(out_file, "\n%*s}", indent - 2, "");
}

函数 dump_vmstate_vmsf() 定义如下:

static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field,int indent)
{fprintf(out_file, "%*s{\n", indent, "");indent += 2;fprintf(out_file, "%*s\"field\": \"%s\",\n", indent, "", field->name);fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",field->version_id);fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "",field->field_exists ? "true" : "false");if (field->flags & VMS_ARRAY) {fprintf(out_file, "%*s\"num\": %d,\n", indent, "", field->num);}fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size);if (field->vmsd != NULL) {fprintf(out_file, ",\n");dump_vmstate_vmsd(out_file, field->vmsd, indent, false);}fprintf(out_file, "\n%*s}", indent - 2, "");
}

函数 dump_vmstate_vmss() 定义如下:

static void dump_vmstate_vmss(FILE *out_file,const VMStateDescription **subsection,int indent)
{if (*subsection != NULL) {dump_vmstate_vmsd(out_file, *subsection, indent, true);}
}

总结

以上分析了 QEMU 系统仿真在启动过程中,QEMU 系统仿真导出虚拟机状态参数到文件中的代码实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十进制正负整数的二进制有几个1

这个问题的答案和这个十进制数的类型有关&#xff08;int、long、byte…&#xff09;。还有要清楚负数的二进制是补码。 我第一个想到的就是树状数组的lowbit int lowbit(int x) { return x & -x; }// lowbit(4)4 lowbit(6)2 int main() {int n;cin >> n;int res…

描述Java中的备忘录模式。

备忘录模式&#xff08;Memento Pattern&#xff09;是软件工程中的一种设计模式&#xff0c;属于行为型模式。它主要用于在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便之后可以将对象恢复到原先保存的状态…

面试二十二、跳表SkipLists

跳表全称为跳跃列表&#xff0c;它允许快速查询&#xff0c;插入和删除一个有序连续元素的数据链表。跳跃列表的平均查找和插入时间复杂度都是O(logn)。快速查询是通过维护一个多层次的链表&#xff0c;且每一层链表中的元素是前一层链表元素的子集&#xff08;见右边的示意图&…

南都电源:以技术创新引领储能行业新发展

随着全球能源结构的深刻变革&#xff0c;储能行业正迎来前所未有的发展机遇。在这个充满挑战与机遇的时代&#xff0c;南都电源以其深厚的技术底蕴和前瞻的战略视野&#xff0c;成为储能行业的佼佼者。近日发布的2023年度业绩报告&#xff0c;更是彰显了其在行业内的领先地位和…

嵌入式UBoot如何跳转Kernel—uboot与linux交界分析

不知道你是否有这种感觉,就是学习了Uboot,学习了kernel,学习了安卓。但是有时候总感觉是各自孤立的,将三者连续不起来? • 不知道你是否在做启动方案的时候,在宏观上知道了整个启动链路流程,但是却在汪洋的代码中迷了路? 那么这篇文章必定对你有点用处。 如果没有,那请…

技术速递|MSTest SDK 简介 – 改进的配置和灵活性

作者&#xff1a;Marco Rossignoli & Amaury Lev 排版&#xff1a;Alan Wang 我们很高兴地宣布&#xff0c;基于 MSBuild Project SDK 系统构建的全新 MSTest SDK已推出。它旨在通过合理的默认值和灵活的选项使项目配置更加容易&#xff0c;从而为您提供更好的 MSTest 测试…

javabean技术四种方法

1.form表单 index页面 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><!-- jsp页面输入三角形三条边&#xff0c;输出周长和面积 --><!-- 实例化对象bean的名字可以随便取名&#xff0…

人工智能与汽车行业的定量分析研究

人工智能与汽车行业的定量分析研究 摘要&#xff1a;[论文摘要] 关键词&#xff1a;[论文关键词] 一、引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经深入到各个行业领域&#xff0c;汽车行业亦不例外。AI与汽车行业的结合&#xff0c;不…

Nginx基本使用 反向代理与负载均衡

什么是Nginx Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器。 其特点是占有内存少&#xff0c;并发能力强&#xff0c;nginx的并发能力在同类型的网页服务器中表现较好&#xff0c;而且几乎可以做到7*24不间断运行&#xff0c;即使运行数个月也不需要重新启动。 …

MP2110A Anritsu 安立 采样示波器 眼图设备 简述

MP2110A是一款集成了误码率测试仪&#xff08;BERT&#xff09;和采样示波器的一体化测量仪器&#xff0c;主要用于光学模块的误码率&#xff08;BER&#xff09;测量、眼图分析等评估操作。它支持从10G到800G的光学模块制造过程中的检测分91522。MP2110A内置4通道采样示波器&a…

MySQL从安装、配置到日常操作和管理的关键步骤

MySQL是一款广泛使用的开源关系型数据库管理系统&#xff0c;用于存储、管理、检索和处理数据。以下是一个详细的MySQL使用教程&#xff0c;包括安装、基本操作、数据管理、权限控制、备份与恢复等方面的内容&#xff1a; 一、MySQL安装 下载&#xff1a; 访问MySQL官方网站&a…

k8s部署jupyterlab,jupyterlab保存不了文件,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

磁盘分区以及MBR与GPT

磁盘分区以及MBR与GPT 磁盘分区的概念MBR&#xff08;Master Boot Record&#xff09;与GPT&#xff08;GUID Partition Table&#xff09;分区命令LinuxWindows 磁盘分区的概念 磁盘分区是将一个物理硬盘驱动器划分为多个逻辑部分的过程。每个分区可以看作是一个独立的硬盘&a…

ElasticSearch:查询操作合集

先看下我的数据&#xff1a; 1、查询所有文档&#xff1a; GET /cartest/_search或者 GET /cartest/_search {"query": {"match_all": {}} }2、匹配查询&#xff1a; match匹配类型查询&#xff0c;会把查询条件进行分词&#xff0c;然后进行查询&…

【树莓派】如何用电脑连接树莓派的远程桌面,灰屏解决

要使用VNC桌面连接到树莓派&#xff0c;你需要确保已经安装并启动了VNC服务器。以下是连接到树莓派的步骤&#xff1a; 在树莓派上启动VNC服务器&#xff1a; 打开终端或SSH连接到你的树莓派。输入以下命令以安装RealVNC的VNC服务器&#xff1a;sudo apt update sudo apt insta…

PLSQL数据库

目录 什么是PLSQL数据库 PL数据库的实现方法 PL数据库的基本语法 1.作用 2.语法 3.赋值输出 4.引用 5.异常处理 6.if 判断 7.loop循环 8.while循环 9.for循环 10.游标 11.参数游标 12.索引 13.分区表 什么是PLSQL数据库 PL/SQL&#xff08;Procedure Language/…

微前端通信机制及其实现

微前端通信机制是指在微前端架构中&#xff0c;不同的微应用之间进行通信的方式和机制。微前端通信机制的实现可以通过以下几种方式&#xff1a; 事件总线&#xff08;Event Bus&#xff09;&#xff1a;微前端架构中的主应用可以创建一个事件总线&#xff0c;用于发布和订阅事…

【C++航海王:追寻罗杰的编程之路】C++11(二)

目录 C11(上) 1 -> STL中的一些变化 2 -> 右值引用和移动语义 2.1 -> 左值引用和右值引用 2.2 -> 左值引用与右值引用比较 2.3 -> 右值引用使用场景与意义 2.4 -> 右值引用引用左值及其更深入的使用场景分析 2.5 -> 完美转发 C11(上) 1 -> STL…

为什么要建设数字化校园?

数字化校园的建设能够使用户能够随时随地的在有互联网的地方获取到校园的信息&#xff0c;而且由于这些信息都是有校园的管理部门发布的&#xff0c;所以这样就能保证信息的权威性。数字化校园平台还能让学校内部建立起相对独立的网络体系&#xff0c;能有效的消除“信息化孤岛…

Leetcode 3121. Count the Number of Special Characters II

Leetcode 3121. Count the Number of Special Characters II 1. 解题思路2. 代码实现 题目链接&#xff1a;3121. Count the Number of Special Characters II 1. 解题思路 这一题算是一个分类讨论的问题吧&#xff0c;我们只需要对每一个字符考察其前序当中所有出现过的字符…