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

ops/2024/9/25 10:36:30/

系列文章目录

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


文章目录

  • 系列文章目录
    • 第二十章 QEMU系统仿真的机器创建分析实例
  • 前言
  • 一、QEMU是什么?
  • 二、QEMU系统仿真的机器创建分析实例
    • 1.系统仿真的命令行参数
    • 2. CPU 配置项解析
      • parse_cpu_option()
        • cpu_class_by_name()
        • parse_features()
    • 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,vendor=GenuineIntel,+ssse3,+sse4.2" -M  "q35,accel=whpx,smm=off" -m "6G" -audio "sdl,model=hda" -vga "std" -netdev "user,id=mynet0" -device "e1000,id=nic1,netdev=mynet0" -L "data" -qtest "unix:qtest-sock,server,nowait"

2. CPU 配置项解析

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

int qemu_init(int argc, char **argv)
{
.../* 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! */
...
}

前文分析了移对象的初始化过程,本文继续完成 CPU 配置项解析的过程。


parse_cpu_option()

函数 parse_cpu_option() 代码如下:


const char *parse_cpu_option(const char *cpu_option)
{ObjectClass *oc;CPUClass *cc;gchar **model_pieces;const char *cpu_type;model_pieces = g_strsplit(cpu_option, ",", 2);if (!model_pieces[0]) {error_report("-cpu option cannot be empty");exit(1);}oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces[0]);if (oc == NULL) {error_report("unable to find CPU model '%s'", model_pieces[0]);g_strfreev(model_pieces);exit(EXIT_FAILURE);}cpu_type = object_class_get_name(oc);cc = CPU_CLASS(oc);cc->parse_features(cpu_type, model_pieces[1], &error_fatal);g_strfreev(model_pieces);return cpu_type;
}

首先,调用函数 g_strsplit() 将 cpu_option 分成两部分,第一部分是 CPU 名字代号,第二部分是 CPU 的特性设置,代码如下:

    model_pieces = g_strsplit(cpu_option, ",", 2);

cpu_class_by_name()

代码如下:

ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
{ObjectClass *oc;CPUClass *cc;oc = object_class_by_name(typename);cc = CPU_CLASS(oc);assert(cc->class_by_name);assert(cpu_model);oc = cc->class_by_name(cpu_model);if (oc == NULL || object_class_is_abstract(oc)) {return NULL;}return oc;
}

然后,调用函数 parse_features() 完成 CPU 特性设定,代码如下:


parse_features()

代码如下:

static void cpu_common_parse_features(const char *typename, char *features,Error **errp)
{char *val;static bool cpu_globals_initialized;/* Single "key=value" string being parsed */char *featurestr = features ? strtok(features, ",") : NULL;/* should be called only once, catch invalid users */assert(!cpu_globals_initialized);cpu_globals_initialized = true;while (featurestr) {val = strchr(featurestr, '=');if (val) {GlobalProperty *prop = g_new0(typeof(*prop), 1);*val = 0;val++;prop->driver = typename;prop->property = g_strdup(featurestr);prop->value = g_strdup(val);qdev_prop_register_global(prop);} else {error_setg(errp, "Expected key=value format, found %s.",featurestr);return;}featurestr = strtok(NULL, ",");}
}

对于 i386 CPU,则有如下实现:

