All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel
@ 2011-09-29 13:47 Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 1/5] backdoor: Add documentation Lluís Vilanova
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

Provides the ability for the guest to communicate with user-provided code inside
QEMU itself, using a lightweight mechanism.

See first commit for a full description.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---

Lluís Vilanova (5):
      backdoor: Add documentation
      backdoor: Add build infrastructure
      backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a"
      backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
      backdoor: Add guest-side library


 Makefile                       |    3 -
 Makefile.objs                  |   21 ++++
 Makefile.target                |    4 +
 backdoor/guest/Makefile        |   18 ++++
 backdoor/guest/common.c        |  130 +++++++++++++++++++++++++++
 backdoor/guest/qemu-backdoor.h |   50 ++++++++++
 backdoor/qemu/qemu-backdoor.h  |   29 ++++++
 backdoor/qemu/softmmu.c        |  124 ++++++++++++++++++++++++++
 backdoor/qemu/user.c           |  194 ++++++++++++++++++++++++++++++++++++++++
 backdoor/qemu/user.h           |   17 ++++
 bsd-user/main.c                |   25 +++++
 bsd-user/mmap.c                |    7 +
 configure                      |   35 +++++++
 darwin-user/main.c             |   25 +++++
 darwin-user/mmap.c             |    7 +
 docs/backdoor.txt              |  144 ++++++++++++++++++++++++++++++
 hw/pci.h                       |    1 
 linux-user/main.c              |   30 ++++++
 linux-user/mmap.c              |    7 +
 19 files changed, 869 insertions(+), 2 deletions(-)
 create mode 100644 backdoor/guest/Makefile
 create mode 100644 backdoor/guest/common.c
 create mode 100644 backdoor/guest/qemu-backdoor.h
 create mode 100644 backdoor/qemu/qemu-backdoor.h
 create mode 100644 backdoor/qemu/softmmu.c
 create mode 100644 backdoor/qemu/user.c
 create mode 100644 backdoor/qemu/user.h
 create mode 100644 docs/backdoor.txt

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 1/5] backdoor: Add documentation
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
@ 2011-09-29 13:47 ` Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure Lluís Vilanova
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 docs/backdoor.txt |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 144 insertions(+), 0 deletions(-)
 create mode 100644 docs/backdoor.txt

diff --git a/docs/backdoor.txt b/docs/backdoor.txt
new file mode 100644
index 0000000..3b26b70
--- /dev/null
+++ b/docs/backdoor.txt
@@ -0,0 +1,144 @@
+= Backdoor communication channel =
+
+== Introduction ==
+
+This document describes how the guest can use the backdoor communication channel
+to interact with user-provided code inside QEMU.
+
+The backdoor provides a lightweight and guest-initiated communication channel
+between code running inside the guest system and code in QEMU, including both
+QEMU in 'softmmu' and 'user' modes.
+
+The semantics of the backdoor channel are up to the user, who must provide the
+implementation of the QEMU-side callbacks used when the backdoor channel is
+invoked.
+
+On the guest side, code can simply link against a simple library provided in
+QEMU to interface with the backdoor channel.
+
+The features of this mechanism are:
+
+* Minimal setup for the guest.
+* Independent of guest architecture.
+* Works with 'softmmu' and 'user' mode.
+* Low overhead; capturing memory accesses to specific addresses does not go
+  through any OS abstraction, except during the setup of the communication
+  channel.
+
+
+== QEMU-side code ==
+
+1. Create the "Makefile" to build the user-provided backdoor channel library:
+
+    mkdir /tmp/my-backdoor-qemu
+    cat > /tmp/my-backdoor-qemu/Makefile <<EOF
+    include $(BUILD_DIR)/config-host.mak
+    include $(BUILD_DIR)/$(TARGET_DIR)../config-target.mak
+    include $(SRC_PATH)/rules.mak
+    
+    vpath %.c /tmp/my-backdoor-qemu
+    
+    
+    libbackdoor.a: backdoor.o
+    
+    
+    # Include automatically generated dependency files
+    -include $(wildcard *.d)
+    EOF
+
+2. Implement the callbacks declared in "backdoor/qemu/qemu-backdoor.h":
+
+    cat > /tmp/my-backdoor-qemu/backdoor.c <<EOF
+    #include "backdoor/qemu/qemu-backdoor.h"
+    
+    #include "cpu.h"
+    
+    #include <stdio.h>
+    
+    
+    void qemu_backdoor_init(uint64_t data_size)
+    {
+        printf("+ %ld\n", data_size);
+    }
+    
+    void qemu_backdoor(uint64_t cmd, void *data)
+    {
+        /* Perform any endianess-wise loads to interpret the data */
+        uint64_t d = ldq_p(data);
+        printf("-> %x :: %x\n", cmd, *(uint64_t*)data);
+    }
+    EOF
+
+3. Build QEMU with the backdoor feature:
+
+    /path/to/qemu/configure --with-backdoor=/tmp/my-backdoor-qemu
+
+
+== Guest-side code ==
+
+1. Compile the corresponding guest-side interface library:
+
+    make -C /path/to/qemu-build/x86_64-linux-user/backdoor/guest
+
+2. Create your own application to interact with the backdoor channel:
+
+    cat > /tmp/my-backdoor-guest.c <<EOF
+    #include <stdio.h>
+    #include <errno.h>
+    #include <stdlib.h>
+    #include <qemu-backdoor.h>
+    
+    
+    int main()
+    {
+        /* This base path is only applicable to 'user' mode */
+        if (qemu_backdoor_init("/tmp/backdoor") != 0) {
+            fprintf(stderr, "error: qemu_backdoor_init: %s\n", strerror(errno));
+            abort();
+        }
+    
+        /* Get a pointer to beginning of the data channel */
+        uint32_t * data = qemu_backdoor_data();
+        /* Write anything into the channel */
+        *data = 0xcafe;
+        /* Invoke the channel */
+        qemu_backdoor(0xbabe);
+    }
+    EOF
+
+3. Link your application against "libqemu-backdoor-guest.a":
+
+    gcc -o /tmp/my-backdoor-guest /tmp/my-backdoor-guest.c /path/to/qemu-build/x86_64-linux-user/backdoor/guest/libqemu-backdoor-guest.a
+
+
+== Running QEMU ==
+
+If you want to use QEMU's 'softmmu' mode:
+
+    /path/to/qemu-build/x86_64-softmmu/qemu-system-x86_64 -device backdoor
+    sudo /tmp/my-backdoor-guest # inside the VM
+
+If you want to use QEMU's 'user' mode:
+
+    /path/to/qemu-build/x86_64-linux-user/qemu-x86_64 -backdoor /tmp/backdoor /tmp/my-backdoor-guest
+
+
+== Implementation details ==
+
+The backdoor channel is composed of two channels that are handled as 'mmap'ed
+files. The data channel is used to contain arbitrary data to communicate back
+and forth between the guest and QEMU. The control channel is used by the guest
+to signal that the data channel is ready to be used.
+
+When using the 'softmmu' mode, the backdoor communication channels are provided
+as a virtual device used through MMIO. The data channel acts as regular memory
+and the control channel intercepts all accesses to it to proxy them to the
+user-provided backdoor library.
+
+When using the 'user' mode, the backdoor communication channels are provided as
+regular files in the host system that the guest must 'mmap' into its address
+space. The data channel acts as regular memory and the 'mmap' of the control
+channel is intercepted in QEMU to establish if it's an 'mmap' for the control
+channel file. If that's the case, the memory that QEMU allocates for the guest
+is 'mprotect'ed to intercept all accesses to it performed by the guest and proxy
+them to the user-provided backdoor library.

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 1/5] backdoor: Add documentation Lluís Vilanova
@ 2011-09-29 13:47 ` Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a" Lluís Vilanova
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 Makefile                      |    3 ++-
 Makefile.objs                 |   18 ++++++++++++++++++
 Makefile.target               |    4 +++-
 backdoor/qemu/qemu-backdoor.h |   29 +++++++++++++++++++++++++++++
 configure                     |   32 ++++++++++++++++++++++++++++++++
 5 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 backdoor/qemu/qemu-backdoor.h

diff --git a/Makefile b/Makefile
index 6ed3194..fd7d9d9 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,8 @@ else
 DOCS=
 endif
 
-SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
+SUBDIR_MAKEFLAGS_=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
+SUBDIR_MAKEFLAGS=$(SUBDIR_MAKEFLAGS_) SUBDIR_MAKEFLAGS="$(SUBDIR_MAKEFLAGS_)"
 SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
 SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 
diff --git a/Makefile.objs b/Makefile.objs
index 1c65087..2493e59 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -395,6 +395,24 @@ trace-obj-y += $(addprefix trace/, $(trace-nested-y))
 $(trace-obj-y): $(GENERATED_HEADERS)
 
 ######################################################################
+# backdoor
+
+backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y))
+
+ifdef CONFIG_BACKDOOR
+LIBBACKDOOR = libbackdoor/libbackdoor.a
+
+.PHONY: force
+force:
+
+$(LIBBACKDOOR): $(dir $(LIBBACKDOOR))/Makefile force
+	$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@)	\
+		QEMU_CFLAGS="$(QEMU_CFLAGS)"				\
+		TARGET_DIR="$(TARGET_DIR)$(dir $@)/" VPATH="$(VPATH)"	\
+		SRC_PATH="$(SRC_PATH)" V="$(V)" "$(notdir $@)")
+endif
+
+######################################################################
 # smartcard
 
 libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
