引言;本文内容主要以分析源码为主,顺着主要代码的逻辑进行梳理,不涉及架构部分
调试命令
ubuntu@VM-8-16-ubuntu:~/qemu$ gdb --args aarch64-softmmu/qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-m 2048 \
-nographic
解析参数的代码位于:vl.c
// vl.c
int main(int argc, char **argv, char **envp)
{
开始是多个QemuOptsList
结构体数组初始化
qemu_add_opts(&qemu_drive_opts);
qemu_add_drive_opts(&qemu_legacy_drive_opts);
qemu_add_drive_opts(&qemu_common_drive_opts);
qemu_add_drive_opts(&qemu_drive_opts);
qemu_add_drive_opts(&bdrv_runtime_opts);
qemu_add_opts(&qemu_chardev_opts);
qemu_add_opts(&qemu_device_opts);
qemu_add_opts(&qemu_netdev_opts);
qemu_add_opts(&qemu_nic_opts);
qemu_add_opts(&qemu_net_opts);
qemu_add_opts(&qemu_rtc_opts);
qemu_add_opts(&qemu_global_opts);
qemu_add_opts(&qemu_mon_opts);
qemu_add_opts(&qemu_trace_opts);
qemu_add_opts(&qemu_option_rom_opts);
qemu_add_opts(&qemu_machine_opts);
qemu_add_opts(&qemu_accel_opts);
qemu_add_opts(&qemu_mem_opts);
qemu_add_opts(&qemu_smp_opts);
qemu_add_opts(&qemu_boot_opts);
qemu_add_opts(&qemu_add_fd_opts);
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_tpmdev_opts);
qemu_add_opts(&qemu_realtime_opts);
qemu_add_opts(&qemu_overcommit_opts);
qemu_add_opts(&qemu_msg_opts);
qemu_add_opts(&qemu_name_opts);
qemu_add_opts(&qemu_numa_opts);
qemu_add_opts(&qemu_icount_opts);
qemu_add_opts(&qemu_semihosting_config_opts);
qemu_add_opts(&qemu_fw_cfg_opts);
所有的QemuOptsList
结构体数组存放于vm_config_groups
(还有一个地方:drive_config_groups
)
// util/qemu-config.c
static QemuOptsList *vm_config_groups[48];
static QemuOptsList *drive_config_groups[5];
以qemu_drive_opts
为例
// blockdev.c
QemuOptsList qemu_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
.desc = {
/*
* no elements => accept any params
* validation will happen later
*/
{
/* end of list */ }
},
};
来看看qemu_add_opts
这个函数,可见就是将该数组加入vm_config_groups
中
// util/qemu-config.c
void qemu_add_opts(QemuOptsList *list)
{
int entries, i;
entries = ARRAY_SIZE(vm_config_groups);
entries--; /* keep list NULL terminated */
for (i = 0; i < entries; i++) {
if (vm_config_groups[i] == NULL) {
vm_config_groups[i] = list;
return;
}
}
fprintf(stderr, "ran out of space in vm_config_groups");
abort();
}
qemu_add_drive_opts
同理
// util/qemu-config.c
void qemu_add_drive_opts(QemuOptsList *list)
{
int entries, i;
entries = ARRAY_SIZE(drive_config_groups);
entries--; /* keep list NULL terminated */
for (i = 0; i < entries; i++) {
if (drive_config_groups[i] == NULL) {
drive_config_groups[i] = list;
return;
}
}
fprintf(stderr, "ran out of space in drive_config_groups");
abort();
}
继续解析过程(它这里从1
开始是因为忽略前面的qemu-system-aarch64
)
/* second pass of option parsing */
optind = 1;
for(;;) {
if (optind >= argc)
break;
if (argv[optind][0] != '-') {
loc_set_cmdline(argv, optind, 1);
drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
} else {
const QEMUOption *popt;
popt = lookup_opt(argc, argv, &optarg, &optind);
if (!(popt->arch_mask & arch_type)) {
error_report("Option not supported for this target");
exit(1);
}
以运行指令为例,调用lookup_opt
获得popt
、optind
和optarg
的值
// vl.c
static const QEMUOption *lookup_opt(int argc, char **argv,
const char **poptarg, int *poptind)
{
const QEMUOption *popt;
int optind = *poptind;
char *r = argv[optind];
const char *optarg;
loc_set_cmdline(argv, optind, 1);
optind++;
/* Treat --foo the same as -foo. */
if (r[1] == '-')
r++;
popt = qemu_options;
for(;;) {
if (!popt->name) {
error_report("invalid option");
exit(1);
}
if (!strcmp(popt->name, r + 1))
break;
popt++;
}
if (popt->flags & HAS_ARG) {
if (optind >= argc) {
error_report("requires an argument");
exit(1);
}
optarg = argv[optind++];
loc_set_cmdline(argv, optind - 2, 2);
} else {
optarg = NULL;
}
*poptarg = optarg;
*poptind = optind;
return popt;