Full analysis of QEMU source code 3 - QEMU parameter analysis (3)

Continued from the previous article: Full Analysis of QEMU Source Code 2 —— Analysis of QEMU Parameters (2)

References for the content of this article:

"Interesting Talk about Linux Operating System" —— Liu Chao, Geek Time

"QEMU/KVM" source code analysis and application - Li Qiang, Machinery Industry Press

Thank you very much!

Last time I talked about the QEMUOptions structure and the global variable qemu_options, this section continues to explore it in depth.

For the convenience of understanding and meeting, the code of the QEMUOption structure is posted here, in softmmu/vl.c:

typedef struct QEMUOption {
    const char *name;
    int flags;
    int index;
    uint32_t arch_mask;
} QEMUOption;

QEMUOption provides basic information about parameters. The saving of actual parameters is done by 3 data structures.

QEMU divides all parameters into several large options, which can also be called classes, such as -enable-kvm and -kernel are machine-related, and each large option is represented by the struct QemuOptsList structure, which is defined in include/qemu/option. h, the code is as follows:

struct QemuOptsList {
    const char *name;
    const char *implied_opt_name;
    bool merge_lists;  /* Merge multiple uses of option into a single list? */
    QTAILQ_HEAD(, QemuOpts) head;
    QemuOptDesc desc[];
};

QEMU defines the global variable vm_config_groups of type struct QemuOptsList in util/qemu-config.c, the code is as follows:

static QemuOptsList *vm_config_groups[48];
static QemuOptsList *drive_config_groups[5];

This means that 48 large options can be supported. In the main function (qemu_init function of softmmu/vl.c), use qemu_add_opts to add each OemuOptsList to vm_config_groups.

Finally back to the code given in the first article of this series, in void qemu_init(int argc, char **argv) in softmmu/vl.c:

    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_plugin_add_opts();
    qemu_add_opts(&qemu_option_rom_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_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);
    qemu_add_opts(&qemu_action_opts);

It's time to look at the implementation of qemu_add_opts. In util/qemu-config.c, the code is as follows:

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();
}

This function implements the functions described above: qemu_add_opts adds each OemuOptsList to vm_config_groups (static QemuOptsList *vm_config_groups[48]).

Each QemuOptsList stores all small options supported by large options, such as -overcommit large options are defined as follows (in softmmu/vl.c):

static QemuOptsList qemu_overcommit_opts = {
    .name = "overcommit",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_overcommit_opts.head),
    .desc = {
        {
            .name = "mem-lock",
            .type = QEMU_OPT_BOOL,
        },
        {
            .name = "cpu-pm",
            .type = QEMU_OPT_BOOL,
        },
        { /* end of list */ }
    },
};

-overcommit only supports two sub-options with a value of bool (QEMU_OPT_BOOL), that is, only -overcommit mem-lock=on/off and -overcommit cpu-pm=on/off.

But this is not the case for some big options, such as -device This (kind of) option is not so rigid. The -device large option is defined as follows (also in oftmmu/vl.c):

QemuOptsList qemu_device_opts = {
    .name = "device",
    .implied_opt_name = "driver",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
    .desc = {
        /*
         * no elements => accept any
         * sanity checking will happen later
         * when setting device properties
         */
        { /* end of list */ }
    },
};

-device does not specify the necessary options, because there are countless kinds of devices, it is impossible to specify all of them, and the analysis is carried out according to "," or "=". Each suboption is represented by a QemuOpt structure.

For the specific definition of the QemuOpt structure and the relationship between QemuOptsList, QemuOpt, QemuOpts and other structures, see the next chapter for decomposition.

Guess you like

Origin blog.csdn.net/phmatthaus/article/details/131547841