diff --git a/Makefile.target b/Makefile.target
index b00ff4e..565d0a8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -79,6 +79,8 @@ libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
 
 libobj-y += disas.o
 
+libobj-$(CONFIG_BACKDOOR) += $(backdoor-obj-y)
+
 $(libobj-y): $(GENERATED_HEADERS)
 
 # libqemu
@@ -397,7 +399,7 @@ endif # CONFIG_LINUX_USER
 
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
-$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(LIBBACKDOOR)
 	$(call LINK,$^)
 
 
diff --git a/backdoor/qemu/qemu-backdoor.h b/backdoor/qemu/qemu-backdoor.h
new file mode 100644
index 0000000..95cb53f
--- /dev/null
+++ b/backdoor/qemu/qemu-backdoor.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU-side user-provided callbacks for the backdoor communication channel.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+
+/* Initialize the backdoor channel.
+ *
+ * @param data_size Size of the data channel.
+ */
+void qemu_backdoor_init(uint64_t data_size);
+
+/* Handle an invocation of the backdoor channel.
+ *
+ * The command argument can be used to achieve concurrency among different
+ * clients (e.g., threads in the guest system) of the backdoor channel (e.g.,
+ * different clients write to different parts of the data channel).
+ *
+ * @param cmd  Command to invoke.
+ * @param data Pointer to the beginning of the data channel.
+ */
+void qemu_backdoor(uint64_t cmd, void *data);
diff --git a/configure b/configure
index 24b8df4..e2be271 100755
--- a/configure
+++ b/configure
@@ -174,6 +174,7 @@ user_pie="no"
 zero_malloc=""
 trace_backend="nop"
 trace_file="trace"
+backdoor=""
 spice=""
 rbd=""
 smartcard=""
@@ -540,6 +541,8 @@ for opt do
   ;;
   --with-trace-file=*) trace_file="$optarg"
   ;;
+  --with-backdoor=*) backdoor="$optarg"
+  ;;
   --enable-gprof) gprof="yes"
   ;;
   --static)
@@ -1037,6 +1040,7 @@ echo "  --enable-trace-backend=B Set trace backend"
 echo "                           Available backends:" $("$source_path"/scripts/tracetool --list-backends)
 echo "  --with-trace-file=NAME   Full PATH,NAME of file to store traces"
 echo "                           Default:trace-<pid>"
+echo "  --with-backdoor=PATH     Directory to build user-provided backdoor library"
 echo "  --disable-spice          disable spice"
 echo "  --enable-spice           enable spice"
 echo "  --enable-rbd             enable building the rados block device (rbd)"
@@ -2514,6 +2518,20 @@ if test "$trace_backend" = "dtrace"; then
 fi
 
 ##########################################
+# check for a valid directory for backdoor
+if test -n "$backdoor"; then
+    if test ! -f "$backdoor/Makefile"; then
+        echo
+        echo "Error: cannot make into '$backdoor'"
+        echo "Please choose a directory where I can run 'make'"
+        echo
+        exit 1
+    fi
+    backdoor=`readlink -f "$backdoor"`
+fi
+
+
+##########################################
 # __sync_fetch_and_and requires at least -march=i486. Many toolchains
 # use i686 as default anyway, but for those that don't, an explicit
 # specification is necessary
@@ -2707,6 +2725,9 @@ echo "uuid support      $uuid"
 echo "vhost-net support $vhost_net"
 echo "Trace backend     $trace_backend"
 echo "Trace output file $trace_file-<pid>"
+if test -n "$backdoor"; then
+    echo "Backdoor lib dir  $backdoor"
+fi
 echo "spice support     $spice"
 echo "rbd support       $rbd"
 echo "xfsctl support    $xfs"
@@ -3072,6 +3093,13 @@ if test "$trace_default" = "yes"; then
   echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
 fi
 
+# backdoor channel
+if test -n "$backdoor"; then
+  echo "CONFIG_BACKDOOR=y" >> $config_host_mak
+  echo "BACKDOOR_PATH=\"$backdoor\"" >> $config_host_mak
+  QEMU_CFLAGS="-I\"$backdoor\" $QEMU_CFLAGS"
+fi
+
 echo "TOOLS=$tools" >> $config_host_mak
 echo "ROMS=$roms" >> $config_host_mak
 echo "MAKE=$make" >> $config_host_mak
@@ -3185,6 +3213,10 @@ if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$targ
   mkdir -p $target_dir/nwfpe
 fi
 symlink $source_path/Makefile.target $target_dir/Makefile
