8.3 Qemu启动参数管理

来源:互联网 发布:中小学排课软件 编辑:程序博客网 时间:2024/04/28 13:01


8.3.1参数初始化流程

其代码位于vl.c(main.c)

a)  判断是否使用default设置 

optind = 1;

popt = lookup_opt(argc, argv,&optarg, &optind);

switch (popt->index) {

case QEMU_OPTION_nodefconfig:

defconfig= false;

break;

caseQEMU_OPTION_nouserconfig:

userconfig= false;

break;

}

b)  若使用default设置,则

if (defconfig)

ret =qemu_read_default_config_files(userconfig);

c)  针对不同命令行参数,做不同预处理,这里看看QEMU_OPTION_hda的流程

popt = lookup_opt(argc, argv,&optarg, &optind);

switch(popt->index) {

case QEMU_OPTION_hda:

{

charbuf[256];

if(cyls == 0)

snprintf(buf,sizeof(buf), "%s", HD_OPTS);

else

snprintf(buf,sizeof(buf), "%s,cyls=%d,heads=%d,secs=%d%s",

HD_OPTS, cyls, heads, secs,

translation== BIOS_ATA_TRANSLATION_LBA ?

",trans=lba":

translation== BIOS_ATA_TRANSLATION_NONE ?

",trans=none": "");

drive_add(IF_DEFAULT,0, optarg, buf);

break;

}

}

d)  参数的使用

if(qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,&machine->use_scsi, 1) != 0)

exit(1);

 

8.3.2 代码分析

(1) lookup_opt

         optind = 1;

          popt =lookup_opt(argc, argv, &optarg, &optind);

lookup_opt 负责从

a.argv中取出一个参数,并将optfind加1。

b.从qemu_options列表中根据参数名进行匹配

popt = qemu_options;

    for(;;) {

        if(!strcmp(popt->name, r + 1))

            break;

        popt++;

    }

optarg = argv[optind++];

    *poptarg = optarg;

    *poptind = optind;

return popt;

 

static const QEMUOption qemu_options[] = {

    { "h", 0,QEMU_OPTION_h, QEMU_ARCH_ALL },

#define QEMU_OPTIONS_GENERATE_OPTIONS

#include "qemu-options-wrapper.h"

    { NULL },

};

查看qemu-options-wrapper.h发现qemu-options.def定义了每个参数项。

DEF("hda", HAS_ARG, QEMU_OPTION_hda,

"-hda/-hdb file  use'file' as IDE hard disk 0/1 image\n", QEMU_ARCH_ALL)

 

(2) Default config加载

qemu_read_default_config_files ==》

    for (f = default_config_files;f->filename; f++) {

        if (!userconfig&& f->userconfig) {

            continue;

        }

        ret =qemu_read_config_file(f->filename);

        if (ret < 0&& ret != -ENOENT) {

            return ret;

        }

    }

static struct defconfig_file {

    const char *filename;

    /* Indicates it is anuser config file (disabled by -no-user-config) */

    bool userconfig;

} default_config_files[] = {

    { CONFIG_QEMU_CONFDIR"/qemu.conf",                   true },

    { CONFIG_QEMU_CONFDIR"/target-" TARGET_ARCH".conf", true },

    { NULL }, /* end oflist */

};

 

qemu_read_config_file ==》qemu_config_parse(f, vm_config_groups, filename);

   从配置文件中解析参数并用qemu_opts_create和qemu_opt_set设置参数和其值

 

qemu_opts_create 将参数项添加到链表中,返回QemuOpts * opts:

   QTAILQ_INIT(&opts->head);

   QTAILQ_INSERT_TAIL(&list->head, opts, next);

 

lists为vm_config_groups,其每个子项时一个list

static QemuOptsList *vm_config_groups[32] = {

    &qemu_drive_opts,

    。。。。。。。

    NULL,

};

 

struct QemuOptsList {

    const char *name;

    const char*implied_opt_name;

    bool merge_lists;  /* Merge multiple uses of option into asingle list? */

    QTAILQ_HEAD(,QemuOpts) head;

    QemuOptDesc desc[];

};

 

static QemuOptsList qemu_drive_opts = {

    .name ="drive",

    .head =QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),

    .desc = {

        {

            .name ="bus",

            .type =QEMU_OPT_NUMBER,

            .help ="bus number",

        },{

            .name ="unit",

            .type =QEMU_OPT_NUMBER,

            .help ="unit number (i.e. lun for scsi)",

        },{

            .name ="if",

            .type =QEMU_OPT_STRING,

            .help ="interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",

        },{

            .name ="index",

            .type =QEMU_OPT_NUMBER,

            .help ="index number",

        },

.........

一个oplist有多个desc.用于描述不同的子参数设子

 

qemu_opt_set ==> opt_set(opts, name, value, false,&local_err);

根据opt的子参数,设置opt项的值

QemuOpt *opt;

    opt =g_malloc0(sizeof(*opt));

    opt->name =g_strdup(name);

    opt->opts = opts;

    if (prepend) {

       QTAILQ_INSERT_HEAD(&opts->head, opt, next);

    } else {

       QTAILQ_INSERT_TAIL(&opts->head, opt, next);

    }

 

小结:(1) QemuOptsList *vm_config_groups 管理不同的配置类别;

      (2) QemuOptsList->head  链表管理用于添加的QemuOpts  *opts;

      (3) QemuOpts->head链表管理子项设置QemuOpt * opt

      (4) 每个QemuOpt ->desc 记录了它对应在opts中的那个子项参数

 

(3) driver 参数分析

QemuOpts *drive_add(BlockInterfaceType type, int index, constchar *file,

                    constchar *optstr)

{

    opts =drive_def(optstr);  //取QemuOpts  *opts

    if (type !=IF_DEFAULT) {

        qemu_opt_set(opts,"if", if_name[type]);

    }

    if (index >= 0) {

        snprintf(buf,sizeof(buf), "%d", index);

        qemu_opt_set(opts,"index", buf);

    }

    if (file)

        qemu_opt_set(opts,"file", file);

    return opts;

}

 

drive_def ==》  qemu_opts_parse(qemu_find_opts("drive"),optstr, 0);

a. qemu_find_opts("drive") 根据名称得到vm_config_groups中的数组一项qemu_drive_opts;

b. qemu_opts_parse ==> opts_parse 在QemuOptsList的链表中搜索QemuOpts *opts,若不存在则创建。

 

qemu_opts_foreach(qemu_find_opts("drive"),drive_init_func, &machine->use_scsi, 1);

qemu_opts_foreach 遍历QemuOptsList, 的每个子项QemuOpts  *opts, 并为其调用callback:

typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);

 

drive_init_func ==> drive_init: 取出参数的值

    bus_id  = qemu_opt_get_number(opts, "bus",0);

    unit_id =qemu_opt_get_number(opts, "unit", -1);

    index   = qemu_opt_get_number(opts,"index", -1);

0 0
原创粉丝点击