From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34871) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YXVnd-00056B-30 for qemu-devel@nongnu.org; Mon, 16 Mar 2015 10:15:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YXVnT-0003Fd-6c for qemu-devel@nongnu.org; Mon, 16 Mar 2015 10:15:21 -0400 Received: from relay-05.andrew.cmu.edu ([128.2.157.12]:47907 helo=relay.andrew.cmu.edu) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YXVnT-0003Eu-22 for qemu-devel@nongnu.org; Mon, 16 Mar 2015 10:15:11 -0400 From: "Gabriel L. Somlo" Date: Mon, 16 Mar 2015 10:15:05 -0400 Message-Id: <1426515305-17766-7-git-send-email-somlo@cmu.edu> In-Reply-To: <1426515305-17766-1-git-send-email-somlo@cmu.edu> References: <1426515305-17766-1-git-send-email-somlo@cmu.edu> Subject: [Qemu-devel] [PATCH 6/6] qga: RFC: guest-side retrieval of fw_cfg file List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: matt.fleming@intel.com, rjones@redhat.com, jordan.l.justen@intel.com, gleb@cloudius-systems.com, mdroth@linux.vnet.ibm.com, gsomlo@gmail.com, kraxel@redhat.com, pbonzini@redhat.com, lersek@redhat.com Add -g (--get-fwcfg) client-mode option to qemu-ga, causing the named fw_cfg file to be retrieved and written to stdout. Signed-off-by: Gabriel Somlo --- First off, I have NOT forgotten the suggestion to make this a standalone binary, and will do so when I submit it "for real". It's just more comfortable this way for quick-n-dirty testing :) Two main issues I need help with before this would be ready to go upstream: 1. I can't for the life of me figure out how to stop gcc -O2 from assuming the if() test below is ALWAYS FALSE, and thus optimizing it out completely. For now I've forced -O0 on the entire function, but for some reason fw_cfg_read(&fcfile, ...) does not appear to count as potentially modifying fcfile... 2. I'm toying with the idea of writing a kernel driver for fw_cfg and thus having all this functionality reduced to "cat /sys/firmware/fw_cfg/ | grep " :) Of course, I have no idea how that would work on Windows, so maybe a binary spitting out a file is still the more portable way to go. (not to mention that most of the code for that is already written below). Thanks much for any additional clue... Gabriel qga/Makefile.objs | 1 + qga/get-fwcfg.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/guest-agent-core.h | 2 ++ qga/main.c | 6 +++- 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 qga/get-fwcfg.c diff --git a/qga/Makefile.objs b/qga/Makefile.objs index 1c5986c..ef53841 100644 --- a/qga/Makefile.objs +++ b/qga/Makefile.objs @@ -4,5 +4,6 @@ qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o qga-obj-$(CONFIG_WIN32) += vss-win32.o qga-obj-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o qga-obj-y += qapi-generated/qga-qmp-marshal.o +qga-obj-y += get-fwcfg.o qga-vss-dll-obj-$(CONFIG_QGA_VSS) += vss-win32/ diff --git a/qga/get-fwcfg.c b/qga/get-fwcfg.c new file mode 100644 index 0000000..1928698 --- /dev/null +++ b/qga/get-fwcfg.c @@ -0,0 +1,92 @@ +/* + * QEMU Guest Agent: retrieve blob from fw_cfg device by name + * + * Copyright Carnegie Mellon University 2015 + * + * Author: + * Gabriel L. Somlo + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include +#include +#include +#include +#include +#include "qemu/bswap.h" +#include "hw/nvram/fw_cfg.h" +#include "qga/guest-agent-core.h" + +#define PORT_FW_CFG_CTL 0x0510 +#define PORT_FW_CFG_DATA 0x0511 + +static void +fw_cfg_select(uint16_t f) +{ + outw(f, PORT_FW_CFG_CTL); +} + +static void +fw_cfg_read(void *buf, int len) +{ + insb(PORT_FW_CFG_DATA, buf, len); +} + +static void +fw_cfg_read_entry(void *buf, int e, int len) +{ + fw_cfg_select(e); + fw_cfg_read(buf, len); +} + +int +__attribute__((optimize("O0"))) //FIXME: "gcc -O2" wrongfully optimizes "if"!!! +ga_get_fwcfg(const char *filename) +{ + int i; + uint32_t count, len = 0; + uint16_t sel; + uint8_t sig[] = "QEMU"; + FWCfgFile fcfile; + void *buf; + + /* ensure access to the fw_cfg device */ + if (ioperm(PORT_FW_CFG_CTL, 2, 1) != 0) { + perror("ioperm failed"); + return EXIT_FAILURE; + } + + /* verify presence of fw_cfg device */ + fw_cfg_select(FW_CFG_SIGNATURE); + for (i = 0; i < sizeof(sig) - 1; i++) { + sig[i] = inb(PORT_FW_CFG_DATA); + } + if (memcmp(sig, "QEMU", sizeof(sig)) != 0) { + fprintf(stderr, "fw_cfg signature not found!\n"); + return EXIT_FAILURE; + } + + /* read number of fw_cfg entries, then scan for requested entry by name */ + fw_cfg_read_entry(&count, FW_CFG_FILE_DIR, sizeof(count)); + count = be32_to_cpu(count); + for (i = 0; i < count; i++) { + fw_cfg_read(&fcfile, sizeof(fcfile)); + //FIXME: why does gcc -O2 optimize away the whole if {} block below?!? + if (!strcmp(fcfile.name, filename)) { + len = be32_to_cpu(fcfile.size); + sel = be16_to_cpu(fcfile.select); + buf = g_malloc(len); + fw_cfg_read_entry(buf, sel, len); + if (write(STDOUT_FILENO, buf, len) != len) { + fprintf(stderr, "Failed to write %s to stdout\n", filename); + return EXIT_FAILURE; + } + return 0;; + } + } + + /* requested entry not present in fw_cfg */ + fprintf(stderr, "File %s not found in fw_cfg!\n", filename); + return EXIT_FAILURE; +} diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index e92c6ab..b859e08 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -41,3 +41,5 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp); #ifndef _WIN32 void reopen_fd_to_null(int fd); #endif + +int ga_get_fwcfg(const char *file); diff --git a/qga/main.c b/qga/main.c index 9939a2b..f9c1ece 100644 --- a/qga/main.c +++ b/qga/main.c @@ -215,6 +215,7 @@ static void usage(const char *cmd) #endif " -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n" " to list available RPCs)\n" +" -g, --get-fwcfg dump the content of a given fw_cfg file to stdout\n" " -h, --help display this help and exit\n" "\n" "Report bugs to \n" @@ -923,7 +924,7 @@ static void ga_print_cmd(QmpCommand *cmd, void *opaque) int main(int argc, char **argv) { - const char *sopt = "hVvdm:p:l:f:F::b:s:t:"; + const char *sopt = "hVvdm:p:l:f:F::b:s:t:g:"; const char *method = NULL, *path = NULL; const char *log_filepath = NULL; const char *pid_filepath; @@ -951,6 +952,7 @@ int main(int argc, char **argv) { "service", 1, NULL, 's' }, #endif { "statedir", 1, NULL, 't' }, + { "get-fwcfg", 1, NULL, 'g' }, { NULL, 0, NULL, 0 } }; int opt_ind = 0, ch, daemonize = 0, i, j, len; @@ -1042,6 +1044,8 @@ int main(int argc, char **argv) } break; #endif + case 'g': + return ga_get_fwcfg(optarg); case 'h': usage(argv[0]); return 0; -- 2.1.0