+if test -n "$backdoor"; then
+    mkdir -p $target_dir/libbackdoor
+    symlink $backdoor/Makefile $target_dir/libbackdoor/Makefile
+fi
 
 
 echo "# Automatically generated by configure - do not modify" > $config_target_mak

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 1/5] backdoor: Add documentation Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure Lluís Vilanova
@ 2011-09-29 13:47 ` Lluís Vilanova
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] " Lluís Vilanova
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

QEMU detects when the guest uses 'mmap' on the control channel file, and then
uses 'mprotect' to detect accesses to it, which are redirected to the
user-provided "libbackdoor.a".

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 Makefile.objs        |    2 +
 backdoor/qemu/user.c |  194 ++++++++++++++++++++++++++++++++++++++++++++++++++
 backdoor/qemu/user.h |   17 ++++
 bsd-user/main.c      |   25 ++++++
 bsd-user/mmap.c      |    7 ++
 configure            |    1 
 darwin-user/main.c   |   25 ++++++
 darwin-user/mmap.c   |    7 ++
 linux-user/main.c    |   30 ++++++++
 linux-user/mmap.c    |    7 ++
 10 files changed, 315 insertions(+), 0 deletions(-)
 create mode 100644 backdoor/qemu/user.c
 create mode 100644 backdoor/qemu/user.h

diff --git a/Makefile.objs b/Makefile.objs
index 2493e59..d39074d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -397,6 +397,8 @@ $(trace-obj-y): $(GENERATED_HEADERS)
 ######################################################################
 # backdoor
 
+backdoor-nested-$(CONFIG_USER_ONLY) += user.o
+
 backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y))
 
 ifdef CONFIG_BACKDOOR
diff --git a/backdoor/qemu/user.c b/backdoor/qemu/user.c
new file mode 100644
index 0000000..a236ca5
--- /dev/null
+++ b/backdoor/qemu/user.c
@@ -0,0 +1,194 @@
+/*
+ * QEMU-side management of backdoor channels in user-level emulation.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 "backdoor/qemu/user.h"
+
+#include <sys/mman.h>
+
+#include "qemu-common.h"
+#include "backdoor/qemu/qemu-backdoor.h"
+
+
+static char *data_path = NULL;
+static char *control_path = NULL;
+static int data_fd = -1;
+static int control_fd = -1;
+
+static void *data = NULL;
+static void *qemu_control_0 = NULL;
+static void *qemu_control_1 = NULL;
+
+static struct stat control_fd_stat;
+
+struct sigaction segv_next;
+static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt);
+
+
+static void init_channel(const char *base, const char *suffix, size_t size,
+                                  char ** path, int *fd, void **addr)
+{
+    *path = g_malloc(strlen(base) + strlen(suffix) + 1);
+    sprintf(*path, "%s%s", base, suffix);
+
+    *fd = open(*path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+    if (*fd == -1) {
+        fprintf(stderr, "error: open(%s): %s\n", *path, strerror(errno));
+        abort();
+    }
+
+    off_t lres = lseek(*fd, size - 1, SEEK_SET);
+    if (lres == (off_t)-1) {
+        fprintf(stderr, "error: lseek(%s): %s\n", *path, strerror(errno));
+        abort();
+    }
+
+    char tmp;
+    ssize_t wres = write(*fd, &tmp, 1);
+    if (wres == -1) {
+        fprintf(stderr, "error: write(%s): %s\n", *path, strerror(errno));
+        abort();
+    }
+
+    if (addr) {
+        *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
+        if (*addr == MAP_FAILED) {
+            fprintf(stderr, "error: mmap(%s): %s\n", *path, strerror(errno));
+            abort();
+        }
+    }
+}
+
+void backdoor_init(const char *base, uint64_t data_size)
+{
+    if (base == NULL) {
+        return;
+    }
+
+    init_channel(base, "-data", data_size, &data_path, &data_fd, &data);
+    void *control;
+    init_channel(base, "-control", getpagesize() * 2, &control_path, &control_fd, &control);
+
+    /* store channel size in first 64bits; command goes into 2nd slot */
+    *(uint64_t*)control = data_size;
+
+    if (fstat(control_fd, &control_fd_stat) == -1) {
+        fprintf(stderr, "error: fstat(backdoor_control): %s\n", strerror(errno));
+        abort();
+    }
+
+    struct sigaction segv;
+    memset(&segv, 0, sizeof(segv));
+    segv.sa_sigaction = segv_handler;
+    segv.sa_flags = SA_SIGINFO | SA_RESTART;
+    sigemptyset(&segv.sa_mask);
+
+    if (sigaction(SIGSEGV, &segv, &segv_next) != 0) {
+        fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errno));
+        abort();
+    }
+
+    qemu_backdoor_init(data_size);
+}
+
+
+static void fini_channel(int *fd, char **path)
+{
+    if (*fd != -1) {
+        if (close(*fd) == -1) {
+            fprintf(stderr, "error: close: %s\n", strerror(errno));
+            abort();
+        }
+        if (unlink(*path) == -1) {
+            fprintf(stderr, "error: unlink(%s): %s\n", *path, strerror(errno));
+            abort();
+        }
+        *fd = -1;
+    }
+    if (*path != NULL) {
+        g_free(path);
+        *path =  NULL;
+    }
+}
+
+void backdoor_fini(void)
+{
+    static bool atexit_in = false;
+    if (atexit_in) {
+        return;
+    }
+    atexit_in = true;
+
+    if (sigaction(SIGSEGV, &segv_next, NULL) != 0) {
+        fprintf(stderr, "error: sigaction(SIGSEGV): %s\n", strerror(errno));
+        abort();
+    }
+    fini_channel(&data_fd, &data_path);
+    fini_channel(&control_fd, &control_path);
+}
+
+
+void backdoor_guest_mmap(int fd, void *qemu_addr)
+{
+    struct stat s;
+    if (fstat(fd, &s) != 0) {
+        return;
+    }
+
+    if (s.st_dev != control_fd_stat.st_dev ||
+        s.st_ino != control_fd_stat.st_ino) {
+        return;
+    }
+
+    qemu_control_0 = qemu_addr;
+    qemu_control_1 = qemu_control_0 + getpagesize();
+    if (mprotect(qemu_control_0, getpagesize(), PROT_READ) == -1) {
+        fprintf(stderr, "error: mprotect(backdoor_control): %s\n",
+                strerror(errno));
+        abort();
+    }
+}
+
+static void swap_control(void *from, void *to)
+{
+    if (mprotect(from, getpagesize(), PROT_READ | PROT_WRITE) == -1) {
+        fprintf(stderr, "error: mprotect(from): %s\n",
+                strerror(errno));
+        abort();
+    }
+    if (mprotect(to, getpagesize(), PROT_READ) == -1) {
+        fprintf(stderr, "error: mprotect(to): %s\n",
+                strerror(errno));
+        abort();
+    }
+}
+
+static void segv_handler(int signum, siginfo_t *siginfo, void *sigctxt)
+{
+    if (qemu_control_0 <= siginfo->si_addr &&
+        siginfo->si_addr < qemu_control_1) {
+
+        assert(((target_ulong)siginfo->si_addr % getpagesize()) == sizeof(uint64_t));
+        swap_control(qemu_control_0, qemu_control_1);
+
+    } else if (qemu_control_1 <= siginfo->si_addr &&
+               siginfo->si_addr < qemu_control_1 + getpagesize()) {
+
+        assert(((target_ulong)siginfo->si_addr % getpagesize()) == sizeof(uint64_t));
+        qemu_backdoor(((uint64_t*)qemu_control_0)[1], data);
+        swap_control(qemu_control_1, qemu_control_0);
+
+    } else {
+        /* proxy to next handler */
+        if (segv_next.sa_sigaction != NULL) {
+            segv_next.sa_sigaction(signum, siginfo, sigctxt);
+        } else if (segv_next.sa_handler != NULL) {
+            segv_next.sa_handler(signum);
+        }
+    }
+}
diff --git a/backdoor/qemu/user.h b/backdoor/qemu/user.h
new file mode 100644
index 0000000..1ecc8cd
--- /dev/null
+++ b/backdoor/qemu/user.h
@@ -0,0 +1,17 @@
+/*
+ * QEMU-side management of backdoor channels in user-level emulation.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+
+void backdoor_init(const char *base, uint64_t data_size);
+/** Check if this mmap is for the control channel and act accordingly. */
+void backdoor_guest_mmap(int fd, void *qemu_addr);
+void backdoor_fini(void);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index cc7d4a3..046ed87 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -33,6 +33,9 @@
 #include "tcg.h"
 #include "qemu-timer.h"
 #include "envlist.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
 
 #define DEBUG_LOGFILE "/tmp/qemu.log"
 
@@ -688,6 +691,11 @@ static void usage(void)
            "-B address        set guest_base address to address\n"
 #endif
            "-bsd type         select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
+#if defined(CONFIG_BACKDOOR)
+           "-backdoor path    base path to backdoor channel\n"
+           "-backdoor-pages value\n"
+           "                  number of pages for the backdoor data channel (default: 1)\n"
+#endif
            "\n"
            "Debug options:\n"
            "-d options   activate log (default logfile=%s)\n"
@@ -744,6 +752,10 @@ int main(int argc, char **argv)
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
     bsd_type = target_openbsd;
+#if defined(CONFIG_BACKDOOR)
+    char *backdoor_base = NULL;
+    uint64_t backdoor_size = getpagesize();
+#endif
 
     if (argc <= 1)
         usage();
@@ -851,6 +863,16 @@ int main(int argc, char **argv)
             singlestep = 1;
         } else if (!strcmp(r, "strace")) {
             do_strace = 1;
+#if defined(CONFIG_BACKDOOR)
+        } else if (!strcmp(r, "backdoor")) {
+            if (atexit(backdoor_fini) != 0) {
+                fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+                abort();
+            }
+            backdoor_base = argv[optind++];
+        } else if (!strcmp(r, "backdoor-pages")) {
+            backdoor_size = atoi(argv[optind++]) * getpagesize();
+#endif
         } else
         {
             usage();
@@ -988,6 +1010,9 @@ int main(int argc, char **argv)
     target_set_brk(info->brk);
     syscall_init();
     signal_init();
+#if defined(CONFIG_BACKDOOR)
+    backdoor_init(backdoor_base, backdoor_size);
+#endif
 
 #if defined(CONFIG_USE_GUEST_BASE)
     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 5d6cffc..afa57df 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -28,6 +28,10 @@
 #include "qemu-common.h"
 #include "bsd-mman.h"
 
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
 //#define DEBUG_MMAP
 
 #if defined(CONFIG_USE_NPTL)
@@ -473,6 +477,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
         }
     }
  the_end1:
+#if defined(CONFIG_BACKDOOR)
+    backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
     page_set_flags(start, start + len, prot | PAGE_VALID);
  the_end:
 #ifdef DEBUG_MMAP
diff --git a/configure b/configure
index e2be271..74a6f5a 100755
--- a/configure
+++ b/configure
@@ -3216,6 +3216,7 @@ symlink $source_path/Makefile.target $target_dir/Makefile
 if test -n "$backdoor"; then
     mkdir -p $target_dir/libbackdoor
     symlink $backdoor/Makefile $target_dir/libbackdoor/Makefile
+    mkdir -p $target_dir/backdoor/qemu
 fi
 
 
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 1a881a0..2b28e46 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -28,6 +28,9 @@
 #include <sys/mman.h>
 
 #include "qemu.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
 
 #define DEBUG_LOGFILE "/tmp/qemu.log"
 
@@ -713,6 +716,11 @@ static void usage(void)
            "-h           print this help\n"
            "-L path      set the %s library path (default='%s')\n"
            "-s size      set the stack size in bytes (default=%ld)\n"
+#if defined(CONFIG_BACKDOOR)
+           "-backdoor path    base path to backdoor channel\n"
+           "-backdoor-pages value\n"
+           "                  number of pages for the backdoor data channel (default: 1)\n"
+#endif
            "\n"
            "debug options:\n"
            "-d options   activate log (logfile='%s')\n"
@@ -747,6 +755,10 @@ int main(int argc, char **argv)
     short use_gdbstub = 0;
     const char *r;
     const char *cpu_model;
+#if defined(CONFIG_BACKDOOR)
+    char *backdoor_base = NULL;
+    uint64_t backdoor_size = getpagesize();
+#endif
 
     if (argc <= 1)
         usage();
@@ -804,6 +816,16 @@ int main(int argc, char **argv)
             }
         } else if (!strcmp(r, "singlestep")) {
             singlestep = 1;
+#if defined(CONFIG_BACKDOOR)
+        } else if (!strcmp(r, "backdoor")) {
+            if (atexit(backdoor_fini) != 0) {
+                fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+                abort();
+            }
+            backdoor_base = argv[optind++];
+        } else if (!strcmp(r, "backdoor-pages")) {
+            backdoor_size = atoi(argv[optind++]) * getpagesize();
+#endif
         } else
         {
             usage();
@@ -870,6 +892,9 @@ int main(int argc, char **argv)
 
     syscall_init();
     signal_init();
+#if defined(CONFIG_BACKDOOR)
+    backdoor_init(backdoor_base, backdoor_size);
+#endif
     global_env = env;
 
     /* build Task State */
diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c
index d840b28..047c5bf 100644
--- a/darwin-user/mmap.c
+++ b/darwin-user/mmap.c
@@ -26,6 +26,10 @@
 
 #include "qemu.h"
 
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
 //#define DEBUG_MMAP
 
 /* NOTE: all the constants are the HOST ones */
@@ -308,6 +312,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
             return ret;
     }
  the_end1:
+#if defined(CONFIG_BACKDOOR)
+    backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
     page_set_flags(start, start + len, prot | PAGE_VALID);
  the_end:
 #ifdef DEBUG_MMAP
diff --git a/linux-user/main.c b/linux-user/main.c
index 186358b..4d5ef97 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,6 +33,9 @@
 #include "tcg.h"
 #include "qemu-timer.h"
 #include "envlist.h"
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
 
 #define DEBUG_LOGFILE "/tmp/qemu.log"
 
@@ -50,6 +53,10 @@ unsigned long guest_base;
 int have_guest_base;
 unsigned long reserved_va;
 #endif
+#if defined(CONFIG_BACKDOOR)
+const char *backdoor_base = NULL;
+uint64_t backdoor_size;
+#endif
 
 static void usage(void);
 
@@ -3080,6 +3087,18 @@ static void handle_arg_strace(const char *arg)
     do_strace = 1;
 }
 
+#if defined(CONFIG_BACKDOOR)
+static void handle_arg_backdoor(const char *arg)
+{
+    backdoor_base = arg;
+}
+
+static void handle_arg_backdoor_pages(const char *arg)
+{
+    backdoor_size = atoi(arg) * getpagesize();
+}
+#endif
+
 static void handle_arg_version(const char *arg)
 {
     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
@@ -3120,6 +3139,12 @@ struct qemu_argument arg_table[] = {
     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
      "size",       "reserve 'size' bytes for guest virtual address space"},
 #endif
+#if defined(CONFIG_BACKDOOR)
+    {"backdoor",   "QEMU_BACKDOOR",    true,  handle_arg_backdoor,
+     "path",       "base path to backdoor channel\n"},
+    {"backdoor-pages", "QEMU_BACKDOOR_PAGES", true,  handle_arg_backdoor_pages,
+     "num",        "number of pages for the backdoor data channel (default: 1)\n"},
+#endif
     {"d",          "QEMU_LOG",         true,  handle_arg_log,
      "options",    "activate log"},
     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
@@ -3279,6 +3304,8 @@ int main(int argc, char **argv, char **envp)
     if (argc <= 1)
         usage();
 
+    backdoor_size = getpagesize();
+
     qemu_cache_utils_init(envp);
 
     if ((envlist = envlist_create()) == NULL) {
@@ -3511,6 +3538,9 @@ int main(int argc, char **argv, char **envp)
     target_set_brk(info->brk);
     syscall_init();
     signal_init();
+#if defined(CONFIG_BACKDOOR)
+    backdoor_init(backdoor_base, backdoor_size);
+#endif
 
 #if defined(CONFIG_USE_GUEST_BASE)
     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 994c02b..2232363 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -31,6 +31,10 @@
 #include "qemu.h"
 #include "qemu-common.h"
 
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/qemu/user.h"
+#endif
+
 //#define DEBUG_MMAP
 
 #if defined(CONFIG_USE_NPTL)
@@ -553,6 +557,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
         }
     }
  the_end1:
+#if defined(CONFIG_BACKDOOR)
+    backdoor_guest_mmap(fd, (void *)g2h(start));
+#endif
     page_set_flags(start, start + len, prot | PAGE_VALID);
  the_end:
 #ifdef DEBUG_MMAP

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
                   ` (2 preceding siblings ...)
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a" Lluís Vilanova
@ 2011-09-29 13:47 ` Lluís Vilanova
  2011-09-29 20:42   ` Blue Swirl
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 5/5] backdoor: Add guest-side library Lluís Vilanova
  2011-09-29 13:52 ` [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Anthony Liguori
  5 siblings, 1 reply; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

Uses a virtual device to proxy uses of the backdoor communication channel to the
user-provided code.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 Makefile.objs           |    1 
 backdoor/qemu/softmmu.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/pci.h                |    1 
 3 files changed, 126 insertions(+), 0 deletions(-)
 create mode 100644 backdoor/qemu/softmmu.c

diff --git a/Makefile.objs b/Makefile.objs
index d39074d..5f54d10 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -398,6 +398,7 @@ $(trace-obj-y): $(GENERATED_HEADERS)
 # backdoor
 
 backdoor-nested-$(CONFIG_USER_ONLY) += user.o
+backdoor-nested-$(CONFIG_SOFTMMU) += softmmu.o
 
 backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y))
 
diff --git a/backdoor/qemu/softmmu.c b/backdoor/qemu/softmmu.c
new file mode 100644
index 0000000..fdd3a25
--- /dev/null
+++ b/backdoor/qemu/softmmu.c
@@ -0,0 +1,124 @@
+/*
+ * QEMU-side management of backdoor channels in softmmu emulation.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 "hw/pci.h"
+#include "backdoor/qemu/qemu-backdoor.h"
+
+
+#define PAGE_SIZE TARGET_PAGE_SIZE
+#define CTRL_BYTES sizeof(uint64_t)
+
+
+typedef struct State
+{
+    PCIDevice dev;
+
+    uint8_t pages;
+    uint64_t size;
+
+    uint64_t cmd;
+
+    void *data_ptr;
+    MemoryRegion data;
+    MemoryRegion control;
+} State;
+
+
+static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    State *s = opaque;
+
+    uint64_t res = ldq_p(&s->size);
+    uint8_t *resb = (uint8_t*)&res;
+    return resb[addr % CTRL_BYTES];
+}
+
+static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
+{
+    State *s = opaque;
+
+    uint8_t *cmdb = (uint8_t*)&s->cmd;
+    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
+
+    if ((addr + size) % CTRL_BYTES == 0) {
+        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
+    }
+}
+
+static const MemoryRegionOps control_ops = {
+    .read = control_io_read,
+    .write = control_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+
+static int init(PCIDevice *dev)
+{
+    State *s = DO_UPCAST(State, dev, dev);
+
+    if (s->pages < 1) {
+        fprintf(stderr, "error: backdoor: "
+                "the data channel must have one or more pages\n");
+        return -1;
+    }
+    s->size = s->pages * PAGE_SIZE;
+
+    pci_set_word(s->dev.config + PCI_COMMAND,
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    memory_region_init_io(&s->control, &control_ops, s, "backdoor.control",
+                          PAGE_SIZE);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->control);
+
+    memory_region_init_ram(&s->data, &s->dev.qdev, "backdoor.data",
+                           s->size);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->data);
+    s->data_ptr = qemu_get_ram_ptr(s->data.ram_addr);
+
+    qemu_backdoor_init(s->size);
+
+    return 0;
+}
+
+static int fini(PCIDevice *dev)
+{
+    State *s = DO_UPCAST(State, dev, dev);
+
+    memory_region_destroy(&s->data);
+    memory_region_destroy(&s->control);
+
+    return 0;
+}
+
+
+static PCIDeviceInfo info = {
+    .qdev.name  = "backdoor",
+    .qdev.desc  = "Backdoor communication channel",
+    .qdev.size  = sizeof(State),
+    .init       = init,
+    .exit       = fini,
+    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
+    .device_id  = PCI_DEVICE_ID_BACKDOOR,
+    .class_id   = PCI_CLASS_MEMORY_RAM,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("pages", State, pages, 1),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void register_device(void)
+{
+    pci_qdev_register(&info);
+}
+
+device_init(register_device)
diff --git a/hw/pci.h b/hw/pci.h
index 86a81c8..4d7d161 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -75,6 +75,7 @@
 #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
 #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
 #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+#define PCI_DEVICE_ID_BACKDOOR           0x1004
 
 #define FMT_PCIBUS                      PRIx64
 

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH 5/5] backdoor: Add guest-side library
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
                   ` (3 preceding siblings ...)
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] " Lluís Vilanova
@ 2011-09-29 13:47 ` Lluís Vilanova
  2011-09-29 13:52 ` [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Anthony Liguori
  5 siblings, 0 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Zhi Yong Wu

Guest applications can link against "libqemu-backdoor-guest.a" to use the
backdoor communication channel.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 backdoor/guest/Makefile        |   18 ++++++
 backdoor/guest/common.c        |  130 ++++++++++++++++++++++++++++++++++++++++
 backdoor/guest/qemu-backdoor.h |   50 +++++++++++++++
 configure                      |    2 +
 4 files changed, 200 insertions(+), 0 deletions(-)
 create mode 100644 backdoor/guest/Makefile
 create mode 100644 backdoor/guest/common.c
 create mode 100644 backdoor/guest/qemu-backdoor.h

diff --git a/backdoor/guest/Makefile b/backdoor/guest/Makefile
new file mode 100644
index 0000000..200ee3b
--- /dev/null
+++ b/backdoor/guest/Makefile
@@ -0,0 +1,18 @@
+include ../../../config-host.mak
+include ../../config-target.mak
+include $(SRC_PATH)/rules.mak
+
+vpath % $(SRC_PATH)/backdoor/guest
+
+QEMU_CFLAGS += $(GLIB_CFLAGS)
+QEMU_CFLAGS += -I../../../
+QEMU_CFLAGS += -I../../
+
+obj-y = common.o
+
+libqemu-backdoor-guest.a: $(obj-y)
+
+all: libqemu-backdoor-guest.a
+
+clean:
+	rm -f $(obj-y) libqemu-backdoor-guest.a
diff --git a/backdoor/guest/common.c b/backdoor/guest/common.c
new file mode 100644
index 0000000..7b4354f
--- /dev/null
+++ b/backdoor/guest/common.c
@@ -0,0 +1,130 @@
+/*
+ * Guest-side management of backdoor channels.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 "qemu-backdoor.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "config-target.h"
+
+
+static char *data_path = NULL;
+static char *control_path = NULL;
+static int data_fd = -1;
+static int control_fd = -1;
+
+static void *data_addr = NULL;
+static void *control_addr = NULL;
+
+
+static int init_channel_file(const char *base, const char *suffix, size_t size,
+                             char ** path, int *fd, void **addr)
+{
+    *path = malloc(strlen(base) + strlen(suffix) + 1);
+    sprintf(*path, "%s%s", base, suffix);
+
+    *fd = open(*path, O_RDWR);
+    if (*fd == -1) {
+        return -1;
+    }
+
+    *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
+    if (*addr == MAP_FAILED) {
+        return -1;
+    }
+    return 0;
+}
+
+int qemu_backdoor_init(const char *base)
+{
+#if defined(CONFIG_USER_ONLY)
+    const char *control_suff = "-control";
+    const size_t control_size = getpagesize() * 2;
+    const char *data_suff = "-data";
+#elif defined(__linux__)
+    const char *control_suff = "/resource0";
+    const size_t control_size = getpagesize();
+    const char *data_suff = "/resource1";
+#else
+#error Unsupported OS
+#endif
+
+    int res;
+    res = init_channel_file(base, control_suff, control_size,
+                            &control_path, &control_fd, &control_addr);
+    if (res != 0) {
+        return res;
+    }
+
+    res = init_channel_file(base, data_suff, qemu_backdoor_data_size(),
+                            &data_path, &data_fd, &data_addr);
+    if (res != 0) {
+        return res;
+    }
+    return 0;
+}
+
+
+static int fini_channel(int *fd, char **path)
+{
+    if (*fd != -1) {
+        if (close(*fd) == -1) {
+            return -1;
+        }
+        *fd = -1;
+    }
+    if (*path != NULL) {
+        free(path);
+        *path =  NULL;
+    }
+    return 0;
+}
+
+int qemu_backdoor_fini(void)
+{
+    if (fini_channel(&data_fd, &data_path) != 0) {
+        return -1;
+    }
+    if (fini_channel(&control_fd, &control_path) != 0) {
+        return -1;
+    }
+    return 0;
+}
+
+
+uint64_t qemu_backdoor_data_size(void)
+{
+    return *(uint64_t*)control_addr;
+}
+
+void *qemu_backdoor_data(void)
+{
+    return data_addr;
+}
+
+void qemu_backdoor (uint64_t cmd)
+{
+    uint64_t *ctrl;
+    ctrl = control_addr;
+    ctrl[1] = cmd;
+#if defined(CONFIG_USER_ONLY)
+    /* QEMU in 'user' mode uses two faulting pages to detect invocations */
+    ctrl = control_addr + getpagesize();
+    ctrl[1] = cmd;
+#endif
+}
diff --git a/backdoor/guest/qemu-backdoor.h b/backdoor/guest/qemu-backdoor.h
new file mode 100644
index 0000000..99d4cb2
--- /dev/null
+++ b/backdoor/guest/qemu-backdoor.h
@@ -0,0 +1,50 @@
+/*
+ * Guest-side management of backdoor channels.
+ *
+ * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+
+/** Initialize the backdoor channel.
+ *
+ * The base path to the backdoor channel is dependant on the type of QEMU
+ * target:
+ *
+ * - User (single-application)
+ *   The base path provided when starting QEMU ("-backdoor" commandline option).
+ *
+ * - Softmmu (full-system); OS-dependant
+ *   - Linux: The base path to the backdoor channel virtual device ("-device
+ *     backdoor" commandline option).
+ *
+ * @param base Base path to the backdoor channel.
+ * @return Zero on success.
+ */
+int qemu_backdoor_init(const char *base);
+
+/** Deinitialize the backdoor channel.
+ *
+ * @return Zero on success.
+ */
+int qemu_backdoor_fini(void);
+
+/** The amount of data that can be passed through the data channel. */
+uint64_t qemu_backdoor_data_size(void);
+/** Pointer to the start of the data channel. */
+void *qemu_backdoor_data(void);
+
+/** Invoke the control channel.
+ *
+ * The command in the control channel can be used to, e.g., differentiate
+ * between multiple users of the backdoor channel without resorting to the data
+ * channel for deambiguation.
+ *
+ * @param cmd Integral number passed out-of-band w.r.t the data channel.
+ */
+void qemu_backdoor(uint64_t cmd);
diff --git a/configure b/configure
index 74a6f5a..e982787 100755
--- a/configure
+++ b/configure
@@ -3217,6 +3217,8 @@ if test -n "$backdoor"; then
     mkdir -p $target_dir/libbackdoor
     symlink $backdoor/Makefile $target_dir/libbackdoor/Makefile
     mkdir -p $target_dir/backdoor/qemu
