對於qemu的啟動參數,qemu使用了一些基本的架構函數完成相關的解析,方便後續開發人員增加功能。
這部分的代碼還是有點複雜,所以自己總結一下。
qemu-kvm啟動參數的一個例子,使用libvirt建立的一個虛擬機器。
/usr/libexec/qemu-kvm
-name rhel6.5
-S
-M pc-0.15
-enable-kvm
-m 1024
-realtime mlock=off
-smp 1,sockets=1,cores=1,threads=1
-uuid 8f338d83-41c1-9df6-d42f-851f13949359
-no-user-config
-nodefaults
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/rhel6.5.monitor,server,nowait
-mon chardev=charmonitor,id=monitor,mode=control
-rtc base=utc
-no-shutdown
-boot c
-drive file=/var/lib/libvirt/images/rhel6.5.img,if=none,id=drive-virtio-disk0,format=raw,cache=none
-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0
-drive if=none,media=cdrom,id=drive-ide0-1-0,readonly=on,format=raw
-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
-netdev tap,fd=23,id=hostnet0
-device e1000,netdev=hostnet0,id=net0,mac=52:54:00:61:00:e7,bus=pci.0,addr=0x3
-chardev pty,id=charserial0
-device isa-serial,chardev=charserial0,id=serial0
-usb -device usb-tablet,id=input0
-vnc 127.0.0.1:0
-vga cirrus
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6
qemu參數程式碼分析,以realtime這個參數為例進行說明:
修改點一:
qemu_add_opts(&qemu_realtime_opts);
修改點二:
static QemuOptsList qemu_realtime_opts = {
.name = "realtime",
.head = QTAILQ_HEAD_INITIALIZER(qemu_realtime_opts.head),
.desc = {
{
.name = "mlock",
.type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
};
修改點三:
case QEMU_OPTION_realtime:
opts = qemu_opts_parse(qemu_find_opts("realtime"), optarg, 0);
if (!opts) {
exit(1);
}
configure_realtime(opts);
break;
修改點四:
static void configure_realtime(QemuOpts *opts)
{
bool enable_mlock;
enable_mlock = qemu_opt_get_bool(opts, "mlock", true);
if (enable_mlock) {
if (os_mlock() < 0) {
fprintf(stderr, "qemu: locking memory failed\n");
exit(1);
}
}
}
修改點五:
qemu-option.hx中增加
DEF("realtime", HAS_ARG, QEMU_OPTION_realtime,
"-realtime [mlock=on|off]\n"
" run qemu with realtime features\n"
" mlock=on|off controls mlock support (default: on)\n",
QEMU_ARCH_ALL)
STEXI
@item -realtime mlock=on|off
@findex -realtime
Run qemu with realtime features.
mlocking qemu and guest memory can be enabled via @option{mlock=on}
(enabled by default).
ETEXI
下面分析一下這些函數的處理流程:
1.qemu_add_opts(&qemu_realtime_opts);
qemu_add_opts函數在include/qemu/config-file.h中聲明,在util/qemu-config.c中定義。
在util/qemu-config.c中定義靜態變數
static QemuOptsList *vm_config_groups[32];
static QemuOptsList *drive_config_groups[4];
定義了數組,通過qemu_add_opts增加到vm_config_groups數組中。 qemu_realtime_opts定義如下:
static QemuOptsList qemu_realtime_opts = {
.name = "realtime",
.head = QTAILQ_HEAD_INITIALIZER(qemu_realtime_opts.head),
.desc = {
{
.name = "mlock",
.type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
};
2.在vl.c的main函數中,調用lookup_opt,該函數根據argv當前執行的參數,尋找qemu_options變數,返回對應的指標。
返回的optarg和optind參數含義:optarg執行對應參數後對應的內容,比如-realtime後的mlock=off.
傳回值的類型是QemuOption,對應的是和qemu-option.hx中名稱一致的變數指標,qemu_options變數在lv.c中定義。
static const QEMUOption qemu_options[] = {
{ "h", 0, QEMU_OPTION_h, QEMU_ARCH_ALL },
#define QEMU_OPTIONS_GENERATE_OPTIONS
#include "qemu-options-wrapper.h"
{ NULL },
};
typedef struct QEMUOption {
const char *name;
int flags;
int index;
uint32_t arch_mask;
} QEMUOption;
#define HAS_ARG 0x0001
#include "qemu-options-wrapper.h"中通過宏分別處理QEMU_OPTIONS_GENERATE_ENUM、QEMU_OPTIONS_GENERATE_HELP、QEMU_OPTIONS_GENERATE_OPTIONS。
具體的內容在#include "qemu-options.def"
通過宏處理後,qemu_options內容被填充。
QEMU_OPTIONS_GENERATE_HELP在如下情境下使用。
static void help(int exitcode)
{
version();
printf("usage: %s [options] [disk_image]\n\n"
"'disk_image' is a raw hard disk image for IDE hard disk 0\n\n",
error_get_progname());
#define QEMU_OPTIONS_GENERATE_HELP
#include "qemu-options-wrapper.h"
printf("\nDuring emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
"ctrl-alt-n switch to virtual console 'n'\n"
"ctrl-alt toggle mouse and keyboard grab\n"
"\n"
"When using -nographic, press 'ctrl-a h' to get some help.\n");
exit(exitcode);
}
枚舉宏的定義在qemu-options.h中定義
#ifndef _QEMU_OPTIONS_H_
#define _QEMU_OPTIONS_H_
enum {
#define QEMU_OPTIONS_GENERATE_ENUM
#include "qemu-options-wrapper.h"
};
#endif
3.qemu_find_opts代碼流程,返回對應名稱的QemuOptsList變數。
QemuOptsList *qemu_find_opts(const char *group)
{
QemuOptsList *ret;
Error *local_err = NULL;
ret = find_list(vm_config_groups, group, &local_err);
if (error_is_set(&local_err)) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
}
return ret;
}
調用qemu_opts_parse函數,根據QemuOptsList中定義的資料格式,產生QemuOpts變數,QemuOpts變數的格式定義如下:
在include/qemu/option_int.h
struct QemuOpt {
const char *name;
const char *str;
const QemuOptDesc *desc;
union {
bool boolean;
uint64_t uint;
} value;
QemuOpts *opts;
QTAILQ_ENTRY(QemuOpt) next;
};
struct QemuOpts {
char *id;
QemuOptsList *list;
Location loc;
QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
QTAILQ_ENTRY(QemuOpts) next;
};
最終可以調用qemu_opt_get_bool來擷取參數的具體值。qemu參數架構已經根據定義的格式完成瞭解析。