qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 6/6] qga: RFC: guest-side retrieval of fw_cfg file


From: Gabriel L. Somlo
Subject: [Qemu-devel] [PATCH 6/6] qga: RFC: guest-side retrieval of fw_cfg file
Date: Mon, 16 Mar 2015 10:15:05 -0400

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 <address@hidden>
---

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/<filename> | grep <something>" :)

     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  <address@hidden>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/io.h>
+#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 <address@hidden>\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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]