+    mkdir -p $target_dir/backdoor/guest
+    symlink $source_path/backdoor/guest/Makefile $target_dir/backdoor/guest/Makefile
 fi
 
 

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel
  2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
                   ` (4 preceding siblings ...)
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 5/5] backdoor: Add guest-side library Lluís Vilanova
@ 2011-09-29 13:52 ` Anthony Liguori
  2011-09-29 17:10   ` Lluís Vilanova
  2011-09-29 20:55   ` Blue Swirl
  5 siblings, 2 replies; 17+ messages in thread
From: Anthony Liguori @ 2011-09-29 13:52 UTC (permalink / raw)
  To: Lluís Vilanova; +Cc: Zhi Yong Wu, qemu-devel

On 09/29/2011 08:47 AM, Lluís Vilanova wrote:
> Provides the ability for the guest to communicate with user-provided code inside
> QEMU itself, using a lightweight mechanism.
>
> See first commit for a full description.
>
> Signed-off-by: Lluís Vilanova<vilanova@ac.upc.edu>

We already have two "backdoors" in QEMU: ivshmem and virtio-serial.  Can you 
discuss why these are insufficient for your purposes?

Also, what's the advantage of having a backdoor mechanism both for softmmu and 
user?  I can't think of a practical use-case for it.

Regards,