/* Parse "+feature,-feature,feature=foo" CPU feature string*/
static void x86_cpu_parse_featurestr(const char *typename, char *features,Error **errp)
{HUEDBG("enter\n");char *featurestr; /* Single 'key=value" string being parsed */static bool cpu_globals_initialized;bool ambiguous = false;if (cpu_globals_initialized) {HUEDBG("exit\n");return;}cpu_globals_initialized = true;if (!features) {HUEDBG("exit\n");return;}HUEDBG("features=[%s]\n", features);for (featurestr = strtok(features, ",");featurestr;featurestr = strtok(NULL, ",")) {const char *name;const char *val = NULL;char *eq = NULL;char num[32];GlobalProperty *prop;/* Compatibility syntax: */if (featurestr[0] == '+') {plus_features = g_list_append(plus_features,g_strdup(featurestr + 1));continue;} else if (featurestr[0] == '-') {minus_features = g_list_append(minus_features,g_strdup(featurestr + 1));continue;}eq = strchr(featurestr, '=');if (eq) {*eq++ = 0;val = eq;} else {val = "on";}feat2prop(featurestr);name = featurestr;if (g_list_find_custom(plus_features, name, compare_string)) {warn_report("Ambiguous CPU model string. ""Don't mix both \"+%s\" and \"%s=%s\"",name, name, val);ambiguous = true;}if (g_list_find_custom(minus_features, name, compare_string)) {warn_report("Ambiguous CPU model string. ""Don't mix both \"-%s\" and \"%s=%s\"",name, name, val);ambiguous = true;}/* Special case: */if (!strcmp(name, "tsc-freq")) {int ret;uint64_t tsc_freq;ret = qemu_strtosz_metric(val, NULL, &tsc_freq);if (ret < 0 || tsc_freq > INT64_MAX) {error_setg(errp, "bad numerical value %s", val);return;}snprintf(num, sizeof(num), "%" PRId64, tsc_freq);val = num;name = "tsc-frequency";}prop = g_new0(typeof(*prop), 1);prop->driver = typename;prop->property = g_strdup(name);prop->value = g_strdup(val);qdev_prop_register_global(prop);}if (ambiguous) {warn_report("Compatibility of ambiguous CPU model ""strings won't be kept on future QEMU versions");}HUEDBG("exit\n");
}

3.调试输出

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

int qemu_init(int argc, char **argv)
{
.../* parse features once if machine provides default cpu_type */huedbg_flag = 1;HUEDBG("\n");current_machine->cpu_type = machine_class->default_cpu_type;if (cpu_option) {current_machine->cpu_type = parse_cpu_option(cpu_option);}HUEDBG("\n");huedbg_flag = 0;/* NB: for machine none cpu_type could STILL be NULL here! */
...
}const char *parse_cpu_option(const char *cpu_option)
{HUEDBG("enter\n");ObjectClass *oc;CPUClass *cc;gchar **model_pieces;const char *cpu_type;HUEDBG("cpu_option=[%s]\n", cpu_option);model_pieces = g_strsplit(cpu_option, ",", 2);if (!model_pieces[0]) {error_report("-cpu option cannot be empty");exit(1);}HUEDBG("cpu_option=[%s]\n", cpu_option);oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces[0]);if (oc == NULL) {error_report("unable to find CPU model '%s'", model_pieces[0]);g_strfreev(model_pieces);exit(EXIT_FAILURE);}cpu_type = object_class_get_name(oc);cc = CPU_CLASS(oc);cc->parse_features(cpu_type, model_pieces[1], &error_fatal);g_strfreev(model_pieces);HUEDBG("cpu_type=[%s]\n", cpu_type);HUEDBG("exit\n");return cpu_type;
}

运行后,输出信息如下:

