fw_cfg: insert fw_cfg file blobs via qemu cmdline
Allow user supplied files to be inserted into the fw_cfg device before starting the guest. Since fw_cfg_add_file() already disallows duplicate fw_cfg file names, qemu will exit with an error message if the user supplies multiple blobs with the same fw_cfg file name, or if a blob name collides with a fw_cfg name programmatically added from within the QEMU source code. A warning message will be printed if the fw_cfg item name does not begin with the prefix "opt/", which is recommended for external, user provided blobs. Signed-off-by: Gabriel Somlo <somlo@cmu.edu> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
0eb973f915
commit
81b2b81062
@ -203,3 +203,24 @@ completes fully overwriting the item's data.
|
|||||||
|
|
||||||
NOTE: This function is deprecated, and will be completely removed
|
NOTE: This function is deprecated, and will be completely removed
|
||||||
starting with QEMU v2.4.
|
starting with QEMU v2.4.
|
||||||
|
|
||||||
|
== Externally Provided Items ==
|
||||||
|
|
||||||
|
As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
|
||||||
|
FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
|
||||||
|
directory structure) may be inserted via the QEMU command line, using
|
||||||
|
the following syntax:
|
||||||
|
|
||||||
|
-fw_cfg [name=]<item_name>,file=<path>
|
||||||
|
|
||||||
|
where <item_name> is the fw_cfg item name, and <path> is the location
|
||||||
|
on the host file system of a file containing the data to be inserted.
|
||||||
|
|
||||||
|
NOTE: Users *SHOULD* choose item names beginning with the prefix "opt/"
|
||||||
|
when using the "-fw_cfg" command line option, to avoid conflicting with
|
||||||
|
item names used internally by QEMU. For instance:
|
||||||
|
|
||||||
|
-fw_cfg name=opt/my_item_name,file=./my_blob.bin
|
||||||
|
|
||||||
|
Similarly, QEMU developers *SHOULD NOT* use item names prefixed with
|
||||||
|
"opt/" when inserting items programmatically, e.g. via fw_cfg_add_file().
|
||||||
|
@ -2686,6 +2686,17 @@ STEXI
|
|||||||
@table @option
|
@table @option
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
|
DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg,
|
||||||
|
"-fw_cfg [name=]<name>,file=<file>\n"
|
||||||
|
" add named fw_cfg entry from file\n",
|
||||||
|
QEMU_ARCH_ALL)
|
||||||
|
STEXI
|
||||||
|
@item -fw_cfg [name=]@var{name},file=@var{file}
|
||||||
|
@findex -fw_cfg
|
||||||
|
Add named fw_cfg entry from file. @var{name} determines the name of
|
||||||
|
the entry in the fw_cfg file directory exposed to the guest.
|
||||||
|
ETEXI
|
||||||
|
|
||||||
DEF("serial", HAS_ARG, QEMU_OPTION_serial, \
|
DEF("serial", HAS_ARG, QEMU_OPTION_serial, \
|
||||||
"-serial dev redirect the serial port to char device 'dev'\n",
|
"-serial dev redirect the serial port to char device 'dev'\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
63
vl.c
63
vl.c
@ -492,6 +492,25 @@ static QemuOptsList qemu_semihosting_config_opts = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QemuOptsList qemu_fw_cfg_opts = {
|
||||||
|
.name = "fw_cfg",
|
||||||
|
.implied_opt_name = "name",
|
||||||
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_fw_cfg_opts.head),
|
||||||
|
.desc = {
|
||||||
|
{
|
||||||
|
.name = "name",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Sets the fw_cfg name of the blob to be inserted",
|
||||||
|
}, {
|
||||||
|
.name = "file",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "Sets the name of the file from which\n"
|
||||||
|
"the fw_cfg blob will be loaded",
|
||||||
|
},
|
||||||
|
{ /* end of list */ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get machine options
|
* Get machine options
|
||||||
*
|
*
|
||||||
@ -2127,6 +2146,38 @@ char *qemu_find_file(int type, const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
||||||
|
{
|
||||||
|
gchar *buf;
|
||||||
|
size_t size;
|
||||||
|
const char *name, *file;
|
||||||
|
|
||||||
|
if (opaque == NULL) {
|
||||||
|
error_report("fw_cfg device not available");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
name = qemu_opt_get(opts, "name");
|
||||||
|
file = qemu_opt_get(opts, "file");
|
||||||
|
if (name == NULL || *name == '\0' || file == NULL || *file == '\0') {
|
||||||
|
error_report("invalid argument value");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) {
|
||||||
|
error_report("name too long (max. %d char)", FW_CFG_MAX_FILE_PATH - 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strncmp(name, "opt/", 4) != 0) {
|
||||||
|
error_report("WARNING: externally provided fw_cfg item names "
|
||||||
|
"should be prefixed with \"opt/\"!");
|
||||||
|
}
|
||||||
|
if (!g_file_get_contents(file, &buf, &size, NULL)) {
|
||||||
|
error_report("can't load %s", file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fw_cfg_add_file((FWCfgState *)opaque, name, buf, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int device_help_func(void *opaque, QemuOpts *opts, Error **errp)
|
static int device_help_func(void *opaque, QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
return qdev_device_help(opts);
|
return qdev_device_help(opts);
|
||||||
@ -2822,6 +2873,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
qemu_add_opts(&qemu_numa_opts);
|
qemu_add_opts(&qemu_numa_opts);
|
||||||
qemu_add_opts(&qemu_icount_opts);
|
qemu_add_opts(&qemu_icount_opts);
|
||||||
qemu_add_opts(&qemu_semihosting_config_opts);
|
qemu_add_opts(&qemu_semihosting_config_opts);
|
||||||
|
qemu_add_opts(&qemu_fw_cfg_opts);
|
||||||
|
|
||||||
runstate_init();
|
runstate_init();
|
||||||
|
|
||||||
@ -3438,6 +3490,12 @@ int main(int argc, char **argv, char **envp)
|
|||||||
}
|
}
|
||||||
do_smbios_option(opts);
|
do_smbios_option(opts);
|
||||||
break;
|
break;
|
||||||
|
case QEMU_OPTION_fwcfg:
|
||||||
|
opts = qemu_opts_parse(qemu_find_opts("fw_cfg"), optarg, 1);
|
||||||
|
if (opts == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case QEMU_OPTION_enable_kvm:
|
case QEMU_OPTION_enable_kvm:
|
||||||
olist = qemu_find_opts("machine");
|
olist = qemu_find_opts("machine");
|
||||||
qemu_opts_parse(olist, "accel=kvm", 0);
|
qemu_opts_parse(olist, "accel=kvm", 0);
|
||||||
@ -4274,6 +4332,11 @@ int main(int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
numa_post_machine_init();
|
numa_post_machine_init();
|
||||||
|
|
||||||
|
if (qemu_opts_foreach(qemu_find_opts("fw_cfg"),
|
||||||
|
parse_fw_cfg, fw_cfg_find(), NULL) != 0) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* init USB devices */
|
/* init USB devices */
|
||||||
if (usb_enabled()) {
|
if (usb_enabled()) {
|
||||||
if (foreach_device_config(DEV_USB, usb_parse) < 0)
|
if (foreach_device_config(DEV_USB, usb_parse) < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user