Anthony Liguori

> ---
>
> Lluís Vilanova (5):
>        backdoor: Add documentation
>        backdoor: Add build infrastructure
>        backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a"
>        backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
>        backdoor: Add guest-side library
>
>
>   Makefile                       |    3 -
>   Makefile.objs                  |   21 ++++
>   Makefile.target                |    4 +
>   backdoor/guest/Makefile        |   18 ++++
>   backdoor/guest/common.c        |  130 +++++++++++++++++++++++++++
>   backdoor/guest/qemu-backdoor.h |   50 ++++++++++
>   backdoor/qemu/qemu-backdoor.h  |   29 ++++++
>   backdoor/qemu/softmmu.c        |  124 ++++++++++++++++++++++++++
>   backdoor/qemu/user.c           |  194 ++++++++++++++++++++++++++++++++++++++++
>   backdoor/qemu/user.h           |   17 ++++
>   bsd-user/main.c                |   25 +++++
>   bsd-user/mmap.c                |    7 +
>   configure                      |   35 +++++++
>   darwin-user/main.c             |   25 +++++
>   darwin-user/mmap.c             |    7 +
>   docs/backdoor.txt              |  144 ++++++++++++++++++++++++++++++
>   hw/pci.h                       |    1
>   linux-user/main.c              |   30 ++++++
>   linux-user/mmap.c              |    7 +
>   19 files changed, 869 insertions(+), 2 deletions(-)
>   create mode 100644 backdoor/guest/Makefile
>   create mode 100644 backdoor/guest/common.c
>   create mode 100644 backdoor/guest/qemu-backdoor.h
>   create mode 100644 backdoor/qemu/qemu-backdoor.h
>   create mode 100644 backdoor/qemu/softmmu.c
>   create mode 100644 backdoor/qemu/user.c
>   create mode 100644 backdoor/qemu/user.h
>   create mode 100644 docs/backdoor.txt
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel
  2011-09-29 13:52 ` [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Anthony Liguori
@ 2011-09-29 17:10   ` Lluís Vilanova
  2011-09-29 20:55   ` Blue Swirl
  1 sibling, 0 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 17:10 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Zhi Yong Wu, qemu-devel

Anthony Liguori writes:

> On 09/29/2011 08:47 AM, Lluís Vilanova wrote:
>> Provides the ability for the guest to communicate with user-provided code inside
>> QEMU itself, using a lightweight mechanism.
>> 
>> See first commit for a full description.
>> 
>> Signed-off-by: Lluís Vilanova<vilanova@ac.upc.edu>

> We already have two "backdoors" in QEMU: ivshmem and virtio-serial.  Can you
> discuss why these are insufficient for your purposes?

The main point is that I want the user to be able to provide (at compile time,
although it could also be done through dlopen or similar) her own implementation
of what to do immediately after the backdoor channel is invoked *and* to be able
to use QEMU internal routines from that code. I also want the mechanism to be as
lightweight as possible (i.e., no OS involvement through syscalls to use the
device); right now, channel invocation is reduced to just a single write to
memory.

Is this possible to achieve with virtio-serial or ivshmem? Maybe I just missed
the details in them that would allow me to do that without yet another device.


> Also, what's the advantage of having a backdoor mechanism both for softmmu and
> user?  I can't think of a practical use-case for it.

The intent is to have the same guest interface to interact with the
user-implemented backdoor code, regardless of which QEMU "mode" we're running on
(user or softmmu).

In the use-mode case, now I can link the application against the backdoor
interface library and add some calls to the backdoor in the points I'm
interested in. Then moving the app into softmmu would just work without further
changes (provided the guest uses the softmmu-capable version of the library).

The contents of the user implementation can be arbitrary, although my target is
to use it coupled together with the patchset for tracing guest code at the TCG
level (which I haven't sent yet in its new form). Thus you could add just a pair
of lines in the guest code to enable tracing of the executed guest instructions
only for whichever part of the program you're interested in.


Lluis

-- 
 "And it's much the same thing with knowledge, for whenever you learn
 something new, the whole world becomes that much richer."
 -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
 Tollbooth

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 13:47 ` [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] " Lluís Vilanova
@ 2011-09-29 20:42   ` Blue Swirl
  2011-09-29 21:49     ` Lluís Vilanova
  0 siblings, 1 reply; 17+ messages in thread