[13052]../system/vl.c/qemu_init(3863):
[13052]../cpu-target.c/parse_cpu_option(248):enter
[13052]../cpu-target.c/parse_cpu_option(254):cpu_option=[Penryn,vendor=GenuineIntel,+ssse3,+sse4.2]
[13052]../cpu-target.c/parse_cpu_option(260):cpu_option=[Penryn,vendor=GenuineIntel,+ssse3,+sse4.2]
[13052]../qom/object.c/object_class_by_name(1095):enter
[13052]../qom/object.c/type_table_lookup(103):lookup type(x86_64-cpu) in hash table
[13052]../qom/object.c/object_class_by_name(1105):class(x86_64-cpu) return
[13052]../qom/object.c/object_class_by_name(1095):enter
[13052]../qom/object.c/type_table_lookup(103):lookup type(Penryn-x86_64-cpu) in hash table
[13052]../qom/object.c/object_class_by_name(1105):class(Penryn-x86_64-cpu) return
[13052]../qom/object.c/type_table_lookup(103):lookup type(cpu) in hash table
[13052]../qom/object.c/type_get_parent(194):parent_type(device)
[13052]../qom/object.c/type_get_parent(194):parent_type(object)
[13052]../qom/object.c/type_get_parent(196):no parent_type
[13052]../qom/object.c/type_get_parent(194):parent_type(x86_64-cpu)
[13052]../qom/object.c/type_get_parent(194):parent_type(cpu)
[13052]../target/i386/cpu.c/x86_cpu_parse_featurestr(5450):enter
[13052]../target/i386/cpu.c/x86_cpu_parse_featurestr(5466):features=[vendor=GenuineIntel,+ssse3,+sse4.2]
[13052]../target/i386/cpu.c/x86_cpu_parse_featurestr(5537):exit
[13052]../cpu-target.c/parse_cpu_option(273):cpu_type=[Penryn-x86_64-cpu]
[13052]../cpu-target.c/parse_cpu_option(274):exit
[13052]../system/vl.c/qemu_init(3868):

总结

以上分析了系统初始化过程中 CPU 配置项的解析过程。


http://www.ppmy.cn/ops/36249.html

相关文章

甲小姐对话柳钢:CEO对股东最大的责任,是对成功的概率负责|甲子光年

只有看见最微小的事物&#xff0c;才能洞悉伟大的定律。 来源&#xff5c;甲子光年 作者&#xff5c;甲小姐 刘杨楠 编辑&#xff5c;栗子 商业史上&#xff0c;职业经理人成为“空降CEO”的故事往往胜少败多。 “究其原因有三条——容易自嗨、喊口号&#xff1b;不顾公司历…

【动态规划算法】【Python实现】最长公共子序列

文章目录 [toc]问题描述最长公共子序列的结构子问题的递归结构 c [ i ] [ j ] c[i][j] c[i][j]递归方程 时间复杂性构造最长公共子序列Python实现算法的改进 问题描述 给定两个序列 X { x 1 , x 2 , ⋯ , x m } X \set{x_{1} , x_{2} , \cdots , x_{m}} X{x1​,x2​,⋯,xm​…

[力扣题解] 216. 组合总和 III

题目&#xff1a;216. 组合总和 III 思路 回溯法 代码 class Solution { private:vector<vector<int>> result;vector<int> path;public:void function(int k, int n, int startindex, int sum){int i;// 剪枝// 超过了, 不用找了;if(sum > n){return…

538.把二叉搜索树转换成累加树

给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值 原树中大于或等于 node.val 的值之和。 方法一&#xff1a;递归 class Solution{int sum 0;publ…

泰克示波器如何测量时延?

泰克示波器&#xff08;Tektronix Oscilloscope&#xff09;是一种用于测量和显示电信号的仪器。它可以通过观察电信号的波形来提供有关信号的各种信息&#xff0c;包括幅度、频率和时延。时延是指信号到达示波器的时间延迟&#xff0c;也可以用于测量信号在电路中传播的时间。…

Vector Laboratories|用于生物偶联疗法BioDesign™ dPEG® Linker连接平台

术语dPEG代表“离散PEG&#xff08;discrete PEG&#xff09;”&#xff0c;这是一种均一的、单分子量&#xff08;MW&#xff09;、高纯度的新一代聚乙二醇聚合物。Vector Laboratorie采用其受专利保护的专有生产工艺&#xff0c;可生产提供适合于各种应用场景&#xff0c;具有…

【代码随想录——哈希表】

1.哈希表理论基础 首先什么是 哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff09;。 那么哈希表能解决什么问题呢&#xff0c;一般哈希表都是用…

Candance画运算放大器

根据拉扎维《模拟CMOS集成电路设计》第九章第一个放大器进行搭建电路图。 此电路图中两个NMOS栅极互联是因为NMOS的衬底要接片上最低电压。所以要两个互联并接到最低点。 因为两条支路上的器件都是一样的&#xff0c;所以这两条路平分idc的直流电流。 测试的时候要加上下图这两…