From patchwork Wed Apr 29 15:21:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gabriel L. Somlo" X-Patchwork-Id: 466154 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D651C1402BC for ; Thu, 30 Apr 2015 01:22:39 +1000 (AEST) Received: from localhost ([::1]:39608 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnToq-0000qH-QT for incoming@patchwork.ozlabs.org; Wed, 29 Apr 2015 11:22:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35516) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnToG-0008FF-U4 for qemu-devel@nongnu.org; Wed, 29 Apr 2015 11:22:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YnToC-0002yw-AV for qemu-devel@nongnu.org; Wed, 29 Apr 2015 11:22:00 -0400 Received: from relay-06.andrew.cmu.edu ([128.2.157.21]:36065 helo=relay.andrew.cmu.edu) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YnToC-0002yi-54 for qemu-devel@nongnu.org; Wed, 29 Apr 2015 11:21:56 -0400 Received: from HEDWIG.ini.cmu.edu (HEDWIG.INI.CMU.EDU [128.2.16.51]) by relay.andrew.cmu.edu (8.14.8/8.14.8) with ESMTP id t3TFLrtI010842; Wed, 29 Apr 2015 11:21:54 -0400 From: "Gabriel L. Somlo" To: qemu-devel@nongnu.org Date: Wed, 29 Apr 2015 11:21:53 -0400 Message-Id: <1430320913-20737-5-git-send-email-somlo@cmu.edu> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1430320913-20737-1-git-send-email-somlo@cmu.edu> References: <1430320913-20737-1-git-send-email-somlo@cmu.edu> X-Scanned-By: MIMEDefang 2.74 on 128.2.157.21 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x X-Received-From: 128.2.157.21 Cc: gsomlo@gmail.com, matt.fleming@intel.com, lersek@redhat.com, kraxel@redhat.com, mst@redhat.com Subject: [Qemu-devel] [PATCH V4 4/4] fw_cfg: insert fw_cfg file blobs via qemu cmdline X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Reviewed-by: Laszlo Ersek --- docs/specs/fw_cfg.txt | 21 +++++++++++++++++ qemu-options.hx | 11 +++++++++ vl.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt index 6accd92..74351dd 100644 --- a/docs/specs/fw_cfg.txt +++ b/docs/specs/fw_cfg.txt @@ -203,3 +203,24 @@ completes fully overwriting the item's data. NOTE: This function is deprecated, and will be completely removed 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=],file= + +where is the fw_cfg item name, and 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(). diff --git a/qemu-options.hx b/qemu-options.hx index 319d971..aa386b4 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2668,6 +2668,17 @@ STEXI @table @option ETEXI +DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg, + "-fw_cfg [name=],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, \ "-serial dev redirect the serial port to char device 'dev'\n", QEMU_ARCH_ALL) diff --git a/vl.c b/vl.c index 74c2681..b02b2d4 100644 --- a/vl.c +++ b/vl.c @@ -490,6 +490,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 * @@ -2118,6 +2137,38 @@ char *qemu_find_file(int type, const char *name) return NULL; } +static int parse_fw_cfg(QemuOpts *opts, void *opaque) +{ + 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(QemuOpts *opts, void *opaque) { return qdev_device_help(opts); @@ -2806,6 +2857,7 @@ int main(int argc, char **argv, char **envp) 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); runstate_init(); @@ -3422,6 +3474,12 @@ int main(int argc, char **argv, char **envp) } do_smbios_option(opts); 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: olist = qemu_find_opts("machine"); qemu_opts_parse(olist, "accel=kvm", 0); @@ -4233,6 +4291,11 @@ int main(int argc, char **argv, char **envp) numa_post_machine_init(); + if (qemu_opts_foreach(qemu_find_opts("fw_cfg"), + parse_fw_cfg, fw_cfg_find(), 1) != 0) { + exit(1); + } + /* init USB devices */ if (usb_enabled()) { if (foreach_device_config(DEV_USB, usb_parse) < 0)