From: Blue Swirl @ 2011-09-29 20:42 UTC (permalink / raw)
  To: Lluís Vilanova; +Cc: Zhi Yong Wu, qemu-devel

2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
> Uses a virtual device to proxy uses of the backdoor communication channel to the
> user-provided code.
>
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  Makefile.objs           |    1
>  backdoor/qemu/softmmu.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/pci.h                |    1
>  3 files changed, 126 insertions(+), 0 deletions(-)
>  create mode 100644 backdoor/qemu/softmmu.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index d39074d..5f54d10 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -398,6 +398,7 @@ $(trace-obj-y): $(GENERATED_HEADERS)
>  # backdoor
>
>  backdoor-nested-$(CONFIG_USER_ONLY) += user.o
> +backdoor-nested-$(CONFIG_SOFTMMU) += softmmu.o
>
>  backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y))
>
> diff --git a/backdoor/qemu/softmmu.c b/backdoor/qemu/softmmu.c
> new file mode 100644
> index 0000000..fdd3a25
> --- /dev/null
> +++ b/backdoor/qemu/softmmu.c
> @@ -0,0 +1,124 @@
> +/*
> + * QEMU-side management of backdoor channels in softmmu emulation.
> + *
> + * Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu>
> + *
> + * 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 "hw/pci.h"
> +#include "backdoor/qemu/qemu-backdoor.h"
> +
> +
> +#define PAGE_SIZE TARGET_PAGE_SIZE
> +#define CTRL_BYTES sizeof(uint64_t)
> +
> +
> +typedef struct State
> +{
> +    PCIDevice dev;
> +
> +    uint8_t pages;
> +    uint64_t size;
> +
> +    uint64_t cmd;
> +
> +    void *data_ptr;
> +    MemoryRegion data;
> +    MemoryRegion control;
> +} State;

Please use BackdoorState.

> +
> +
> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
> +{
> +    State *s = opaque;
> +
> +    uint64_t res = ldq_p(&s->size);
> +    uint8_t *resb = (uint8_t*)&res;
> +    return resb[addr % CTRL_BYTES];

I don't think these lines do what you mean, but I'm also not sure what
it is supposed to mean.

> +}
> +
> +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
> +{
> +    State *s = opaque;
> +
> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
> +
> +    if ((addr + size) % CTRL_BYTES == 0) {
> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
> +    }

Same here.

> +}
> +
> +static const MemoryRegionOps control_ops = {
> +    .read = control_io_read,
> +    .write = control_io_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +
> +static int init(PCIDevice *dev)
> +{
> +    State *s = DO_UPCAST(State, dev, dev);
> +
> +    if (s->pages < 1) {
> +        fprintf(stderr, "error: backdoor: "
> +                "the data channel must have one or more pages\n");
> +        return -1;
> +    }
> +    s->size = s->pages * PAGE_SIZE;
> +
> +    pci_set_word(s->dev.config + PCI_COMMAND,
> +                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
> +
> +    memory_region_init_io(&s->control, &control_ops, s, "backdoor.control",
> +                          PAGE_SIZE);
> +    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->control);
> +
> +    memory_region_init_ram(&s->data, &s->dev.qdev, "backdoor.data",
> +                           s->size);
> +    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->data);
> +    s->data_ptr = qemu_get_ram_ptr(s->data.ram_addr);
> +
> +    qemu_backdoor_init(s->size);
> +
> +    return 0;
> +}
> +
> +static int fini(PCIDevice *dev)
> +{
> +    State *s = DO_UPCAST(State, dev, dev);
> +
> +    memory_region_destroy(&s->data);
> +    memory_region_destroy(&s->control);
> +
> +    return 0;
> +}
> +
> +
> +static PCIDeviceInfo info = {
> +    .qdev.name  = "backdoor",
> +    .qdev.desc  = "Backdoor communication channel",
> +    .qdev.size  = sizeof(State),
> +    .init       = init,
> +    .exit       = fini,
> +    .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
> +    .device_id  = PCI_DEVICE_ID_BACKDOOR,
> +    .class_id   = PCI_CLASS_MEMORY_RAM,
> +    .qdev.props = (Property[]) {
> +        DEFINE_PROP_UINT8("pages", State, pages, 1),
> +        DEFINE_PROP_END_OF_LIST(),
> +    }
> +};
> +
> +static void register_device(void)
> +{
> +    pci_qdev_register(&info);
> +}
> +
> +device_init(register_device)
> diff --git a/hw/pci.h b/hw/pci.h
> index 86a81c8..4d7d161 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -75,6 +75,7 @@
>  #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
>  #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
>  #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
> +#define PCI_DEVICE_ID_BACKDOOR           0x1004
>
>  #define FMT_PCIBUS                      PRIx64
>
>
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel
  2011-09-29 13:52 ` [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Anthony Liguori
  2011-09-29 17:10   ` Lluís Vilanova
@ 2011-09-29 20:55   ` Blue Swirl
  1 sibling, 0 replies; 17+ messages in thread
From: Blue Swirl @ 2011-09-29 20:55 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Zhi Yong Wu, Lluís Vilanova, qemu-devel

2011/9/29 Anthony Liguori <anthony@codemonkey.ws>:
> On 09/29/2011 08:47 AM, Lluís Vilanova wrote:
>>
>> Provides the ability for the guest to communicate with user-provided code
>> inside
>> QEMU itself, using a lightweight mechanism.
>>
>> See first commit for a full description.
>>
>> Signed-off-by: Lluís Vilanova<vilanova@ac.upc.edu>
>
> We already have two "backdoors" in QEMU: ivshmem and virtio-serial.  Can you
> discuss why these are insufficient for your purposes?
>
> Also, what's the advantage of having a backdoor mechanism both for softmmu
> and user?  I can't think of a practical use-case for it.

This can be used for instrumentation and maybe it could be used for
test setups too instead of a dedicated test device.

> Regards,
>
> Anthony Liguori
>
>> ---
>>
>> Lluís Vilanova (5):
>>       backdoor: Add documentation
>>       backdoor: Add build infrastructure
>>       backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a"
>>       backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
>>       backdoor: Add guest-side library
>>
>>
>>  Makefile                       |    3 -
>>  Makefile.objs                  |   21 ++++
>>  Makefile.target                |    4 +
>>  backdoor/guest/Makefile        |   18 ++++
>>  backdoor/guest/common.c        |  130 +++++++++++++++++++++++++++
>>  backdoor/guest/qemu-backdoor.h |   50 ++++++++++
>>  backdoor/qemu/qemu-backdoor.h  |   29 ++++++
>>  backdoor/qemu/softmmu.c        |  124 ++++++++++++++++++++++++++
>>  backdoor/qemu/user.c           |  194
>> ++++++++++++++++++++++++++++++++++++++++
>>  backdoor/qemu/user.h           |   17 ++++
>>  bsd-user/main.c                |   25 +++++
>>  bsd-user/mmap.c                |    7 +
>>  configure                      |   35 +++++++
>>  darwin-user/main.c             |   25 +++++
>>  darwin-user/mmap.c             |    7 +
>>  docs/backdoor.txt              |  144 ++++++++++++++++++++++++++++++
>>  hw/pci.h                       |    1
>>  linux-user/main.c              |   30 ++++++
>>  linux-user/mmap.c              |    7 +
>>  19 files changed, 869 insertions(+), 2 deletions(-)
>>  create mode 100644 backdoor/guest/Makefile
>>  create mode 100644 backdoor/guest/common.c
>>  create mode 100644 backdoor/guest/qemu-backdoor.h
>>  create mode 100644 backdoor/qemu/qemu-backdoor.h
>>  create mode 100644 backdoor/qemu/softmmu.c
>>  create mode 100644 backdoor/qemu/user.c
>>  create mode 100644 backdoor/qemu/user.h
>>  create mode 100644 docs/backdoor.txt
>>
>>
>
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 20:42   ` Blue Swirl
@ 2011-09-29 21:49     ` Lluís Vilanova
  2011-09-29 22:13       ` Frans de Boer
                         ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-29 21:49 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Zhi Yong Wu, qemu-devel

Blue Swirl writes:

> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>> +{
>> +    State *s = opaque;
>> +
>> +    uint64_t res = ldq_p(&s->size);
>> +    uint8_t *resb = (uint8_t*)&res;
>> +    return resb[addr % CTRL_BYTES];

> I don't think these lines do what you mean, but I'm also not sure what
> it is supposed to mean.

Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
just because the code looks less ugly, and host performance should not be an
issue here.

The device is treated as a circular buffer of length CTRL_BYTES

Reads are only used to get the size of the data channel.

First line should handle guest/host endianess swapping, although I'm not sure if
that's the API I'm supposed to use.

Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
result.

>> +}
>> +
>> +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
>> +{
>> +    State *s = opaque;
>> +
>> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
>> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
>> +
>> +    if ((addr + size) % CTRL_BYTES == 0) {
>> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
>> +    }

> Same here.

Pre: same as during reads.

Accumulates writes into s->cmd to build the command the guest is sending us (in
guest endianess).

When CTRL_BYTES bytes have been written into the device, get the command value
into host endianess and invoke the user-provided backdoor callback.

This assumes that when executing in KVM, the device handling infrastructure will
get a lock and only one CPU will be sending a backdoor command until completion.


I'll add some comments there and prefix all structs and functions with
"backdoor_", as otherwise debugging could get harder if everyone started
avoiding the prefixes.


Lluis

-- 
 "And it's much the same thing with knowledge, for whenever you learn
 something new, the whole world becomes that much richer."
 -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
 Tollbooth

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 21:49     ` Lluís Vilanova
@ 2011-09-29 22:13       ` Frans de Boer
  2011-09-29 22:35       ` Frans de Boer
  2011-09-30 20:07       ` Blue Swirl
  2 siblings, 0 replies; 17+ messages in thread
From: Frans de Boer @ 2011-09-29 22:13 UTC (permalink / raw)
  To: qemu-devel

On 09/29/2011 11:49 PM, Lluís Vilanova wrote:
> Blue Swirl writes:
>
>> 2011/9/29 Lluís Vilanova<vilanova@ac.upc.edu>:
>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint64_t res = ldq_p(&s->size);
>>> +    uint8_t *resb = (uint8_t*)&res;
>>> +    return resb[addr % CTRL_BYTES];
>
>> I don't think these lines do what you mean, but I'm also not sure what
>> it is supposed to mean.
>
> Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
> just because the code looks less ugly, and host performance should not be an
> issue here.
>
> The device is treated as a circular buffer of length CTRL_BYTES
>
> Reads are only used to get the size of the data channel.
>
> First line should handle guest/host endianess swapping, although I'm not sure if
> that's the API I'm supposed to use.
>
> Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
> result.
>
>>> +}
>>> +
>>> +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
>>> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
>>> +
>>> +    if ((addr + size) % CTRL_BYTES == 0) {
>>> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
>>> +    }
>
>> Same here.
>
> Pre: same as during reads.
>
> Accumulates writes into s->cmd to build the command the guest is sending us (in
> guest endianess).
>
> When CTRL_BYTES bytes have been written into the device, get the command value
> into host endianess and invoke the user-provided backdoor callback.
>
> This assumes that when executing in KVM, the device handling infrastructure will
> get a lock and only one CPU will be sending a backdoor command until completion.
>
>
> I'll add some comments there and prefix all structs and functions with
> "backdoor_", as otherwise debugging could get harder if everyone started
> avoiding the prefixes.
>
>
> Lluis
>
I have not read the whole thread, but being an advisor in matters of 
information risk management, the very word "backdoor" send quivers along 
my spine. Why use a backdoor at all? The word alone gives us bad vibes.

Using these words will disseminate QEMU from professional use since a 
possible risk might be introduced (even if it seems documented). So, 
please clarify the word "backdoor" or change it into something less 
threatening.

regards,
Frans de Boer.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 21:49     ` Lluís Vilanova
  2011-09-29 22:13       ` Frans de Boer
@ 2011-09-29 22:35       ` Frans de Boer
  2011-09-30 20:29         ` Blue Swirl
  2011-09-30 20:07       ` Blue Swirl
  2 siblings, 1 reply; 17+ messages in thread
From: Frans de Boer @ 2011-09-29 22:35 UTC (permalink / raw)
  To: qemu-devel

On 09/29/2011 11:49 PM, Lluís Vilanova wrote:
> Blue Swirl writes:
>
>> 2011/9/29 Lluís Vilanova<vilanova@ac.upc.edu>:
>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint64_t res = ldq_p(&s->size);
>>> +    uint8_t *resb = (uint8_t*)&res;
>>> +    return resb[addr % CTRL_BYTES];
>
>> I don't think these lines do what you mean, but I'm also not sure what
>> it is supposed to mean.
>
> Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
> just because the code looks less ugly, and host performance should not be an
> issue here.
>
> The device is treated as a circular buffer of length CTRL_BYTES
>
> Reads are only used to get the size of the data channel.
>
> First line should handle guest/host endianess swapping, although I'm not sure if
> that's the API I'm supposed to use.
>
> Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
> result.
>
>>> +}
>>> +
>>> +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
>>> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
>>> +
>>> +    if ((addr + size) % CTRL_BYTES == 0) {
>>> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
>>> +    }
>
>> Same here.
>
> Pre: same as during reads.
>
> Accumulates writes into s->cmd to build the command the guest is sending us (in
> guest endianess).
>
> When CTRL_BYTES bytes have been written into the device, get the command value
> into host endianess and invoke the user-provided backdoor callback.
>
> This assumes that when executing in KVM, the device handling infrastructure will
> get a lock and only one CPU will be sending a backdoor command until completion.
>
>
> I'll add some comments there and prefix all structs and functions with
> "backdoor_", as otherwise debugging could get harder if everyone started
> avoiding the prefixes.
>
>
> Lluis
>
I have not read the whole thread, but being an advisor in matters of 
information risk management, the very word "backdoor" send quivers along 
my spine. Why use a backdoor at all? The word alone gives us bad vibes.

Using these words will disseminate QEMU from professional use since a 
possible risk might be introduced (even if it seems documented). So, 
please clarify the word "backdoor" or change it into something less 
threatening.

regards,
Frans de Boer.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 21:49     ` Lluís Vilanova
  2011-09-29 22:13       ` Frans de Boer
  2011-09-29 22:35       ` Frans de Boer
@ 2011-09-30 20:07       ` Blue Swirl
  2011-09-30 20:49         ` Lluís Vilanova
  2 siblings, 1 reply; 17+ messages in thread
From: Blue Swirl @ 2011-09-30 20:07 UTC (permalink / raw)
  To: Blue Swirl, qemu-devel, Zhi Yong Wu

2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
> Blue Swirl writes:
>
>> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint64_t res = ldq_p(&s->size);
>>> +    uint8_t *resb = (uint8_t*)&res;
>>> +    return resb[addr % CTRL_BYTES];
>
>> I don't think these lines do what you mean, but I'm also not sure what
>> it is supposed to mean.
>
> Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
> just because the code looks less ugly, and host performance should not be an
> issue here.
>
> The device is treated as a circular buffer of length CTRL_BYTES
>
> Reads are only used to get the size of the data channel.
>
> First line should handle guest/host endianess swapping, although I'm not sure if
> that's the API I'm supposed to use.
>
> Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
> result.

That may be the intention, but the first line will load res from guest
memory using an address (&s->size) in host memory. I think the next
two lines are equal to
return res >> (addr % CTRL_BYTES);
but with some obfuscation.

It would be much clearer if the registers were byte arrays so you
could read and write the data directly without pointer arithmetic.

Byte accesses will be slower than larger word size accesses, I thought
performance was one of the goals with this?

>>> +}
>>> +
>>> +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size)
>>> +{
>>> +    State *s = opaque;
>>> +
>>> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
>>> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
>>> +
>>> +    if ((addr + size) % CTRL_BYTES == 0) {
>>> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
>>> +    }
>
>> Same here.
>
> Pre: same as during reads.
>
> Accumulates writes into s->cmd to build the command the guest is sending us (in
> guest endianess).
>
> When CTRL_BYTES bytes have been written into the device, get the command value
> into host endianess and invoke the user-provided backdoor callback.
>
> This assumes that when executing in KVM, the device handling infrastructure will
> get a lock and only one CPU will be sending a backdoor command until completion.
>
>
> I'll add some comments there and prefix all structs and functions with
> "backdoor_", as otherwise debugging could get harder if everyone started
> avoiding the prefixes.
>
>
> Lluis
>
> --
>  "And it's much the same thing with knowledge, for whenever you learn
>  something new, the whole world becomes that much richer."
>  -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
>  Tollbooth
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-29 22:35       ` Frans de Boer
@ 2011-09-30 20:29         ` Blue Swirl
  0 siblings, 0 replies; 17+ messages in thread
From: Blue Swirl @ 2011-09-30 20:29 UTC (permalink / raw)
  To: Frans de Boer; +Cc: qemu-devel

On Thu, Sep 29, 2011 at 10:35 PM, Frans de Boer <frans@fransdb.nl> wrote:
> On 09/29/2011 11:49 PM, Lluís Vilanova wrote:
>>
>> Blue Swirl writes:
>>
>>> 2011/9/29 Lluís Vilanova<vilanova@ac.upc.edu>:
>>>>
>>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr,
>>>> unsigned size)
>>>> +{
>>>> +    State *s = opaque;
>>>> +
>>>> +    uint64_t res = ldq_p(&s->size);
>>>> +    uint8_t *resb = (uint8_t*)&res;
>>>> +    return resb[addr % CTRL_BYTES];
>>
>>> I don't think these lines do what you mean, but I'm also not sure what
>>> it is supposed to mean.
>>
>> Pre: only can read on a byte-per-byte basis (as stated in
>> control_ops.impl),
>> just because the code looks less ugly, and host performance should not be
>> an
>> issue here.
>>
>> The device is treated as a circular buffer of length CTRL_BYTES
>>
>> Reads are only used to get the size of the data channel.
>>
>> First line should handle guest/host endianess swapping, although I'm not
>> sure if
>> that's the API I'm supposed to use.
>>
>> Then return the N'th byte of the uint64_t variable holding the
>> (endianess-aware)
>> result.
>>
>>>> +}
>>>> +
>>>> +static void control_io_write(void *opaque, target_phys_addr_t addr,
>>>> uint64_t data, unsigned size)
>>>> +{
>>>> +    State *s = opaque;
>>>> +
>>>> +    uint8_t *cmdb = (uint8_t*)&s->cmd;
>>>> +    cmdb[addr % CTRL_BYTES] = (uint8_t)data;
>>>> +
>>>> +    if ((addr + size) % CTRL_BYTES == 0) {
>>>> +        qemu_backdoor(ldq_p(&s->cmd), s->data_ptr);
>>>> +    }
>>
>>> Same here.
>>
>> Pre: same as during reads.
>>
>> Accumulates writes into s->cmd to build the command the guest is sending
>> us (in
>> guest endianess).
>>
>> When CTRL_BYTES bytes have been written into the device, get the command
>> value
>> into host endianess and invoke the user-provided backdoor callback.
>>
>> This assumes that when executing in KVM, the device handling
>> infrastructure will
>> get a lock and only one CPU will be sending a backdoor command until
>> completion.
>>
>>
>> I'll add some comments there and prefix all structs and functions with
>> "backdoor_", as otherwise debugging could get harder if everyone started
>> avoiding the prefixes.
>>
>>
>> Lluis
>>
> I have not read the whole thread, but being an advisor in matters of
> information risk management, the very word "backdoor" send quivers along my
> spine. Why use a backdoor at all? The word alone gives us bad vibes.

Are the other methods for guest to interact with the host, like virtio
services OK then just because of their virtuous names? What about KVM,
isn't it horrible that untrusted guest code is executed by ultimately
trusted kernel module?

Jokes aside, the name could be improved.

> Using these words will disseminate QEMU from professional use since a
> possible risk might be introduced (even if it seems documented). So, please
> clarify the word "backdoor" or change it into something less threatening.

Obviously this device should never be enabled in any untrusted
environment, maybe not even compiled by default unless configured
during build. The same should apply to all debugging devices.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-30 20:07       ` Blue Swirl
@ 2011-09-30 20:49         ` Lluís Vilanova
  2011-09-30 20:59           ` Blue Swirl
  0 siblings, 1 reply; 17+ messages in thread
From: Lluís Vilanova @ 2011-09-30 20:49 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Zhi Yong Wu, qemu-devel

Blue Swirl writes:

> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>> Blue Swirl writes:
>> 
>>> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>>>> +{
>>>> +    State *s = opaque;
>>>> +
>>>> +    uint64_t res = ldq_p(&s->size);
>>>> +    uint8_t *resb = (uint8_t*)&res;
>>>> +    return resb[addr % CTRL_BYTES];
>> 
>>> I don't think these lines do what you mean, but I'm also not sure what
>>> it is supposed to mean.
>> 
>> Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
>> just because the code looks less ugly, and host performance should not be an
>> issue here.
>> 
>> The device is treated as a circular buffer of length CTRL_BYTES
>> 
>> Reads are only used to get the size of the data channel.
>> 
>> First line should handle guest/host endianess swapping, although I'm not sure if
>> that's the API I'm supposed to use.
>> 
>> Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
>> result.

> That may be the intention, but the first line will load res from guest
> memory using an address (&s->size) in host memory.

Ok, I think I found what I really wanted: tswap64


> I think the next two lines are equal to
> return res >> (addr % CTRL_BYTES);
> but with some obfuscation.

But I cannot assume any endianess on neither host or guest. The only thing I can
assume is that the generic device code handling the reads will read from lower
to higher addresses.

In any case, take me with a grain of salt, endianess often confuses me.


> It would be much clearer if the registers were byte arrays so you
> could read and write the data directly without pointer arithmetic.

Is that something present on the device API? Sorry I don't know what you mean by
byte array... for me 'resb' already is a byte array :)


> Byte accesses will be slower than larger word size accesses, I thought
> performance was one of the goals with this?

They will be slower on host time, but will not waste "guest time".

BTW, will the current scheme in KVM provoke one VM exit for each byte or only
one for the whole 64bits?

But yes, I was just too lazy to add code for all the supported sizes from 1 to
8, and let the generic device code pick the best.


Lluis

-- 
 "And it's much the same thing with knowledge, for whenever you learn
 something new, the whole world becomes that much richer."
 -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
 Tollbooth

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] Add QEMU-side proxy to "libbackdoor.a"
  2011-09-30 20:49         ` Lluís Vilanova
@ 2011-09-30 20:59           ` Blue Swirl
  0 siblings, 0 replies; 17+ messages in thread
From: Blue Swirl @ 2011-09-30 20:59 UTC (permalink / raw)
  To: Blue Swirl, qemu-devel, Zhi Yong Wu

2011/9/30 Lluís Vilanova <vilanova@ac.upc.edu>:
> Blue Swirl writes:
>
>> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>>> Blue Swirl writes:
>>>
>>>> 2011/9/29 Lluís Vilanova <vilanova@ac.upc.edu>:
>>>>> +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
>>>>> +{
>>>>> +    State *s = opaque;
>>>>> +
>>>>> +    uint64_t res = ldq_p(&s->size);
>>>>> +    uint8_t *resb = (uint8_t*)&res;
>>>>> +    return resb[addr % CTRL_BYTES];
>>>
>>>> I don't think these lines do what you mean, but I'm also not sure what
>>>> it is supposed to mean.
>>>
>>> Pre: only can read on a byte-per-byte basis (as stated in control_ops.impl),
>>> just because the code looks less ugly, and host performance should not be an
>>> issue here.
>>>
>>> The device is treated as a circular buffer of length CTRL_BYTES
>>>
>>> Reads are only used to get the size of the data channel.
>>>
>>> First line should handle guest/host endianess swapping, although I'm not sure if
>>> that's the API I'm supposed to use.
>>>
>>> Then return the N'th byte of the uint64_t variable holding the (endianess-aware)
>>> result.
>
>> That may be the intention, but the first line will load res from guest
>> memory using an address (&s->size) in host memory.
>
> Ok, I think I found what I really wanted: tswap64
>
>
>> I think the next two lines are equal to
>> return res >> (addr % CTRL_BYTES);
>> but with some obfuscation.
>
> But I cannot assume any endianess on neither host or guest. The only thing I can
> assume is that the generic device code handling the reads will read from lower
> to higher addresses.

Since this is your device, you can specify that the device works only
in little endian, like most if not all PCI devices. Then you can use
le64_to_cpu().

> In any case, take me with a grain of salt, endianess often confuses me.
>
>
>> It would be much clearer if the registers were byte arrays so you
>> could read and write the data directly without pointer arithmetic.
>
> Is that something present on the device API? Sorry I don't know what you mean by
> byte array... for me 'resb' already is a byte array :)

I meant that instead of
    uint64_t size;
    uint64_t cmd;

you'd have
    uint8_t size[8];
    uint8_t cmd[8];

>> Byte accesses will be slower than larger word size accesses, I thought
>> performance was one of the goals with this?
>
> They will be slower on host time, but will not waste "guest time".
>
> BTW, will the current scheme in KVM provoke one VM exit for each byte or only
> one for the whole 64bits?
>
> But yes, I was just too lazy to add code for all the supported sizes from 1 to
> 8, and let the generic device code pick the best.
>
>
> Lluis
>
> --
>  "And it's much the same thing with knowledge, for whenever you learn
>  something new, the whole world becomes that much richer."
>  -- The Princess of Pure Reason, as told by Norton Juster in The Phantom
>  Tollbooth
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2011-09-30 20:59 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-29 13:47 [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Lluís Vilanova
2011-09-29 13:47 ` [Qemu-devel] [PATCH 1/5] backdoor: Add documentation Lluís Vilanova
2011-09-29 13:47 ` [Qemu-devel] [PATCH 2/5] backdoor: Add build infrastructure Lluís Vilanova
2011-09-29 13:47 ` [Qemu-devel] [PATCH 3/5] backdoor: [*-user] Add QEMU-side proxy to "libbackdoor.a" Lluís Vilanova
2011-09-29 13:47 ` [Qemu-devel] [PATCH 4/5] backdoor: [softmmu] " Lluís Vilanova
2011-09-29 20:42   ` Blue Swirl
2011-09-29 21:49     ` Lluís Vilanova
2011-09-29 22:13       ` Frans de Boer
2011-09-29 22:35       ` Frans de Boer
2011-09-30 20:29         ` Blue Swirl
2011-09-30 20:07       ` Blue Swirl
2011-09-30 20:49         ` Lluís Vilanova
2011-09-30 20:59           ` Blue Swirl
2011-09-29 13:47 ` [Qemu-devel] [PATCH 5/5] backdoor: Add guest-side library Lluís Vilanova
2011-09-29 13:52 ` [Qemu-devel] [RFC][PATCH 0/5] backdoor: lightweight guest-to-QEMU backdoor channel Anthony Liguori
2011-09-29 17:10   ` Lluís Vilanova
2011-09-29 20:55   ` Blue Swirl

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.