QEMU的参数解析

QEMU中定义了QEMUOption结构体来表示执行qemu-system-i386等命令时用到的选项。

qemu参数 qemu命令参数_main函数

并且在vl.c中定义了QEMUOption数组qemu_options来存储所有可用的选项,并且利用qemu-options-wrapper.h来给这个数组赋值。如上图
,#define QEMU_OPTIONS_GENERATE_OPTIONS选择qemu-options-wrapper.h的操作,在qemu-options-wrapper.h中有一些宏

qemu参数 qemu命令参数_数组_02

QEMU_OPTIONS_GENERATE_ENUM: 生成一个枚举值列表,对应与上图中QEMUOption结构的index值,例如QEMU_OPTION_h

QEMU_OPTIONS_GENERATE_HELP: 生成帮助信息输出到标准输出

QEMU_OPTIONS_GENERATE_OPTIONS: 生成一组选项列表

在qemu-options.hx中可以看到调用,例如object选项

qemu参数 qemu命令参数_数组_03

给qemu_options数组赋值之后,在vl.c的main函数中根据这个数组来解析命令。

参数解析第一步,遍历参数数组,通过lookup_opt函数来得到一个QEMUOption,判断这个QEMUOption是否在原来生成的QEMUOption数组中,主要作用是排错。第二步才是真正的解析

qemu参数 qemu命令参数_数组_04

lookup_opt中通过参数名来在qemu_options这个全局数组中根据参数寻找对应的option,然后将option后边的参数保存到optarg

qemu参数 qemu命令参数_数组_05

第二步也是遍历参数数组,通过lookup_opt函数找到对应的QEMUOption,然后将option后边的参数保存到optarg通过index成员来判断是哪个option,然后执行不同的分支。

qemu参数 qemu命令参数_qemu参数_06

解析参数用到的四个结构:QemuOpts, QemuOpt, QemuOptsList, QemuOptDesc

QemuOpts和QemuOpt定义在option_int.h中,QemuOpt存储子选项,每个QemuOpt都有一个QemuOptDesc来描述子选项的名字,类型以及帮助信息。QemuOpts表示同一个id下的所有子选项,QEMU可能会多次使用同一个大选项来指定多个相同的设备,这个就是用id来区分。

qemu参数 qemu命令参数_qemu参数_07

qemu参数 qemu命令参数_赋值_08

子选项的类型如下:

qemu参数 qemu命令参数_赋值_09

QemuOptDesc和QemuOptsList定义在option.h中,一个QemuOptsList代表一个qemu option,子选项就存在QemuOpt中。

qemu参数 qemu命令参数_main函数_10

整个QEMU选项结构体之间的关系图如下:

qemu参数 qemu命令参数_qemu参数_11

以object选项为例,具体解析

首先在vl.c的main函数中解析参数,解析参数用到的函数时qemu_opts_parse_noisily和qemu_find_opts

![

qemu参数 qemu命令参数_main函数_12


1.qemu_find_opts函数qemu_find_opts声明在qemu\config-file.h中,定义在qemu-config.c中,内部调用了find_list函数,find_list函数里面通过比较vm_config_groups(是一个QemuOptsList结构数组)的name与group的值,来返回一个QemuOptsList

qemu参数 qemu命令参数_main函数_13

qemu参数 qemu命令参数_数组_14

vm_config_groups这个结构的填充,实在vl.c的main函数中通过调用qemu_add_opts这个函数把定义好的不同的选项QemuOptsList结构添加到这个数组中。

qemu参数 qemu命令参数_qemu参数_15

qemu参数 qemu命令参数_main函数_16

2.qemu_opts_parse_noisily函数

qemu_opts_parse_noisily声明在qemu\option.h中,定义在util\qemu-option.c中,调用了opts_parse

qemu参数 qemu命令参数_main函数_17

在opts_parse函数中首先获取id的值,然后调用qemu_opts_create返回一个opts,调用opts_do_parse解析。firstname是list->implied_opt_name值。

qemu参数 qemu命令参数_数组_18


qemu参数 qemu命令参数_赋值_19

在qemu_opts_create中,判断如果id存在或list->merge_lists存在,则直接调用qemu_opts_find来返回一个QEMUOpts结构。否则新建一个QemuOpts节点,插入list。

qemu参数 qemu命令参数_main函数_20

qemu参数 qemu命令参数_qemu参数_21

在qemu_opts_find中,调用宏QTAILQ_FOREACH,遍历list中的每个QemuOpts节点,判断id是否同时存在或同事不存在,

qemu参数 qemu命令参数_数组_22

opts_do_parse函数中,具体的解析操作

qemu参数 qemu命令参数_qemu参数_23

qemu参数 qemu命令参数_main函数_24

得到一个子选项后,调用opt_set函数,首先得到这个子选项的描述信息desc,然后新建一个子选项节点QemuOpt,填充信息,将这个QemuOpt节点加入到QemuOpts这个结构中。opt->str先保存子选项的值,然后调用qemu_opt_parse函数,根据子选项的类型来给value重新赋值。

qemu参数 qemu命令参数_qemu参数_25

在qemu_opt_parse中根据子选项的类型,重新对value赋值。

qemu参数 qemu命令参数_qemu参数_26