All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part)
@ 2015-05-04  7:22 Quan Xu
  2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Quan Xu
                   ` (8 more replies)
  0 siblings, 9 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

*INTRODUCTION*
The goal of virtual Trusted Platform Module (vTPM) is to provide a TPM functionality to virtual machines (Fedora, Ubuntu, Redhat, Windows .etc). This allows programs to interact with a TPM in a virtual machine the same way they interact with a TPM on the physical system. Each virtual machine gets its own unique, emulated, software TPM. Each major component of vTPM is implemented as a stubdom, providing secure separation guaranteed by the hypervisor.

The vTPM stubdom is a Xen mini-OS domain that emulates a TPM for the virtual machine to use. It is a small wrapper around the Berlios TPM emulator. TPM commands are passed from mini-os TPM backend driver.

*ARCHITECTURE*
The architecture of stubdom vTPM for HVM virtual machine:

            +--------------------+
            | Windows/Linux DomU | ...
            |        |  ^        |
            |        v  |        |
            |  Qemu tpm1.2 Tis   |
            |        |  ^        |
            |        v  |        |
            | XenStubdoms backend|
            +--------------------+
                     |  ^
                     v  |
            +--------------------+
            |      XenDevOps     |
            +--------------------+
                     |  ^
                     v  |
            +--------------------+
            |  mini-os/tpmback   |
            |        |  ^        |
            |        v  |        |
            |   vtpm-stubdom     | ...
            |        |  ^        |
            |        v  |        |
            |  mini-os/tpmfront  |
            +--------------------+
                     |  ^
                     v  |
            +--------------------+
            |  mini-os/tpmback   |
            |        |  ^        |
            |        v  |        |
            |  vtpmmgr-stubdom   |
            |        |  ^        |
            |        v  |        |
            |  mini-os/tpm_tis   |
            +--------------------+
                     |  ^
                     v  |
            +--------------------+
            |    Hardware TPM    |
            +--------------------+

 * Windows/Linux DomU:
    The HVM based guest that wants to use a vTPM. There may be
    more than one of these.

 * Qemu tpm1.2 Tis:
    Implementation of the tpm1.2 Tis interface for HVM virtual
    machines. It is Qemu emulation device.

 * vTPM xenstubdoms driver:
    Qemu vTPM driver. This driver provides vtpm initialization
    and sending data and commends to a para-virtualized vtpm
    stubdom.

 * XenDevOps:
    Register Xen stubdom vTPM frontend driver, and transfer any
    request/repond between TPM xenstubdoms driver and Xen vTPM
    stubdom. Facilitate communications between Xen vTPM stubdom
    and vTPM xenstubdoms driver.

 * mini-os/tpmback:
    Mini-os TPM backend driver. The Linux frontend driver connects
    to this backend driver to facilitate communications between the
    Linux DomU and its vTPM. This driver is also used by vtpmmgr
    stubdom to communicate with vtpm-stubdom.

 * vtpm-stubdom:
    A mini-os stub domain that implements a vTPM. There is a
    one to one mapping between running vtpm-stubdom instances and
    logical vtpms on the system. The vTPM Platform Configuration
    Registers (PCRs) are all initialized to zero.

 * mini-os/tpmfront:
    Mini-os TPM frontend driver. The vTPM mini-os domain vtpm
    stubdom uses this driver to communicate with vtpmmgr-stubdom.
    This driver could also be used separately to implement a mini-os
    domain that wishes to use a vTPM of its own.

 * vtpmmgr-stubdom:
    A mini-os domain that implements the vTPM manager. There is only
    one vTPM manager and it should be running during the entire lifetime
    of the machine. vtpmmgr domain securely stores encryption keys for
    each of the vtpms and accesses to the hardware TPM to get the root of
    trust for the entire system.

 * mini-os/tpm_tis:
    Mini-os TPM version 1.2 TPM Interface Specification (TIS) driver.
    This driver used by vtpmmgr-stubdom to talk directly to the hardware
    TPM. Communication is facilitated by mapping hardware memory pages
    into vtpmmgr stubdom.

 * Hardware TPM: The physical TPM 1.2 that is soldered onto the motherboard.


--Changes in v6:
 -Add a parameter indicating whether the command that was a selftest,
  and whether it completed successfully.
 -Remove the redundant copy right.
 -Reduce the includes to its minimum.
 -Replace buf_size with PAGE_SIZE and use length rather than
  shr->length.
 -Remove stray insertion.

Quan Xu (6):
  Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  Qemu-Xen-vTPM: Xen frontend driver infrastructure
  Qemu-Xen-vTPM: Xen frontend driver infrastructure
  Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init()

 configure                        |  14 ++
 hmp.c                            |   2 +
 hw/display/xenfb.c               |   4 +-
 hw/tpm/Makefile.objs             |   3 +-
 hw/tpm/tpm_passthrough.c         |  13 +-
 hw/tpm/tpm_util.c                |  39 ++++
 hw/tpm/tpm_xenstubdoms.c         | 277 ++++++++++++++++++++++
 hw/tpm/xen_vtpm_frontend.c       | 315 +++++++++++++++++++++++++
 hw/xen/Makefile.objs             |   2 +-
 hw/xen/xen_backend.c             | 353 ----------------------------
 hw/xen/xen_frontend.c            | 365 +++++++++++++++++++++++++++++
 hw/xen/xen_pvdev.c               | 481 +++++++++++++++++++++++++++++++++++++++
 include/hw/xen/xen_backend.h     |  27 ++-
 include/hw/xen/xen_common.h      |   6 +
 include/sysemu/tpm_backend_int.h |   1 +
 qapi-schema.json                 |  16 +-
 qemu-options.hx                  |  13 +-
 tpm.c                            |   7 +-
 vl.c                             |  17 +-
 xen-hvm.c                        |   5 +
 20 files changed, 1579 insertions(+), 381 deletions(-)
 create mode 100644 hw/tpm/tpm_util.c
 create mode 100644 hw/tpm/tpm_xenstubdoms.c
 create mode 100644 hw/tpm/xen_vtpm_frontend.c
 create mode 100644 hw/xen/xen_frontend.c
 create mode 100644 hw/xen/xen_pvdev.c

-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
@ 2015-05-04  7:22 ` Quan Xu
  2015-05-05 14:28   ` Eric Blake
  2015-05-05 14:28   ` [Qemu-devel] " Eric Blake
  2015-05-04  7:22 ` Quan Xu
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Remove stray insertion.
---
 configure        | 14 ++++++++++++++
 hmp.c            |  2 ++
 qapi-schema.json | 16 ++++++++++++++--
 qemu-options.hx  | 13 +++++++++++--
 tpm.c            |  7 ++++++-
 5 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 09c9225..8c9411d 100755
--- a/configure
+++ b/configure
@@ -3010,6 +3010,16 @@ else
 fi
 
 ##########################################
+# TPM xenstubdoms is only on x86 Linux
+
+if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64 && \
+   test "$xen" = "yes"; then
+  tpm_xenstubdoms=$tpm
+else
+  tpm_xenstubdoms=no
+fi
+
+##########################################
 # attr probe
 
 if test "$attr" != "no" ; then
@@ -4432,6 +4442,7 @@ echo "gcov              $gcov_tool"
 echo "gcov enabled      $gcov"
 echo "TPM support       $tpm"
 echo "libssh2 support   $libssh2"
+echo "TPM xenstubdoms   $tpm_xenstubdoms"
 echo "TPM passthrough   $tpm_passthrough"
 echo "QOM debugging     $qom_cast_debug"
 echo "vhdx              $vhdx"
@@ -4919,6 +4930,9 @@ if test "$tpm" = "yes"; then
   if test "$tpm_passthrough" = "yes"; then
     echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
   fi
+  if test "$tpm_xenstubdoms" = "yes"; then
+    echo "CONFIG_TPM_XENSTUBDOMS=y" >> $config_host_mak
+  fi
 fi
 
 echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
diff --git a/hmp.c b/hmp.c
index f31ae27..c10b6f7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -813,6 +813,8 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
                            tpo->has_cancel_path ? ",cancel-path=" : "",
                            tpo->has_cancel_path ? tpo->cancel_path : "");
             break;
+        case TPM_TYPE_OPTIONS_KIND_XENSTUBDOMS:
+            break;
         case TPM_TYPE_OPTIONS_KIND_MAX:
             break;
         }
diff --git a/qapi-schema.json b/qapi-schema.json
index ac9594d..9bdb15e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2975,9 +2975,11 @@
 #
 # @passthrough: TPM passthrough type
 #
+# @xenstubdoms: TPM xenstubdoms type (since 2.4)
+#
 # Since: 1.5
 ##
-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'xenstubdoms' ] }
 
 ##
 # @query-tpm-types:
@@ -3006,6 +3008,15 @@
                                              '*cancel-path' : 'str'} }
 
 ##
+# @TPMXenstubdomsOptions:
+#
+# Information about the TPM xenstubdoms type
+#
+# Since: 2.4
+##
+{ 'type': 'TPMXenstubdomsOptions', 'data': {  } }
+
+##
 # @TpmTypeOptions:
 #
 # A union referencing different TPM backend types' configuration options
@@ -3015,7 +3026,8 @@
 # Since: 1.5
 ##
 { 'union': 'TpmTypeOptions',
-   'data': { 'passthrough' : 'TPMPassthroughOptions' } }
+  'data': { 'passthrough' : 'TPMPassthroughOptions',
+            'xenstubdoms' : 'TPMXenstubdomsOptions' } }
 
 ##
 # @TpmInfo:
diff --git a/qemu-options.hx b/qemu-options.hx
index 319d971..9254902 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2539,7 +2539,8 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
     "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
     "                use path to provide path to a character device; default is /dev/tpm0\n"
     "                use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
-    "                not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+    "                not provided it will be searched for in /sys/class/misc/tpm?/device\n"
+    "-tpmdev xenstubdoms,id=id\n",
     QEMU_ARCH_ALL)
 STEXI
 
@@ -2549,7 +2550,8 @@ The general form of a TPM device option is:
 @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
 @findex -tpmdev
 Backend type must be:
-@option{passthrough}.
+@option{passthrough}, or
+@option{xenstubdoms}.
 
 The specific backend type will determine the applicable options.
 The @code{-tpmdev} option creates the TPM backend and requires a
@@ -2599,6 +2601,13 @@ To create a passthrough TPM use the following two options:
 Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
 @code{tpmdev=tpm0} in the device option.
 
+To create a xenstubdoms TPM use the following two options:
+@example
+-tpmdev xenstubdoms,id=tpm0 -device tpm-tis,tpmdev=tpm0
+@end example
+Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
+@code{tpmdev=tpm0} in the device option.
+
 @end table
 
 ETEXI
diff --git a/tpm.c b/tpm.c
index 963b7ee..30643fd 100644
--- a/tpm.c
+++ b/tpm.c
@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
 
 
 #define TPM_MAX_MODELS      1
-#define TPM_MAX_DRIVERS     1
+#define TPM_MAX_DRIVERS     2
 
 static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
     NULL,
@@ -254,6 +254,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
 {
     TPMInfo *res = g_new0(TPMInfo, 1);
     TPMPassthroughOptions *tpo;
+    TPMXenstubdomsOptions *txo;
 
     res->id = g_strdup(drv->id);
     res->model = drv->fe_model;
@@ -273,6 +274,10 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
             tpo->has_cancel_path = true;
         }
         break;
+    case TPM_TYPE_XENSTUBDOMS:
+        res->options->kind = TPM_TYPE_OPTIONS_KIND_XENSTUBDOMS;
+        txo = g_new0(TPMXenstubdomsOptions, 1);
+        res->options->xenstubdoms = txo;
     case TPM_TYPE_MAX:
         break;
     }
-- 
1.8.3.2

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

* [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
  2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Quan Xu
@ 2015-05-04  7:22 ` Quan Xu
  2015-05-04  7:22   ` Quan Xu
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Remove stray insertion.
---
 configure        | 14 ++++++++++++++
 hmp.c            |  2 ++
 qapi-schema.json | 16 ++++++++++++++--
 qemu-options.hx  | 13 +++++++++++--
 tpm.c            |  7 ++++++-
 5 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 09c9225..8c9411d 100755
--- a/configure
+++ b/configure
@@ -3010,6 +3010,16 @@ else
 fi
 
 ##########################################
+# TPM xenstubdoms is only on x86 Linux
+
+if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64 && \
+   test "$xen" = "yes"; then
+  tpm_xenstubdoms=$tpm
+else
+  tpm_xenstubdoms=no
+fi
+
+##########################################
 # attr probe
 
 if test "$attr" != "no" ; then
@@ -4432,6 +4442,7 @@ echo "gcov              $gcov_tool"
 echo "gcov enabled      $gcov"
 echo "TPM support       $tpm"
 echo "libssh2 support   $libssh2"
+echo "TPM xenstubdoms   $tpm_xenstubdoms"
 echo "TPM passthrough   $tpm_passthrough"
 echo "QOM debugging     $qom_cast_debug"
 echo "vhdx              $vhdx"
@@ -4919,6 +4930,9 @@ if test "$tpm" = "yes"; then
   if test "$tpm_passthrough" = "yes"; then
     echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
   fi
+  if test "$tpm_xenstubdoms" = "yes"; then
+    echo "CONFIG_TPM_XENSTUBDOMS=y" >> $config_host_mak
+  fi
 fi
 
 echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
diff --git a/hmp.c b/hmp.c
index f31ae27..c10b6f7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -813,6 +813,8 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
                            tpo->has_cancel_path ? ",cancel-path=" : "",
                            tpo->has_cancel_path ? tpo->cancel_path : "");
             break;
+        case TPM_TYPE_OPTIONS_KIND_XENSTUBDOMS:
+            break;
         case TPM_TYPE_OPTIONS_KIND_MAX:
             break;
         }
diff --git a/qapi-schema.json b/qapi-schema.json
index ac9594d..9bdb15e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2975,9 +2975,11 @@
 #
 # @passthrough: TPM passthrough type
 #
+# @xenstubdoms: TPM xenstubdoms type (since 2.4)
+#
 # Since: 1.5
 ##
-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'xenstubdoms' ] }
 
 ##
 # @query-tpm-types:
@@ -3006,6 +3008,15 @@
                                              '*cancel-path' : 'str'} }
 
 ##
+# @TPMXenstubdomsOptions:
+#
+# Information about the TPM xenstubdoms type
+#
+# Since: 2.4
+##
+{ 'type': 'TPMXenstubdomsOptions', 'data': {  } }
+
+##
 # @TpmTypeOptions:
 #
 # A union referencing different TPM backend types' configuration options
@@ -3015,7 +3026,8 @@
 # Since: 1.5
 ##
 { 'union': 'TpmTypeOptions',
-   'data': { 'passthrough' : 'TPMPassthroughOptions' } }
+  'data': { 'passthrough' : 'TPMPassthroughOptions',
+            'xenstubdoms' : 'TPMXenstubdomsOptions' } }
 
 ##
 # @TpmInfo:
diff --git a/qemu-options.hx b/qemu-options.hx
index 319d971..9254902 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2539,7 +2539,8 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
     "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
     "                use path to provide path to a character device; default is /dev/tpm0\n"
     "                use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
-    "                not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+    "                not provided it will be searched for in /sys/class/misc/tpm?/device\n"
+    "-tpmdev xenstubdoms,id=id\n",
     QEMU_ARCH_ALL)
 STEXI
 
@@ -2549,7 +2550,8 @@ The general form of a TPM device option is:
 @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
 @findex -tpmdev
 Backend type must be:
-@option{passthrough}.
+@option{passthrough}, or
+@option{xenstubdoms}.
 
 The specific backend type will determine the applicable options.
 The @code{-tpmdev} option creates the TPM backend and requires a
@@ -2599,6 +2601,13 @@ To create a passthrough TPM use the following two options:
 Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
 @code{tpmdev=tpm0} in the device option.
 
+To create a xenstubdoms TPM use the following two options:
+@example
+-tpmdev xenstubdoms,id=tpm0 -device tpm-tis,tpmdev=tpm0
+@end example
+Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
+@code{tpmdev=tpm0} in the device option.
+
 @end table
 
 ETEXI
diff --git a/tpm.c b/tpm.c
index 963b7ee..30643fd 100644
--- a/tpm.c
+++ b/tpm.c
@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
 
 
 #define TPM_MAX_MODELS      1
-#define TPM_MAX_DRIVERS     1
+#define TPM_MAX_DRIVERS     2
 
 static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
     NULL,
@@ -254,6 +254,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
 {
     TPMInfo *res = g_new0(TPMInfo, 1);
     TPMPassthroughOptions *tpo;
+    TPMXenstubdomsOptions *txo;
 
     res->id = g_strdup(drv->id);
     res->model = drv->fe_model;
@@ -273,6 +274,10 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
             tpo->has_cancel_path = true;
         }
         break;
+    case TPM_TYPE_XENSTUBDOMS:
+        res->options->kind = TPM_TYPE_OPTIONS_KIND_XENSTUBDOMS;
+        txo = g_new0(TPMXenstubdomsOptions, 1);
+        res->options->xenstubdoms = txo;
     case TPM_TYPE_MAX:
         break;
     }
-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
@ 2015-05-04  7:22   ` Quan Xu
  2015-05-04  7:22 ` Quan Xu
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This patch adds infrastructure for xen front drivers living in qemu,
so drivers don't need to implement common stuff on their own.  It's
mostly xenbus management stuff: some functions to access XenStore,
setting up XenStore watches, callbacks on device discovery and state
changes, and handle event channel between the virtual machines.

Call xen_fe_register() function to register XenDevOps, and make sure,
XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
the XenDevOps is Xen frontend.

Create a new file xen_pvdev.c for some common part of xen frontend
and backend, such as xendevs queue and xenstore update functions.

Signed-off-by: Quan Xu <quan.xu@intel.com>
---
 hw/display/xenfb.c           |   4 +-
 hw/xen/Makefile.objs         |   2 +-
 hw/xen/xen_backend.c         | 353 -------------------------------
 hw/xen/xen_frontend.c        | 345 +++++++++++++++++++++++++++++++
 hw/xen/xen_pvdev.c           | 481 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/xen/xen_backend.h |  22 +-
 6 files changed, 850 insertions(+), 357 deletions(-)
 create mode 100644 hw/xen/xen_frontend.c
 create mode 100644 hw/xen/xen_pvdev.c

diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 5e324ef..10751df 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -988,8 +988,8 @@ void xen_init_display(int domid)
 wait_more:
     i++;
     main_loop_wait(true);
-    xfb = xen_be_find_xendev("vfb", domid, 0);
-    xin = xen_be_find_xendev("vkbd", domid, 0);
+    xfb = xen_find_xendev("vfb", domid, 0);
+    xin = xen_find_xendev("vkbd", domid, 0);
     if (!xfb || !xin) {
         if (i < 256) {
             usleep(10000);
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index a0ca0aa..95eb9d0 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -1,5 +1,5 @@
 # xen backend driver support
-common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o xen_frontend.o xen_pvdev.o
 
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
index b2cb22b..844f918 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen_backend.c
@@ -44,86 +44,11 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
-struct xs_handle *xenstore = NULL;
 const char *xen_protocol;
 
 /* private */
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
 static int debug = 0;
 
-/* ------------------------------------------------------------- */
-
-int xenstore_write_str(const char *base, const char *node, const char *val)
-{
-    char abspath[XEN_BUFSIZE];
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
-        return -1;
-    }
-    return 0;
-}
-
-char *xenstore_read_str(const char *base, const char *node)
-{
-    char abspath[XEN_BUFSIZE];
-    unsigned int len;
-    char *str, *ret = NULL;
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    str = xs_read(xenstore, 0, abspath, &len);
-    if (str != NULL) {
-        /* move to qemu-allocated memory to make sure
-         * callers can savely g_free() stuff. */
-        ret = g_strdup(str);
-        free(str);
-    }
-    return ret;
-}
-
-int xenstore_write_int(const char *base, const char *node, int ival)
-{
-    char val[12];
-
-    snprintf(val, sizeof(val), "%d", ival);
-    return xenstore_write_str(base, node, val);
-}
-
-int xenstore_write_int64(const char *base, const char *node, int64_t ival)
-{
-    char val[21];
-
-    snprintf(val, sizeof(val), "%"PRId64, ival);
-    return xenstore_write_str(base, node, val);
-}
-
-int xenstore_read_int(const char *base, const char *node, int *ival)
-{
-    char *val;
-    int rc = -1;
-
-    val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%d", ival)) {
-        rc = 0;
-    }
-    g_free(val);
-    return rc;
-}
-
-int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
-{
-    char *val;
-    int rc = -1;
-
-    val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
-        rc = 0;
-    }
-    g_free(val);
-    return rc;
-}
-
 int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
 {
     return xenstore_write_str(xendev->be, node, val);
@@ -195,183 +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
 }
 
 /* ------------------------------------------------------------- */
-
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
-{
-    struct XenDevice *xendev;
-
-    QTAILQ_FOREACH(xendev, &xendevs, next) {
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev) {
-            continue;
-        }
-        if (strcmp(xendev->type, type) != 0) {
-            continue;
-        }
-        return xendev;
-    }
-    return NULL;
-}
-
-/*
- * get xen backend device, allocate a new one if it doesn't exist.
- */
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
-                                           struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-
-    xendev = xen_be_find_xendev(type, dom, dev);
-    if (xendev) {
-        return xendev;
-    }
-
-    /* init new xendev */
-    xendev = g_malloc0(ops->size);
-    xendev->type  = type;
-    xendev->dom   = dom;
-    xendev->dev   = dev;
-    xendev->ops   = ops;
-
-    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
-             xendev->type, xendev->dom, xendev->dev);
-    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
-             xendev->type, xendev->dev);
-
-    xendev->debug      = debug;
-    xendev->local_port = -1;
-
-    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
-    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
-        xen_be_printf(NULL, 0, "can't open evtchn device\n");
-        g_free(xendev);
-        return NULL;
-    }
-    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
-
-    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
-        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
-            xen_be_printf(NULL, 0, "can't open gnttab device\n");
-            xc_evtchn_close(xendev->evtchndev);
-            g_free(xendev);
-            return NULL;
-        }
-    } else {
-        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
-    }
-
-    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
-
-    if (xendev->ops->alloc) {
-        xendev->ops->alloc(xendev);
-    }
-
-    return xendev;
-}
-
-/*
- * release xen backend device.
- */
-static struct XenDevice *xen_be_del_xendev(int dom, int dev)
-{
-    struct XenDevice *xendev, *xnext;
-
-    /*
-     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
-     * we save the next pointer in xnext because we might free xendev.
-     */
-    xnext = xendevs.tqh_first;
-    while (xnext) {
-        xendev = xnext;
-        xnext = xendev->next.tqe_next;
-
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev && dev != -1) {
-            continue;
-        }
-
-        if (xendev->ops->free) {
-            xendev->ops->free(xendev);
-        }
-
-        if (xendev->fe) {
-            char token[XEN_BUFSIZE];
-            snprintf(token, sizeof(token), "fe:%p", xendev);
-            xs_unwatch(xenstore, xendev->fe, token);
-            g_free(xendev->fe);
-        }
-
-        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
-            xc_evtchn_close(xendev->evtchndev);
-        }
-        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
-            xc_gnttab_close(xendev->gnttabdev);
-        }
-
-        QTAILQ_REMOVE(&xendevs, xendev, next);
-        g_free(xendev);
-    }
-    return NULL;
-}
-
-/*
- * Sync internal data structures on xenstore updates.
- * Node specifies the changed field.  node = NULL means
- * update all fields (used for initialization).
- */
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
-{
-    if (node == NULL  ||  strcmp(node, "online") == 0) {
-        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
-            xendev->online = 0;
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "backend update: %s\n", node);
-        if (xendev->ops->backend_changed) {
-            xendev->ops->backend_changed(xendev, node);
-        }
-    }
-}
-
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
-{
-    int fe_state;
-
-    if (node == NULL  ||  strcmp(node, "state") == 0) {
-        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
-            fe_state = XenbusStateUnknown;
-        }
-        if (xendev->fe_state != fe_state) {
-            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
-                          xenbus_strstate(xendev->fe_state),
-                          xenbus_strstate(fe_state));
-        }
-        xendev->fe_state = fe_state;
-    }
-    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
-        g_free(xendev->protocol);
-        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
-        if (xendev->protocol) {
-            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
-        if (xendev->ops->frontend_changed) {
-            xendev->ops->frontend_changed(xendev, node);
-        }
-    }
-}
-
-/* ------------------------------------------------------------- */
 /* Check for possible state transitions and perform them.        */
 
 /*
@@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
     return 0;
 }
 
-static void xenstore_update_be(char *watch, char *type, int dom,
-                               struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-    char path[XEN_BUFSIZE], *bepath;
-    unsigned int len, dev;
-
-    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
-    if (strncmp(path, watch, len) != 0) {
-        return;
-    }
-    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
-        strcpy(path, "");
-        if (sscanf(watch+len, "/%u", &dev) != 1) {
-            dev = -1;
-        }
-    }
-    if (dev == -1) {
-        return;
-    }
-
-    xendev = xen_be_get_xendev(type, dom, dev, ops);
-    if (xendev != NULL) {
-        bepath = xs_read(xenstore, 0, xendev->be, &len);
-        if (bepath == NULL) {
-            xen_be_del_xendev(dom, dev);
-        } else {
-            free(bepath);
-            xen_be_backend_changed(xendev, path);
-            xen_be_check_state(xendev);
-        }
-    }
-}
-
-static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
-{
-    char *node;
-    unsigned int len;
-
-    len = strlen(xendev->fe);
-    if (strncmp(xendev->fe, watch, len) != 0) {
-        return;
-    }
-    if (watch[len] != '/') {
-        return;
-    }
-    node = watch + len + 1;
-
-    xen_be_frontend_changed(xendev, node);
-    xen_be_check_state(xendev);
-}
-
-static void xenstore_update(void *unused)
-{
-    char **vec = NULL;
-    intptr_t type, ops, ptr;
-    unsigned int dom, count;
-
-    vec = xs_read_watch(xenstore, &count);
-    if (vec == NULL) {
-        goto cleanup;
-    }
-
-    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
-               &type, &dom, &ops) == 3) {
-        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
-    }
-    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
-        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
-    }
-
-cleanup:
-    free(vec);
-}
-
 static void xen_be_evtchn_event(void *opaque)
 {
     struct XenDevice *xendev = opaque;
@@ -706,32 +379,6 @@ static void xen_be_evtchn_event(void *opaque)
 
 /* -------------------------------------------------------------------- */
 
-int xen_be_init(void)
-{
-    xenstore = xs_daemon_open();
-    if (!xenstore) {
-        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
-        return -1;
-    }
-
-    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
-        goto err;
-    }
-
-    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
-        /* Check if xen_init() have been called */
-        goto err;
-    }
-    return 0;
-
-err:
-    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
-    xs_daemon_close(xenstore);
-    xenstore = NULL;
-
-    return -1;
-}
-
 int xen_be_register(const char *type, struct XenDevOps *ops)
 {
     return xenstore_scan(type, xen_domid, ops);
diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
new file mode 100644
index 0000000..55af45a
--- /dev/null
+++ b/hw/xen/xen_frontend.c
@@ -0,0 +1,345 @@
+/*
+ * Xen frontend driver infrastructure
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include "hw/hw.h"
+#include "sysemu/char.h"
+#include "qemu/log.h"
+#include "hw/xen/xen_backend.h"
+#include <xen/grant_table.h>
+
+int xenstore_dev;
+
+/* private */
+static int debug;
+
+static void xen_fe_evtchn_event(void *opaque)
+{
+    struct XenDevice *xendev = opaque;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xendev->evtchndev);
+    if (port != xendev->local_port) {
+        return;
+    }
+    xc_evtchn_unmask(xendev->evtchndev, port);
+
+    if (xendev->ops->event) {
+        xendev->ops->event(xendev);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
+{
+    xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
+                                                     remote_dom);
+    if (xendev->local_port == -1) {
+        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
+        return -1;
+    }
+    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+                        xen_fe_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+/*
+ * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
+ * xendev->ops->initialize()
+ */
+int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus)
+{
+    xs_transaction_t xbt = XBT_NULL;
+
+    if (xendev->fe_state == xbus) {
+        return 0;
+    }
+
+    xendev->fe_state = xbus;
+    if (xendev->fe == NULL) {
+        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
+        return -1;
+    }
+
+retry_transaction:
+    xbt = xs_transaction_start(xenstore);
+    if (xbt == XBT_NULL) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(xendev->fe, "state", xbus)) {
+        goto abort_transaction;
+    }
+
+    if (!xs_transaction_end(xenstore, xbt, 0)) {
+        if (errno == EAGAIN) {
+            goto retry_transaction;
+        }
+    }
+
+    return 0;
+
+abort_transaction:
+    xs_transaction_end(xenstore, xbt, 1);
+    return -1;
+}
+
+/*
+ * Simplify QEMU side, a thread is running in Xen backend, which will
+ * connect frontend when the frontend is initialised. Call these initialised
+ * functions.
+ */
+static int xen_fe_try_init(void *opaque)
+{
+    struct XenDevOps *ops = opaque;
+    int rc = -1;
+
+    if (ops->init) {
+        rc = ops->init(NULL);
+    }
+
+    return rc;
+}
+
+static int xen_fe_try_initialise(struct XenDevice *xendev)
+{
+    int rc = 0, fe_state;
+
+    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+        fe_state = XenbusStateUnknown;
+    }
+    xendev->fe_state = fe_state;
+
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
+    }
+    if (rc != 0) {
+        xen_fe_printf(xendev, 0, "initialise() failed\n");
+        return rc;
+    }
+
+    xenbus_switch_state(xendev, XenbusStateInitialised);
+    return 0;
+}
+
+static void xen_fe_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
+static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
+                        int handle)
+{
+    int rc = 0;
+
+    rc = xen_fe_try_initialise(xendev);
+    if (rc != 0) {
+        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
+                      xendev->name);
+        goto err;
+    }
+    xen_fe_try_connected(xendev);
+
+    return rc;
+
+err:
+    xen_del_xendev(domid, handle);
+    return -1;
+}
+
+static char *xenstore_fe_get_backend(const char *type, int be_domid,
+                                     uint32_t domid, int *hdl)
+{
+    char *name, *str, *ret = NULL;
+    uint32_t i, cdev;
+    int handle = 0;
+    char path[XEN_BUFSIZE];
+    char **dev = NULL;
+
+    name = xenstore_get_domain_name(domid);
+    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    for (i = 0; i < cdev; i++) {
+        handle = i;
+        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
+        type, be_domid, handle);
+        str = xenstore_read_str(path, "domain");
+        if (!strcmp(name, str)) {
+            break;
+        }
+
+        free(str);
+
+        /* Not the backend domain */
+        if (handle == (cdev - 1)) {
+            goto err;
+        }
+    }
+
+    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
+    type, be_domid, handle);
+    str = xenstore_read_str(path, "backend");
+    if (str != NULL) {
+        ret = g_strdup(str);
+        free(str);
+    }
+
+    *hdl = handle;
+    free(dev);
+
+    return ret;
+err:
+    *hdl = -1;
+    free(dev);
+    return NULL;
+}
+
+static int xenstore_fe_scan(const char *type, uint32_t domid,
+                            struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    unsigned int cdev, j;
+    char *backend;
+    char **dev = NULL;
+    int rc;
+
+    /* ops .init check, xendev is NOT initialized */
+    rc = xen_fe_try_init(ops);
+    if (rc != 0) {
+        return -1;
+    }
+
+    /* Get /local/domain/0/${type}/{} directory */
+    snprintf(path, sizeof(path), "frontend/%s", type);
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    if (dev == NULL) {
+        return 0;
+    }
+
+    for (j = 0; j < cdev; j++) {
+
+        /* Get backend via domain name */
+        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
+                                          domid, &xenstore_dev);
+        if (backend == NULL) {
+            continue;
+        }
+
+        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend, ops);
+        free(backend);
+        if (xendev == NULL) {
+            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
+            continue;
+        }
+
+        /*
+         * Simplify QEMU side, a thread is running in Xen backend, which will
+         * connect frontend when the frontend is initialised.
+         */
+        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
+            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
+            continue;
+        }
+
+        /* Setup watch */
+        snprintf(token, sizeof(token), "be:%p:%d:%p",
+                 type, domid, xendev->ops);
+        if (!xs_watch(xenstore, xendev->be, token)) {
+            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
+            continue;
+        }
+    }
+
+    free(dev);
+    return 0;
+}
+
+int xen_fe_register(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_fe_scan(type, xen_domid, ops);
+}
+
+/*
+ * msg_level:
+ *  0 == errors (stderr + logfile).
+ *  1 == informative debug messages (logfile only).
+ *  2 == noisy debug messages (logfile only).
+ *  3 == will flood your log (logfile only).
+ */
+void xen_fe_printf(struct XenDevice *xendev, int msg_level,
+                   const char *fmt, ...)
+{
+    va_list args;
+
+    if (xendev) {
+        if (msg_level > xendev->debug) {
+            return;
+        }
+        qemu_log("xen fe: %s: ", xendev->name);
+        if (msg_level == 0) {
+            fprintf(stderr, "xen fe: %s: ", xendev->name);
+        }
+    } else {
+        if (msg_level > debug) {
+            return;
+        }
+        qemu_log("xen fe core: ");
+        if (msg_level == 0) {
+            fprintf(stderr, "xen fe core: ");
+        }
+    }
+    va_start(args, fmt);
+    qemu_log_vprintf(fmt, args);
+    va_end(args);
+    if (msg_level == 0) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+    qemu_log_flush();
+}
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
new file mode 100644
index 0000000..dac8639
--- /dev/null
+++ b/hw/xen/xen_pvdev.c
@@ -0,0 +1,481 @@
+/*
+ * Xen para-virtualization device
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include "hw/hw.h"
+#include "sysemu/char.h"
+#include "qemu/log.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/grant_table.h>
+
+static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
+           QTAILQ_HEAD_INITIALIZER(xendevs);
+static int debug;
+
+/* public */
+XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
+struct xs_handle *xenstore;
+
+/*
+ * find Xen device
+ */
+struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    QTAILQ_FOREACH(xendev, &xendevs, next) {
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev) {
+            continue;
+        }
+        if (strcmp(xendev->type, type) != 0) {
+            continue;
+        }
+        return xendev;
+    }
+    return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                    struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+
+    xendev = xen_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = g_malloc0(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
+             xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * get xen fe device, allocate a new one if it doesn't exist.
+ */
+struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
+                                    char *backend, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+
+    xendev = xen_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = g_malloc0(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
+    if (!(ops->flags & DEVOPS_FLAG_FE)) {
+        return NULL;
+    }
+
+    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+
+    xendev->debug = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * release xen device
+ */
+
+struct XenDevice *xen_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_next;
+
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev && dev != -1) {
+            continue;
+        }
+
+        if (xendev->ops->free) {
+            xendev->ops->free(xendev);
+        }
+
+        if (xendev->fe) {
+            char token[XEN_BUFSIZE];
+            snprintf(token, sizeof(token), "fe:%p", xendev);
+            xs_unwatch(xenstore, xendev->fe, token);
+            g_free(xendev->fe);
+        }
+
+        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
+            xc_evtchn_close(xendev->evtchndev);
+        }
+        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
+            xc_gnttab_close(xendev->gnttabdev);
+        }
+
+        QTAILQ_REMOVE(&xendevs, xendev, next);
+        g_free(xendev);
+    }
+    return NULL;
+}
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_BUFSIZE];
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
+        return -1;
+    }
+    return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+    char abspath[XEN_BUFSIZE];
+    unsigned int len;
+    char *str, *ret = NULL;
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    str = xs_read(xenstore, 0, abspath, &len);
+    if (str != NULL) {
+        /* move to qemu-allocated memory to make sure
+         * callers can savely g_free() stuff. */
+        ret = g_strdup(str);
+        free(str);
+    }
+    return ret;
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+    char val[12];
+
+    snprintf(val, sizeof(val), "%d", ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_write_int64(const char *base, const char *node, int64_t ival)
+{
+    char val[21];
+
+    snprintf(val, sizeof(val), "%"PRId64, ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%d", ival)) {
+        rc = 0;
+    }
+    g_free(val);
+    return rc;
+}
+
+int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
+        rc = 0;
+    }
+    g_free(val);
+    return rc;
+}
+
+char *xenstore_get_domain_name(uint32_t domid)
+{
+    char *dom_path, *str, *ret = NULL;;
+
+    dom_path = xs_get_domain_path(xenstore, domid);
+    str = xenstore_read_str(dom_path, "name");
+    free(dom_path);
+    if (str != NULL) {
+        ret = g_strdup(str);
+        free(str);
+    }
+
+    return ret;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field.  node = NULL means
+ * update all fields (used for initialization).
+ */
+void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    if (node == NULL  ||  strcmp(node, "online") == 0) {
+        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
+            xendev->online = 0;
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "backend update: %s\n", node);
+        if (xendev->ops->backend_changed) {
+            xendev->ops->backend_changed(xendev, node);
+        }
+    }
+}
+
+void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    int fe_state;
+
+    if (node == NULL  ||  strcmp(node, "state") == 0) {
+        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+            fe_state = XenbusStateUnknown;
+        }
+        if (xendev->fe_state != fe_state) {
+            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+                          xenbus_strstate(xendev->fe_state),
+                          xenbus_strstate(fe_state));
+        }
+        xendev->fe_state = fe_state;
+    }
+    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
+        g_free(xendev->protocol);
+        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+        if (xendev->protocol) {
+            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
+                          xendev->protocol);
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+        if (xendev->ops->frontend_changed) {
+            xendev->ops->frontend_changed(xendev, node);
+        }
+    }
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+                        struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *bepath;
+    unsigned int len, dev;
+
+    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
+
+    if (strstr(watch, path) == NULL) {
+        return;
+    }
+    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+        strcpy(path, "");
+        if (sscanf(watch+len, "/%u", &dev) != 1) {
+            dev = -1;
+        }
+    }
+    if (dev == -1) {
+        return;
+    }
+
+    xendev = xen_be_get_xendev(type, dom, dev, ops);
+    if (xendev != NULL) {
+        bepath = xs_read(xenstore, 0, xendev->be, &len);
+        if (bepath == NULL) {
+            xen_del_xendev(dom, dev);
+        } else {
+            free(bepath);
+            xen_be_backend_changed(xendev, path);
+            if (!(ops->flags & DEVOPS_FLAG_FE)) {
+                xen_be_check_state(xendev);
+            }
+        }
+    }
+}
+
+static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+{
+    char *node;
+    unsigned int len;
+
+    len = strlen(xendev->fe);
+    if (strncmp(xendev->fe, watch, len) != 0) {
+        return;
+    }
+    if (watch[len] != '/') {
+        return;
+    }
+    node = watch + len + 1;
+
+    xen_be_frontend_changed(xendev, node);
+    xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+    char **vec = NULL;
+    intptr_t type, ops, ptr;
+    unsigned int dom, count;
+
+    vec = xs_read_watch(xenstore, &count);
+    if (vec == NULL) {
+        goto cleanup;
+    }
+
+    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+               &type, &dom, &ops) == 3) {
+        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void *)ops);
+    }
+    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
+        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
+    }
+
+cleanup:
+    free(vec);
+}
+
+int xen_be_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
+        NULL, NULL) < 0) {
+        goto err;
+    }
+
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+
+        /* Check if xen_init() have been called */
+        goto err;
+    }
+    return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index 3b4125e..bb0b303 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -15,6 +15,8 @@ struct XenDevice;
 #define DEVOPS_FLAG_NEED_GNTDEV   1
 /* don't expect frontend doing correct state transitions (aka console quirk) */
 #define DEVOPS_FLAG_IGNORE_STATE  2
+/*dev is frontend device*/
+#define DEVOPS_FLAG_FE            4
 
 struct XenDevOps {
     size_t    size;
@@ -59,6 +61,7 @@ struct XenDevice {
 extern XenXC xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
+extern int xenstore_dev;
 
 /* xenstore helper functions */
 int xenstore_write_str(const char *base, const char *node, const char *val);
@@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
 int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval);
 int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval);
 
+char *xenstore_get_domain_name(uint32_t domid);
+
 const char *xenbus_strstate(enum xenbus_state state);
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
+struct XenDevice *xen_del_xendev(int dom, int dev);
+struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                    struct XenDevOps *ops);
+struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
+                                    char *backend, struct XenDevOps *ops);
 void xen_be_check_state(struct XenDevice *xendev);
+void xen_be_backend_changed(struct XenDevice *xendev, const char *node);
+void xen_be_frontend_changed(struct XenDevice *xendev, const char *node);
 
 /* xen backend driver bits */
 int xen_be_init(void);
@@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice *xendev);
 int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
     GCC_FMT_ATTR(3, 4);
+void xen_fe_printf(struct XenDevice *xendev, int msg_level,
+                   const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+/* Xen frontend driver */
+int xen_fe_register(const char *type, struct XenDevOps *ops);
+int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
+int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
 
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
@@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
 extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
 extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
+extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/
 
 void xen_init_display(int domid);
 
-- 
1.8.3.2

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

* [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
@ 2015-05-04  7:22   ` Quan Xu
  0 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This patch adds infrastructure for xen front drivers living in qemu,
so drivers don't need to implement common stuff on their own.  It's
mostly xenbus management stuff: some functions to access XenStore,
setting up XenStore watches, callbacks on device discovery and state
changes, and handle event channel between the virtual machines.

Call xen_fe_register() function to register XenDevOps, and make sure,
XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
the XenDevOps is Xen frontend.

Create a new file xen_pvdev.c for some common part of xen frontend
and backend, such as xendevs queue and xenstore update functions.

Signed-off-by: Quan Xu <quan.xu@intel.com>
---
 hw/display/xenfb.c           |   4 +-
 hw/xen/Makefile.objs         |   2 +-
 hw/xen/xen_backend.c         | 353 -------------------------------
 hw/xen/xen_frontend.c        | 345 +++++++++++++++++++++++++++++++
 hw/xen/xen_pvdev.c           | 481 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/xen/xen_backend.h |  22 +-
 6 files changed, 850 insertions(+), 357 deletions(-)
 create mode 100644 hw/xen/xen_frontend.c
 create mode 100644 hw/xen/xen_pvdev.c

diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 5e324ef..10751df 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -988,8 +988,8 @@ void xen_init_display(int domid)
 wait_more:
     i++;
     main_loop_wait(true);
-    xfb = xen_be_find_xendev("vfb", domid, 0);
-    xin = xen_be_find_xendev("vkbd", domid, 0);
+    xfb = xen_find_xendev("vfb", domid, 0);
+    xin = xen_find_xendev("vkbd", domid, 0);
     if (!xfb || !xin) {
         if (i < 256) {
             usleep(10000);
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index a0ca0aa..95eb9d0 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -1,5 +1,5 @@
 # xen backend driver support
-common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o xen_frontend.o xen_pvdev.o
 
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
index b2cb22b..844f918 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen_backend.c
@@ -44,86 +44,11 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
-struct xs_handle *xenstore = NULL;
 const char *xen_protocol;
 
 /* private */
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
 static int debug = 0;
 
-/* ------------------------------------------------------------- */
-
-int xenstore_write_str(const char *base, const char *node, const char *val)
-{
-    char abspath[XEN_BUFSIZE];
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
-        return -1;
-    }
-    return 0;
-}
-
-char *xenstore_read_str(const char *base, const char *node)
-{
-    char abspath[XEN_BUFSIZE];
-    unsigned int len;
-    char *str, *ret = NULL;
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    str = xs_read(xenstore, 0, abspath, &len);
-    if (str != NULL) {
-        /* move to qemu-allocated memory to make sure
-         * callers can savely g_free() stuff. */
-        ret = g_strdup(str);
-        free(str);
-    }
-    return ret;
-}
-
-int xenstore_write_int(const char *base, const char *node, int ival)
-{
-    char val[12];
-
-    snprintf(val, sizeof(val), "%d", ival);
-    return xenstore_write_str(base, node, val);
-}
-
-int xenstore_write_int64(const char *base, const char *node, int64_t ival)
-{
-    char val[21];
-
-    snprintf(val, sizeof(val), "%"PRId64, ival);
-    return xenstore_write_str(base, node, val);
-}
-
-int xenstore_read_int(const char *base, const char *node, int *ival)
-{
-    char *val;
-    int rc = -1;
-
-    val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%d", ival)) {
-        rc = 0;
-    }
-    g_free(val);
-    return rc;
-}
-
-int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
-{
-    char *val;
-    int rc = -1;
-
-    val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
-        rc = 0;
-    }
-    g_free(val);
-    return rc;
-}
-
 int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
 {
     return xenstore_write_str(xendev->be, node, val);
@@ -195,183 +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
 }
 
 /* ------------------------------------------------------------- */
-
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
-{
-    struct XenDevice *xendev;
-
-    QTAILQ_FOREACH(xendev, &xendevs, next) {
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev) {
-            continue;
-        }
-        if (strcmp(xendev->type, type) != 0) {
-            continue;
-        }
-        return xendev;
-    }
-    return NULL;
-}
-
-/*
- * get xen backend device, allocate a new one if it doesn't exist.
- */
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
-                                           struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-
-    xendev = xen_be_find_xendev(type, dom, dev);
-    if (xendev) {
-        return xendev;
-    }
-
-    /* init new xendev */
-    xendev = g_malloc0(ops->size);
-    xendev->type  = type;
-    xendev->dom   = dom;
-    xendev->dev   = dev;
-    xendev->ops   = ops;
-
-    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
-             xendev->type, xendev->dom, xendev->dev);
-    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
-             xendev->type, xendev->dev);
-
-    xendev->debug      = debug;
-    xendev->local_port = -1;
-
-    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
-    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
-        xen_be_printf(NULL, 0, "can't open evtchn device\n");
-        g_free(xendev);
-        return NULL;
-    }
-    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
-
-    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
-        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
-            xen_be_printf(NULL, 0, "can't open gnttab device\n");
-            xc_evtchn_close(xendev->evtchndev);
-            g_free(xendev);
-            return NULL;
-        }
-    } else {
-        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
-    }
-
-    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
-
-    if (xendev->ops->alloc) {
-        xendev->ops->alloc(xendev);
-    }
-
-    return xendev;
-}
-
-/*
- * release xen backend device.
- */
-static struct XenDevice *xen_be_del_xendev(int dom, int dev)
-{
-    struct XenDevice *xendev, *xnext;
-
-    /*
-     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
-     * we save the next pointer in xnext because we might free xendev.
-     */
-    xnext = xendevs.tqh_first;
-    while (xnext) {
-        xendev = xnext;
-        xnext = xendev->next.tqe_next;
-
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev && dev != -1) {
-            continue;
-        }
-
-        if (xendev->ops->free) {
-            xendev->ops->free(xendev);
-        }
-
-        if (xendev->fe) {
-            char token[XEN_BUFSIZE];
-            snprintf(token, sizeof(token), "fe:%p", xendev);
-            xs_unwatch(xenstore, xendev->fe, token);
-            g_free(xendev->fe);
-        }
-
-        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
-            xc_evtchn_close(xendev->evtchndev);
-        }
-        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
-            xc_gnttab_close(xendev->gnttabdev);
-        }
-
-        QTAILQ_REMOVE(&xendevs, xendev, next);
-        g_free(xendev);
-    }
-    return NULL;
-}
-
-/*
- * Sync internal data structures on xenstore updates.
- * Node specifies the changed field.  node = NULL means
- * update all fields (used for initialization).
- */
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
-{
-    if (node == NULL  ||  strcmp(node, "online") == 0) {
-        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
-            xendev->online = 0;
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "backend update: %s\n", node);
-        if (xendev->ops->backend_changed) {
-            xendev->ops->backend_changed(xendev, node);
-        }
-    }
-}
-
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
-{
-    int fe_state;
-
-    if (node == NULL  ||  strcmp(node, "state") == 0) {
-        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
-            fe_state = XenbusStateUnknown;
-        }
-        if (xendev->fe_state != fe_state) {
-            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
-                          xenbus_strstate(xendev->fe_state),
-                          xenbus_strstate(fe_state));
-        }
-        xendev->fe_state = fe_state;
-    }
-    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
-        g_free(xendev->protocol);
-        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
-        if (xendev->protocol) {
-            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
-        if (xendev->ops->frontend_changed) {
-            xendev->ops->frontend_changed(xendev, node);
-        }
-    }
-}
-
-/* ------------------------------------------------------------- */
 /* Check for possible state transitions and perform them.        */
 
 /*
@@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
     return 0;
 }
 
-static void xenstore_update_be(char *watch, char *type, int dom,
-                               struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-    char path[XEN_BUFSIZE], *bepath;
-    unsigned int len, dev;
-
-    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
-    if (strncmp(path, watch, len) != 0) {
-        return;
-    }
-    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
-        strcpy(path, "");
-        if (sscanf(watch+len, "/%u", &dev) != 1) {
-            dev = -1;
-        }
-    }
-    if (dev == -1) {
-        return;
-    }
-
-    xendev = xen_be_get_xendev(type, dom, dev, ops);
-    if (xendev != NULL) {
-        bepath = xs_read(xenstore, 0, xendev->be, &len);
-        if (bepath == NULL) {
-            xen_be_del_xendev(dom, dev);
-        } else {
-            free(bepath);
-            xen_be_backend_changed(xendev, path);
-            xen_be_check_state(xendev);
-        }
-    }
-}
-
-static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
-{
-    char *node;
-    unsigned int len;
-
-    len = strlen(xendev->fe);
-    if (strncmp(xendev->fe, watch, len) != 0) {
-        return;
-    }
-    if (watch[len] != '/') {
-        return;
-    }
-    node = watch + len + 1;
-
-    xen_be_frontend_changed(xendev, node);
-    xen_be_check_state(xendev);
-}
-
-static void xenstore_update(void *unused)
-{
-    char **vec = NULL;
-    intptr_t type, ops, ptr;
-    unsigned int dom, count;
-
-    vec = xs_read_watch(xenstore, &count);
-    if (vec == NULL) {
-        goto cleanup;
-    }
-
-    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
-               &type, &dom, &ops) == 3) {
-        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
-    }
-    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
-        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
-    }
-
-cleanup:
-    free(vec);
-}
-
 static void xen_be_evtchn_event(void *opaque)
 {
     struct XenDevice *xendev = opaque;
@@ -706,32 +379,6 @@ static void xen_be_evtchn_event(void *opaque)
 
 /* -------------------------------------------------------------------- */
 
-int xen_be_init(void)
-{
-    xenstore = xs_daemon_open();
-    if (!xenstore) {
-        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
-        return -1;
-    }
-
-    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
-        goto err;
-    }
-
-    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
-        /* Check if xen_init() have been called */
-        goto err;
-    }
-    return 0;
-
-err:
-    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
-    xs_daemon_close(xenstore);
-    xenstore = NULL;
-
-    return -1;
-}
-
 int xen_be_register(const char *type, struct XenDevOps *ops)
 {
     return xenstore_scan(type, xen_domid, ops);
diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
new file mode 100644
index 0000000..55af45a
--- /dev/null
+++ b/hw/xen/xen_frontend.c
@@ -0,0 +1,345 @@
+/*
+ * Xen frontend driver infrastructure
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include "hw/hw.h"
+#include "sysemu/char.h"
+#include "qemu/log.h"
+#include "hw/xen/xen_backend.h"
+#include <xen/grant_table.h>
+
+int xenstore_dev;
+
+/* private */
+static int debug;
+
+static void xen_fe_evtchn_event(void *opaque)
+{
+    struct XenDevice *xendev = opaque;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xendev->evtchndev);
+    if (port != xendev->local_port) {
+        return;
+    }
+    xc_evtchn_unmask(xendev->evtchndev, port);
+
+    if (xendev->ops->event) {
+        xendev->ops->event(xendev);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
+{
+    xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
+                                                     remote_dom);
+    if (xendev->local_port == -1) {
+        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
+        return -1;
+    }
+    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+                        xen_fe_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+/*
+ * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
+ * xendev->ops->initialize()
+ */
+int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus)
+{
+    xs_transaction_t xbt = XBT_NULL;
+
+    if (xendev->fe_state == xbus) {
+        return 0;
+    }
+
+    xendev->fe_state = xbus;
+    if (xendev->fe == NULL) {
+        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
+        return -1;
+    }
+
+retry_transaction:
+    xbt = xs_transaction_start(xenstore);
+    if (xbt == XBT_NULL) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(xendev->fe, "state", xbus)) {
+        goto abort_transaction;
+    }
+
+    if (!xs_transaction_end(xenstore, xbt, 0)) {
+        if (errno == EAGAIN) {
+            goto retry_transaction;
+        }
+    }
+
+    return 0;
+
+abort_transaction:
+    xs_transaction_end(xenstore, xbt, 1);
+    return -1;
+}
+
+/*
+ * Simplify QEMU side, a thread is running in Xen backend, which will
+ * connect frontend when the frontend is initialised. Call these initialised
+ * functions.
+ */
+static int xen_fe_try_init(void *opaque)
+{
+    struct XenDevOps *ops = opaque;
+    int rc = -1;
+
+    if (ops->init) {
+        rc = ops->init(NULL);
+    }
+
+    return rc;
+}
+
+static int xen_fe_try_initialise(struct XenDevice *xendev)
+{
+    int rc = 0, fe_state;
+
+    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+        fe_state = XenbusStateUnknown;
+    }
+    xendev->fe_state = fe_state;
+
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
+    }
+    if (rc != 0) {
+        xen_fe_printf(xendev, 0, "initialise() failed\n");
+        return rc;
+    }
+
+    xenbus_switch_state(xendev, XenbusStateInitialised);
+    return 0;
+}
+
+static void xen_fe_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
+static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
+                        int handle)
+{
+    int rc = 0;
+
+    rc = xen_fe_try_initialise(xendev);
+    if (rc != 0) {
+        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
+                      xendev->name);
+        goto err;
+    }
+    xen_fe_try_connected(xendev);
+
+    return rc;
+
+err:
+    xen_del_xendev(domid, handle);
+    return -1;
+}
+
+static char *xenstore_fe_get_backend(const char *type, int be_domid,
+                                     uint32_t domid, int *hdl)
+{
+    char *name, *str, *ret = NULL;
+    uint32_t i, cdev;
+    int handle = 0;
+    char path[XEN_BUFSIZE];
+    char **dev = NULL;
+
+    name = xenstore_get_domain_name(domid);
+    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    for (i = 0; i < cdev; i++) {
+        handle = i;
+        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
+        type, be_domid, handle);
+        str = xenstore_read_str(path, "domain");
+        if (!strcmp(name, str)) {
+            break;
+        }
+
+        free(str);
+
+        /* Not the backend domain */
+        if (handle == (cdev - 1)) {
+            goto err;
+        }
+    }
+
+    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
+    type, be_domid, handle);
+    str = xenstore_read_str(path, "backend");
+    if (str != NULL) {
+        ret = g_strdup(str);
+        free(str);
+    }
+
+    *hdl = handle;
+    free(dev);
+
+    return ret;
+err:
+    *hdl = -1;
+    free(dev);
+    return NULL;
+}
+
+static int xenstore_fe_scan(const char *type, uint32_t domid,
+                            struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    unsigned int cdev, j;
+    char *backend;
+    char **dev = NULL;
+    int rc;
+
+    /* ops .init check, xendev is NOT initialized */
+    rc = xen_fe_try_init(ops);
+    if (rc != 0) {
+        return -1;
+    }
+
+    /* Get /local/domain/0/${type}/{} directory */
+    snprintf(path, sizeof(path), "frontend/%s", type);
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    if (dev == NULL) {
+        return 0;
+    }
+
+    for (j = 0; j < cdev; j++) {
+
+        /* Get backend via domain name */
+        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
+                                          domid, &xenstore_dev);
+        if (backend == NULL) {
+            continue;
+        }
+
+        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend, ops);
+        free(backend);
+        if (xendev == NULL) {
+            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
+            continue;
+        }
+
+        /*
+         * Simplify QEMU side, a thread is running in Xen backend, which will
+         * connect frontend when the frontend is initialised.
+         */
+        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
+            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
+            continue;
+        }
+
+        /* Setup watch */
+        snprintf(token, sizeof(token), "be:%p:%d:%p",
+                 type, domid, xendev->ops);
+        if (!xs_watch(xenstore, xendev->be, token)) {
+            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
+            continue;
+        }
+    }
+
+    free(dev);
+    return 0;
+}
+
+int xen_fe_register(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_fe_scan(type, xen_domid, ops);
+}
+
+/*
+ * msg_level:
+ *  0 == errors (stderr + logfile).
+ *  1 == informative debug messages (logfile only).
+ *  2 == noisy debug messages (logfile only).
+ *  3 == will flood your log (logfile only).
+ */
+void xen_fe_printf(struct XenDevice *xendev, int msg_level,
+                   const char *fmt, ...)
+{
+    va_list args;
+
+    if (xendev) {
+        if (msg_level > xendev->debug) {
+            return;
+        }
+        qemu_log("xen fe: %s: ", xendev->name);
+        if (msg_level == 0) {
+            fprintf(stderr, "xen fe: %s: ", xendev->name);
+        }
+    } else {
+        if (msg_level > debug) {
+            return;
+        }
+        qemu_log("xen fe core: ");
+        if (msg_level == 0) {
+            fprintf(stderr, "xen fe core: ");
+        }
+    }
+    va_start(args, fmt);
+    qemu_log_vprintf(fmt, args);
+    va_end(args);
+    if (msg_level == 0) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+    qemu_log_flush();
+}
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
new file mode 100644
index 0000000..dac8639
--- /dev/null
+++ b/hw/xen/xen_pvdev.c
@@ -0,0 +1,481 @@
+/*
+ * Xen para-virtualization device
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include "hw/hw.h"
+#include "sysemu/char.h"
+#include "qemu/log.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/grant_table.h>
+
+static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
+           QTAILQ_HEAD_INITIALIZER(xendevs);
+static int debug;
+
+/* public */
+XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
+struct xs_handle *xenstore;
+
+/*
+ * find Xen device
+ */
+struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    QTAILQ_FOREACH(xendev, &xendevs, next) {
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev) {
+            continue;
+        }
+        if (strcmp(xendev->type, type) != 0) {
+            continue;
+        }
+        return xendev;
+    }
+    return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                    struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+
+    xendev = xen_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = g_malloc0(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
+             xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * get xen fe device, allocate a new one if it doesn't exist.
+ */
+struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
+                                    char *backend, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+
+    xendev = xen_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = g_malloc0(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
+    if (!(ops->flags & DEVOPS_FLAG_FE)) {
+        return NULL;
+    }
+
+    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+
+    xendev->debug = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * release xen device
+ */
+
+struct XenDevice *xen_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_next;
+
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev && dev != -1) {
+            continue;
+        }
+
+        if (xendev->ops->free) {
+            xendev->ops->free(xendev);
+        }
+
+        if (xendev->fe) {
+            char token[XEN_BUFSIZE];
+            snprintf(token, sizeof(token), "fe:%p", xendev);
+            xs_unwatch(xenstore, xendev->fe, token);
+            g_free(xendev->fe);
+        }
+
+        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
+            xc_evtchn_close(xendev->evtchndev);
+        }
+        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
+            xc_gnttab_close(xendev->gnttabdev);
+        }
+
+        QTAILQ_REMOVE(&xendevs, xendev, next);
+        g_free(xendev);
+    }
+    return NULL;
+}
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_BUFSIZE];
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
+        return -1;
+    }
+    return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+    char abspath[XEN_BUFSIZE];
+    unsigned int len;
+    char *str, *ret = NULL;
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    str = xs_read(xenstore, 0, abspath, &len);
+    if (str != NULL) {
+        /* move to qemu-allocated memory to make sure
+         * callers can savely g_free() stuff. */
+        ret = g_strdup(str);
+        free(str);
+    }
+    return ret;
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+    char val[12];
+
+    snprintf(val, sizeof(val), "%d", ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_write_int64(const char *base, const char *node, int64_t ival)
+{
+    char val[21];
+
+    snprintf(val, sizeof(val), "%"PRId64, ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%d", ival)) {
+        rc = 0;
+    }
+    g_free(val);
+    return rc;
+}
+
+int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
+        rc = 0;
+    }
+    g_free(val);
+    return rc;
+}
+
+char *xenstore_get_domain_name(uint32_t domid)
+{
+    char *dom_path, *str, *ret = NULL;;
+
+    dom_path = xs_get_domain_path(xenstore, domid);
+    str = xenstore_read_str(dom_path, "name");
+    free(dom_path);
+    if (str != NULL) {
+        ret = g_strdup(str);
+        free(str);
+    }
+
+    return ret;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field.  node = NULL means
+ * update all fields (used for initialization).
+ */
+void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    if (node == NULL  ||  strcmp(node, "online") == 0) {
+        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
+            xendev->online = 0;
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "backend update: %s\n", node);
+        if (xendev->ops->backend_changed) {
+            xendev->ops->backend_changed(xendev, node);
+        }
+    }
+}
+
+void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    int fe_state;
+
+    if (node == NULL  ||  strcmp(node, "state") == 0) {
+        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+            fe_state = XenbusStateUnknown;
+        }
+        if (xendev->fe_state != fe_state) {
+            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+                          xenbus_strstate(xendev->fe_state),
+                          xenbus_strstate(fe_state));
+        }
+        xendev->fe_state = fe_state;
+    }
+    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
+        g_free(xendev->protocol);
+        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+        if (xendev->protocol) {
+            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
+                          xendev->protocol);
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+        if (xendev->ops->frontend_changed) {
+            xendev->ops->frontend_changed(xendev, node);
+        }
+    }
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+                        struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *bepath;
+    unsigned int len, dev;
+
+    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
+
+    if (strstr(watch, path) == NULL) {
+        return;
+    }
+    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+        strcpy(path, "");
+        if (sscanf(watch+len, "/%u", &dev) != 1) {
+            dev = -1;
+        }
+    }
+    if (dev == -1) {
+        return;
+    }
+
+    xendev = xen_be_get_xendev(type, dom, dev, ops);
+    if (xendev != NULL) {
+        bepath = xs_read(xenstore, 0, xendev->be, &len);
+        if (bepath == NULL) {
+            xen_del_xendev(dom, dev);
+        } else {
+            free(bepath);
+            xen_be_backend_changed(xendev, path);
+            if (!(ops->flags & DEVOPS_FLAG_FE)) {
+                xen_be_check_state(xendev);
+            }
+        }
+    }
+}
+
+static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+{
+    char *node;
+    unsigned int len;
+
+    len = strlen(xendev->fe);
+    if (strncmp(xendev->fe, watch, len) != 0) {
+        return;
+    }
+    if (watch[len] != '/') {
+        return;
+    }
+    node = watch + len + 1;
+
+    xen_be_frontend_changed(xendev, node);
+    xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+    char **vec = NULL;
+    intptr_t type, ops, ptr;
+    unsigned int dom, count;
+
+    vec = xs_read_watch(xenstore, &count);
+    if (vec == NULL) {
+        goto cleanup;
+    }
+
+    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+               &type, &dom, &ops) == 3) {
+        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void *)ops);
+    }
+    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
+        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
+    }
+
+cleanup:
+    free(vec);
+}
+
+int xen_be_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
+        NULL, NULL) < 0) {
+        goto err;
+    }
+
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+
+        /* Check if xen_init() have been called */
+        goto err;
+    }
+    return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index 3b4125e..bb0b303 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -15,6 +15,8 @@ struct XenDevice;
 #define DEVOPS_FLAG_NEED_GNTDEV   1
 /* don't expect frontend doing correct state transitions (aka console quirk) */
 #define DEVOPS_FLAG_IGNORE_STATE  2
+/*dev is frontend device*/
+#define DEVOPS_FLAG_FE            4
 
 struct XenDevOps {
     size_t    size;
@@ -59,6 +61,7 @@ struct XenDevice {
 extern XenXC xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
+extern int xenstore_dev;
 
 /* xenstore helper functions */
 int xenstore_write_str(const char *base, const char *node, const char *val);
@@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
 int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval);
 int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval);
 
+char *xenstore_get_domain_name(uint32_t domid);
+
 const char *xenbus_strstate(enum xenbus_state state);
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
+struct XenDevice *xen_del_xendev(int dom, int dev);
+struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                    struct XenDevOps *ops);
+struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
+                                    char *backend, struct XenDevOps *ops);
 void xen_be_check_state(struct XenDevice *xendev);
+void xen_be_backend_changed(struct XenDevice *xendev, const char *node);
+void xen_be_frontend_changed(struct XenDevice *xendev, const char *node);
 
 /* xen backend driver bits */
 int xen_be_init(void);
@@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice *xendev);
 int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
     GCC_FMT_ATTR(3, 4);
+void xen_fe_printf(struct XenDevice *xendev, int msg_level,
+                   const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+/* Xen frontend driver */
+int xen_fe_register(const char *type, struct XenDevOps *ops);
+int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
+int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
 
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
@@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
 extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
 extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
 extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
+extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/
 
 void xen_init_display(int domid);
 
-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
@ 2015-05-04  7:22   ` Quan Xu
  2015-05-04  7:22 ` Quan Xu
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This patch adds infrastructure for xen front drivers living in qemu,
so drivers don't need to implement common stuff on their own.  It's
mostly xenbus management stuff: some functions to access XenStore,
setting up XenStore watches, callbacks on device discovery and state
changes, and handle event channel between the virtual machines.

Call xen_fe_register() function to register XenDevOps, and make sure,
         [...]
    3 = ""
     [...]
     device = "" (frontend device, the backend is running in QEMU/.etc)
      vkbd = ""
       [...]
      vif = ""
       [...]

 ..

(QEMU) xen_vtpmdev_ops is initialized with the following process:
  xen_hvm_init()
    [...]
    -->xen_fe_register("vtpm", ...)
      -->xenstore_fe_scan()
        -->xen_fe_try_init(ops)
          --> XenDevOps.init()
        -->xen_fe_get_xendev()
          --> XenDevOps.alloc()
        -->xen_fe_check()
          -->xen_fe_try_initialise()
            --> XenDevOps.initialise()
          -->xen_fe_try_connected()
            --> XenDevOps.connected()
        -->xs_watch()
    [...]

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Replace buf_size with PAGE_SIZE and use length rather than
  shr->length.
---
 hw/tpm/Makefile.objs         |   1 +
 hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
 hw/xen/xen_frontend.c        |  20 +++
 include/hw/xen/xen_backend.h |   5 +
 include/hw/xen/xen_common.h  |   6 +
 xen-hvm.c                    |   5 +
 6 files changed, 352 insertions(+)
 create mode 100644 hw/tpm/xen_vtpm_frontend.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 99f5983..57919fa 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,3 @@
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
new file mode 100644
index 0000000..d6e7cc6
--- /dev/null
+++ b/hw/tpm/xen_vtpm_frontend.c
@@ -0,0 +1,315 @@
+/*
+ * Connect to Xen vTPM stubdom domain
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include "hw/hw.h"
+#include "block/aio.h"
+#include "hw/xen/xen_backend.h"
+
+#ifndef XS_STUBDOM_VTPM_ENABLE
+#define XS_STUBDOM_VTPM_ENABLE    "1"
+#endif
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE      4096
+#endif
+
+enum tpmif_state {
+    /* No contents, vTPM idle, cancel complete */
+    TPMIF_STATE_IDLE,
+    /* Request ready or vTPM working */
+    TPMIF_STATE_SUBMIT,
+    /* Response ready or vTPM idle */
+    TPMIF_STATE_FINISH,
+    /* Cancel requested or vTPM working */
+    TPMIF_STATE_CANCEL,
+};
+
+static AioContext *vtpm_aio_ctx;
+
+enum status_bits {
+    VTPM_STATUS_RUNNING  = 0x1,
+    VTPM_STATUS_IDLE     = 0x2,
+    VTPM_STATUS_RESULT   = 0x4,
+    VTPM_STATUS_CANCELED = 0x8,
+};
+
+struct tpmif_shared_page {
+    /* Request and response length in bytes */
+    uint32_t length;
+    /* Enum tpmif_state */
+    uint8_t  state;
+    /* For the current request */
+    uint8_t  locality;
+    /* Should be zero */
+    uint8_t  pad;
+    /* Extra pages for long packets; may be zero */
+    uint8_t  nr_extra_pages;
+    /*
+     * Grant IDs, the length is actually nr_extra_pages.
+     * beyond the extra_pages entries is the actual request
+     * and response.
+     */
+    uint32_t extra_pages[0];
+};
+
+struct xen_vtpm_dev {
+    struct XenDevice xendev;  /* must be first */
+    struct           tpmif_shared_page *shr;
+    xc_gntshr        *xen_xcs;
+    int              ring_ref;
+    int              bedomid;
+    QEMUBH           *sr_bh;
+};
+
+static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev)
+{
+    switch (vtpmdev->shr->state) {
+    case TPMIF_STATE_IDLE:
+    case TPMIF_STATE_FINISH:
+        return VTPM_STATUS_IDLE;
+    case TPMIF_STATE_SUBMIT:
+    case TPMIF_STATE_CANCEL:
+        return VTPM_STATUS_RUNNING;
+    default:
+        return 0;
+    }
+}
+
+static bool vtpm_aio_wait(AioContext *ctx)
+{
+    return aio_poll(ctx, true);
+}
+
+static void sr_bh_handler(void *opaque)
+{
+}
+
+int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    struct tpmif_shared_page *shr = vtpmdev->shr;
+    unsigned int offset;
+    size_t length = shr->length;
+
+    if (shr->state == TPMIF_STATE_IDLE) {
+        return -ECANCELED;
+    }
+
+    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
+    if (offset > PAGE_SIZE) {
+        return -EIO;
+    }
+
+    if (offset + length > PAGE_SIZE) {
+        length = PAGE_SIZE - offset;
+    }
+
+    memcpy(buf, offset + (uint8_t *)shr, length);
+    *count = length;
+
+    return 0;
+}
+
+int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    struct tpmif_shared_page *shr = vtpmdev->shr;
+    unsigned int offset = sizeof(*shr) +
+                          sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
+
+    if (offset > PAGE_SIZE) {
+        return -EIO;
+    }
+
+    if (offset + count > PAGE_SIZE) {
+        return -ECANCELED;
+    }
+
+    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
+        vtpm_aio_wait(vtpm_aio_ctx);
+    }
+
+    memcpy(offset + (uint8_t *)shr, buf, count);
+    shr->length = count;
+    barrier();
+    shr->state = TPMIF_STATE_SUBMIT;
+    xen_wmb();
+    xen_be_send_notify(&vtpmdev->xendev);
+
+    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
+        vtpm_aio_wait(vtpm_aio_ctx);
+    }
+
+    return count;
+}
+
+static int vtpm_initialise(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    xs_transaction_t xbt = XBT_NULL;
+    unsigned int ring_ref;
+
+    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev, "frontend");
+    if (vtpmdev->xendev.fe == NULL) {
+        return -1;
+    }
+
+    /* Get backend domid */
+    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
+                             &vtpmdev->bedomid)) {
+        return -1;
+    }
+
+    /* Alloc shared page */
+    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs, vtpmdev->bedomid, 1,
+                                         &ring_ref, PROT_READ|PROT_WRITE);
+    vtpmdev->ring_ref = ring_ref;
+    if (vtpmdev->shr == NULL) {
+        return -1;
+    }
+
+    /* Create event channel */
+    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
+        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+        return -1;
+    }
+
+    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
+                     vtpmdev->xendev.local_port);
+
+again:
+    xbt = xs_transaction_start(xenstore);
+    if (xbt == XBT_NULL) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
+                           vtpmdev->ring_ref)) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
+                           vtpmdev->xendev.local_port)) {
+        goto abort_transaction;
+    }
+
+    /* Publish protocol v2 feature */
+    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
+        goto abort_transaction;
+    }
+
+    if (!xs_transaction_end(xenstore, xbt, 0)) {
+        if (errno == EAGAIN) {
+            goto again;
+        }
+    }
+
+    return 0;
+
+abort_transaction:
+    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+    xs_transaction_end(xenstore, xbt, 1);
+    return -1;
+}
+
+static int vtpm_free(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    aio_poll(vtpm_aio_ctx, false);
+    qemu_bh_delete(vtpmdev->sr_bh);
+    if (vtpmdev->shr) {
+        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+    }
+    xc_interface_close(vtpmdev->xen_xcs);
+    return 0;
+}
+
+static int vtpm_init(struct XenDevice *xendev)
+{
+    char path[XEN_BUFSIZE];
+    char *value;
+    unsigned int stubdom_vtpm = 0;
+
+    snprintf(path, sizeof(path), "/local/domain/%d/platform/acpi_stubdom_vtpm",
+             xen_domid);
+    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
+    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
+        free(value);
+        return -1;
+    }
+    free(value);
+    return 0;
+}
+
+static void vtpm_alloc(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    vtpm_aio_ctx = aio_context_new(NULL);
+    if (vtpm_aio_ctx == NULL) {
+        return;
+    }
+    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
+    qemu_bh_schedule(vtpmdev->sr_bh);
+    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0);
+}
+
+static void vtpm_event(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    qemu_bh_schedule(vtpmdev->sr_bh);
+}
+
+struct XenDevOps xen_vtpmdev_ops = {
+    .size             = sizeof(struct xen_vtpm_dev),
+    .flags            = DEVOPS_FLAG_IGNORE_STATE |
+                        DEVOPS_FLAG_FE,
+    .event            = vtpm_event,
+    .free             = vtpm_free,
+    .init             = vtpm_init,
+    .alloc            = vtpm_alloc,
+    .initialise       = vtpm_initialise,
+    .backend_changed  = vtpm_backend_changed,
+};
diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
index 55af45a..1ca7342 100644
--- a/hw/xen/xen_frontend.c
+++ b/hw/xen/xen_frontend.c
@@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
 
 /* ------------------------------------------------------------- */
 
+void vtpm_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    int be_state;
+
+    if (strcmp(node, "state") == 0) {
+        xenstore_read_be_int(xendev, node, &be_state);
+        switch (be_state) {
+        case XenbusStateConnected:
+            /* TODO */
+            break;
+        case XenbusStateClosing:
+        case XenbusStateClosed:
+            xenbus_switch_state(xendev, XenbusStateClosing);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
 int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
 {
     xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index bb0b303..b959413 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps *ops);
 int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
 int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
 
+/* Xen vtpm */
+int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
+int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
+void vtpm_backend_changed(struct XenDevice *xendev, const char *node);
+
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 38f29fb..7268d0c 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
     return xc_interface_open(logger, dombuild_logger, open_flags);
 }
 
+static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
+                                            unsigned int open_flags)
+{
+    return xc_gntshr_open(logger, open_flags);
+}
+
 /* FIXME There is now way to have the xen fd */
 static inline int xc_fd(xc_interface *xen_xc)
 {
diff --git a/xen-hvm.c b/xen-hvm.c
index 315864c..b2403dc 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         return -1;
     }
+
+#ifdef CONFIG_TPM_XENSTUBDOMS
+    xen_fe_register("vtpm", &xen_vtpmdev_ops);
+#endif
+
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("qdisk", &xen_blkdev_ops);
-- 
1.8.3.2

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

* [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
@ 2015-05-04  7:22   ` Quan Xu
  0 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This patch adds infrastructure for xen front drivers living in qemu,
so drivers don't need to implement common stuff on their own.  It's
mostly xenbus management stuff: some functions to access XenStore,
setting up XenStore watches, callbacks on device discovery and state
changes, and handle event channel between the virtual machines.

Call xen_fe_register() function to register XenDevOps, and make sure,
         [...]
    3 = ""
     [...]
     device = "" (frontend device, the backend is running in QEMU/.etc)
      vkbd = ""
       [...]
      vif = ""
       [...]

 ..

(QEMU) xen_vtpmdev_ops is initialized with the following process:
  xen_hvm_init()
    [...]
    -->xen_fe_register("vtpm", ...)
      -->xenstore_fe_scan()
        -->xen_fe_try_init(ops)
          --> XenDevOps.init()
        -->xen_fe_get_xendev()
          --> XenDevOps.alloc()
        -->xen_fe_check()
          -->xen_fe_try_initialise()
            --> XenDevOps.initialise()
          -->xen_fe_try_connected()
            --> XenDevOps.connected()
        -->xs_watch()
    [...]

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Replace buf_size with PAGE_SIZE and use length rather than
  shr->length.
---
 hw/tpm/Makefile.objs         |   1 +
 hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
 hw/xen/xen_frontend.c        |  20 +++
 include/hw/xen/xen_backend.h |   5 +
 include/hw/xen/xen_common.h  |   6 +
 xen-hvm.c                    |   5 +
 6 files changed, 352 insertions(+)
 create mode 100644 hw/tpm/xen_vtpm_frontend.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 99f5983..57919fa 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,3 @@
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
+common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
new file mode 100644
index 0000000..d6e7cc6
--- /dev/null
+++ b/hw/tpm/xen_vtpm_frontend.c
@@ -0,0 +1,315 @@
+/*
+ * Connect to Xen vTPM stubdom domain
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include "hw/hw.h"
+#include "block/aio.h"
+#include "hw/xen/xen_backend.h"
+
+#ifndef XS_STUBDOM_VTPM_ENABLE
+#define XS_STUBDOM_VTPM_ENABLE    "1"
+#endif
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE      4096
+#endif
+
+enum tpmif_state {
+    /* No contents, vTPM idle, cancel complete */
+    TPMIF_STATE_IDLE,
+    /* Request ready or vTPM working */
+    TPMIF_STATE_SUBMIT,
+    /* Response ready or vTPM idle */
+    TPMIF_STATE_FINISH,
+    /* Cancel requested or vTPM working */
+    TPMIF_STATE_CANCEL,
+};
+
+static AioContext *vtpm_aio_ctx;
+
+enum status_bits {
+    VTPM_STATUS_RUNNING  = 0x1,
+    VTPM_STATUS_IDLE     = 0x2,
+    VTPM_STATUS_RESULT   = 0x4,
+    VTPM_STATUS_CANCELED = 0x8,
+};
+
+struct tpmif_shared_page {
+    /* Request and response length in bytes */
+    uint32_t length;
+    /* Enum tpmif_state */
+    uint8_t  state;
+    /* For the current request */
+    uint8_t  locality;
+    /* Should be zero */
+    uint8_t  pad;
+    /* Extra pages for long packets; may be zero */
+    uint8_t  nr_extra_pages;
+    /*
+     * Grant IDs, the length is actually nr_extra_pages.
+     * beyond the extra_pages entries is the actual request
+     * and response.
+     */
+    uint32_t extra_pages[0];
+};
+
+struct xen_vtpm_dev {
+    struct XenDevice xendev;  /* must be first */
+    struct           tpmif_shared_page *shr;
+    xc_gntshr        *xen_xcs;
+    int              ring_ref;
+    int              bedomid;
+    QEMUBH           *sr_bh;
+};
+
+static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev)
+{
+    switch (vtpmdev->shr->state) {
+    case TPMIF_STATE_IDLE:
+    case TPMIF_STATE_FINISH:
+        return VTPM_STATUS_IDLE;
+    case TPMIF_STATE_SUBMIT:
+    case TPMIF_STATE_CANCEL:
+        return VTPM_STATUS_RUNNING;
+    default:
+        return 0;
+    }
+}
+
+static bool vtpm_aio_wait(AioContext *ctx)
+{
+    return aio_poll(ctx, true);
+}
+
+static void sr_bh_handler(void *opaque)
+{
+}
+
+int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    struct tpmif_shared_page *shr = vtpmdev->shr;
+    unsigned int offset;
+    size_t length = shr->length;
+
+    if (shr->state == TPMIF_STATE_IDLE) {
+        return -ECANCELED;
+    }
+
+    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
+    if (offset > PAGE_SIZE) {
+        return -EIO;
+    }
+
+    if (offset + length > PAGE_SIZE) {
+        length = PAGE_SIZE - offset;
+    }
+
+    memcpy(buf, offset + (uint8_t *)shr, length);
+    *count = length;
+
+    return 0;
+}
+
+int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    struct tpmif_shared_page *shr = vtpmdev->shr;
+    unsigned int offset = sizeof(*shr) +
+                          sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
+
+    if (offset > PAGE_SIZE) {
+        return -EIO;
+    }
+
+    if (offset + count > PAGE_SIZE) {
+        return -ECANCELED;
+    }
+
+    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
+        vtpm_aio_wait(vtpm_aio_ctx);
+    }
+
+    memcpy(offset + (uint8_t *)shr, buf, count);
+    shr->length = count;
+    barrier();
+    shr->state = TPMIF_STATE_SUBMIT;
+    xen_wmb();
+    xen_be_send_notify(&vtpmdev->xendev);
+
+    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
+        vtpm_aio_wait(vtpm_aio_ctx);
+    }
+
+    return count;
+}
+
+static int vtpm_initialise(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+    xs_transaction_t xbt = XBT_NULL;
+    unsigned int ring_ref;
+
+    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev, "frontend");
+    if (vtpmdev->xendev.fe == NULL) {
+        return -1;
+    }
+
+    /* Get backend domid */
+    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
+                             &vtpmdev->bedomid)) {
+        return -1;
+    }
+
+    /* Alloc shared page */
+    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs, vtpmdev->bedomid, 1,
+                                         &ring_ref, PROT_READ|PROT_WRITE);
+    vtpmdev->ring_ref = ring_ref;
+    if (vtpmdev->shr == NULL) {
+        return -1;
+    }
+
+    /* Create event channel */
+    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
+        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+        return -1;
+    }
+
+    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
+                     vtpmdev->xendev.local_port);
+
+again:
+    xbt = xs_transaction_start(xenstore);
+    if (xbt == XBT_NULL) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
+                           vtpmdev->ring_ref)) {
+        goto abort_transaction;
+    }
+
+    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
+                           vtpmdev->xendev.local_port)) {
+        goto abort_transaction;
+    }
+
+    /* Publish protocol v2 feature */
+    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
+        goto abort_transaction;
+    }
+
+    if (!xs_transaction_end(xenstore, xbt, 0)) {
+        if (errno == EAGAIN) {
+            goto again;
+        }
+    }
+
+    return 0;
+
+abort_transaction:
+    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+    xs_transaction_end(xenstore, xbt, 1);
+    return -1;
+}
+
+static int vtpm_free(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    aio_poll(vtpm_aio_ctx, false);
+    qemu_bh_delete(vtpmdev->sr_bh);
+    if (vtpmdev->shr) {
+        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
+    }
+    xc_interface_close(vtpmdev->xen_xcs);
+    return 0;
+}
+
+static int vtpm_init(struct XenDevice *xendev)
+{
+    char path[XEN_BUFSIZE];
+    char *value;
+    unsigned int stubdom_vtpm = 0;
+
+    snprintf(path, sizeof(path), "/local/domain/%d/platform/acpi_stubdom_vtpm",
+             xen_domid);
+    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
+    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
+        free(value);
+        return -1;
+    }
+    free(value);
+    return 0;
+}
+
+static void vtpm_alloc(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    vtpm_aio_ctx = aio_context_new(NULL);
+    if (vtpm_aio_ctx == NULL) {
+        return;
+    }
+    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
+    qemu_bh_schedule(vtpmdev->sr_bh);
+    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0);
+}
+
+static void vtpm_event(struct XenDevice *xendev)
+{
+    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
+                                                xendev);
+
+    qemu_bh_schedule(vtpmdev->sr_bh);
+}
+
+struct XenDevOps xen_vtpmdev_ops = {
+    .size             = sizeof(struct xen_vtpm_dev),
+    .flags            = DEVOPS_FLAG_IGNORE_STATE |
+                        DEVOPS_FLAG_FE,
+    .event            = vtpm_event,
+    .free             = vtpm_free,
+    .init             = vtpm_init,
+    .alloc            = vtpm_alloc,
+    .initialise       = vtpm_initialise,
+    .backend_changed  = vtpm_backend_changed,
+};
diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
index 55af45a..1ca7342 100644
--- a/hw/xen/xen_frontend.c
+++ b/hw/xen/xen_frontend.c
@@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
 
 /* ------------------------------------------------------------- */
 
+void vtpm_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    int be_state;
+
+    if (strcmp(node, "state") == 0) {
+        xenstore_read_be_int(xendev, node, &be_state);
+        switch (be_state) {
+        case XenbusStateConnected:
+            /* TODO */
+            break;
+        case XenbusStateClosing:
+        case XenbusStateClosed:
+            xenbus_switch_state(xendev, XenbusStateClosing);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
 int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
 {
     xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index bb0b303..b959413 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps *ops);
 int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
 int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
 
+/* Xen vtpm */
+int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
+int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
+void vtpm_backend_changed(struct XenDevice *xendev, const char *node);
+
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
 extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 38f29fb..7268d0c 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
     return xc_interface_open(logger, dombuild_logger, open_flags);
 }
 
+static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
+                                            unsigned int open_flags)
+{
+    return xc_gntshr_open(logger, open_flags);
+}
+
 /* FIXME There is now way to have the xen fd */
 static inline int xc_fd(xc_interface *xen_xc)
 {
diff --git a/xen-hvm.c b/xen-hvm.c
index 315864c..b2403dc 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         return -1;
     }
+
+#ifdef CONFIG_TPM_XENSTUBDOMS
+    xen_fe_register("vtpm", &xen_vtpmdev_ops);
+#endif
+
     xen_be_register("console", &xen_console_ops);
     xen_be_register("vkbd", &xen_kbdmouse_ops);
     xen_be_register("qdisk", &xen_blkdev_ops);
-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
                   ` (4 preceding siblings ...)
  2015-05-04  7:22 ` [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c Quan Xu
@ 2015-05-04  7:22 ` Quan Xu
  2015-05-04 15:25   ` Stefan Berger
  2015-05-04 15:25   ` [Qemu-devel] " Stefan Berger
  2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen Quan Xu
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

and rename it to tpm_util_is_selftest().

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Remove the redundant copy right.
 -Reduce the includes to its minimum.
---
 hw/tpm/Makefile.objs             |  2 +-
 hw/tpm/tpm_passthrough.c         | 13 +------------
 hw/tpm/tpm_util.c                | 39 +++++++++++++++++++++++++++++++++++++++
 include/sysemu/tpm_backend_int.h |  1 +
 4 files changed, 42 insertions(+), 13 deletions(-)
 create mode 100644 hw/tpm/tpm_util.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 57919fa..e8fca65 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,3 +1,3 @@
-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
+common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
 common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 2a45071..ff08e15 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
     }
 }
 
-static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
-{
-    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
-
-    if (in_len >= sizeof(*hdr)) {
-        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
-    }
-
-    return false;
-}
-
 static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
                                         const uint8_t *in, uint32_t in_len,
                                         uint8_t *out, uint32_t out_len,
@@ -136,7 +125,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
     tpm_pt->tpm_executing = true;
     *selftest_done = false;
 
-    is_selftest = tpm_passthrough_is_selftest(in, in_len);
+    is_selftest = tpm_util_is_selftest(in, in_len);
 
     ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
     if (ret != in_len) {
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
new file mode 100644
index 0000000..73be8c5
--- /dev/null
+++ b/hw/tpm/tpm_util.c
@@ -0,0 +1,39 @@
+/*
+ *  TPM util functions
+ *
+ * *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ *  Copyright (c) 2010 - 2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "sysemu/tpm_backend_int.h"
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
+{
+    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
+
+    if (in_len >= sizeof(*hdr)) {
+        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
+    }
+
+    return false;
+}
diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
index 05d94d0..e18acab 100644
--- a/include/sysemu/tpm_backend_int.h
+++ b/include/sysemu/tpm_backend_int.h
@@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread *tbt,
 void tpm_backend_thread_end(TPMBackendThread *tbt);
 void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
                                   GFunc func, gpointer user_data);
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
 
 typedef enum TPMBackendCmd {
     TPM_BACKEND_CMD_INIT = 1,
-- 
1.8.3.2

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

* [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
                   ` (3 preceding siblings ...)
  2015-05-04  7:22   ` Quan Xu
@ 2015-05-04  7:22 ` Quan Xu
  2015-05-04  7:22 ` [Qemu-devel] " Quan Xu
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:22 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

and rename it to tpm_util_is_selftest().

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Remove the redundant copy right.
 -Reduce the includes to its minimum.
---
 hw/tpm/Makefile.objs             |  2 +-
 hw/tpm/tpm_passthrough.c         | 13 +------------
 hw/tpm/tpm_util.c                | 39 +++++++++++++++++++++++++++++++++++++++
 include/sysemu/tpm_backend_int.h |  1 +
 4 files changed, 42 insertions(+), 13 deletions(-)
 create mode 100644 hw/tpm/tpm_util.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 57919fa..e8fca65 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,3 +1,3 @@
-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
+common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
 common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 2a45071..ff08e15 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
     }
 }
 
-static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
-{
-    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
-
-    if (in_len >= sizeof(*hdr)) {
-        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
-    }
-
-    return false;
-}
-
 static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
                                         const uint8_t *in, uint32_t in_len,
                                         uint8_t *out, uint32_t out_len,
@@ -136,7 +125,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
     tpm_pt->tpm_executing = true;
     *selftest_done = false;
 
-    is_selftest = tpm_passthrough_is_selftest(in, in_len);
+    is_selftest = tpm_util_is_selftest(in, in_len);
 
     ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
     if (ret != in_len) {
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
new file mode 100644
index 0000000..73be8c5
--- /dev/null
+++ b/hw/tpm/tpm_util.c
@@ -0,0 +1,39 @@
+/*
+ *  TPM util functions
+ *
+ * *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ *  Copyright (c) 2010 - 2013 IBM Corporation
+ *  Authors:
+ *    Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "sysemu/tpm_backend_int.h"
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
+{
+    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
+
+    if (in_len >= sizeof(*hdr)) {
+        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
+    }
+
+    return false;
+}
diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
index 05d94d0..e18acab 100644
--- a/include/sysemu/tpm_backend_int.h
+++ b/include/sysemu/tpm_backend_int.h
@@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread *tbt,
 void tpm_backend_thread_end(TPMBackendThread *tbt);
 void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
                                   GFunc func, gpointer user_data);
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
 
 typedef enum TPMBackendCmd {
     TPM_BACKEND_CMD_INIT = 1,
-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
                   ` (5 preceding siblings ...)
  2015-05-04  7:22 ` [Qemu-devel] " Quan Xu
@ 2015-05-04  7:23 ` Quan Xu
  2015-05-04 15:30   ` Stefan Berger
  2015-05-04 15:30   ` Stefan Berger
  2015-05-04  7:23 ` Quan Xu
  2015-05-04  7:23   ` Quan Xu
  8 siblings, 2 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:23 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
stubdom vTPM domain that provides the actual TPM functionality. It
sends data and TPM commends with xen_vtpm_frontend. It is similar as
another two vTPM backens:
  *vTPM passthrough backen Since QEMU 1.5.
  *vTPM libtpms-based backen.

Some details:
This part of the patch provides support for the spawning of a thread
that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
It expects a signal from the frontend to wake and pick up the TPM
command that is supposed to be processed and delivers the response
packet using a callback function provided by the frontend.

The backend connects itself to the frontend by filling out an interface
structure with pointers to the function implementing support for various
operations.

(QEMU) vTPM XenStubdoms backen is initialized by Qemu command line options,
      "-tpmdev xenstubdoms,id=xenvtpm0 -device tpm-tis,tpmdev=xenvtpm0"

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Add a parameter indicating whether the command that was a selftest,
  and whether it completed successfully.
---
 hw/tpm/Makefile.objs     |   2 +-
 hw/tpm/tpm_xenstubdoms.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 hw/tpm/tpm_xenstubdoms.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index e8fca65..698b9e6 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,3 +1,3 @@
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
-common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
+common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o tpm_xenstubdoms.o
diff --git a/hw/tpm/tpm_xenstubdoms.c b/hw/tpm/tpm_xenstubdoms.c
new file mode 100644
index 0000000..f461323
--- /dev/null
+++ b/hw/tpm/tpm_xenstubdoms.c
@@ -0,0 +1,277 @@
+/*
+ * Xen Stubdom vTPM driver
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <dirent.h>
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/sockets.h"
+#include "qemu/log.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/xen/xen_backend.h"
+#include "sysemu/tpm_backend_int.h"
+#include "tpm_tis.h"
+
+#ifdef DEBUG_TPM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define TYPE_TPM_XENSTUBDOMS "tpm-xenstubdoms"
+#define TPM_XENSTUBDOMS(obj) \
+    OBJECT_CHECK(TPMXenstubdomsState, (obj), TYPE_TPM_XENSTUBDOMS)
+
+static const TPMDriverOps tpm_xenstubdoms_driver;
+
+/* Data structures */
+typedef struct TPMXenstubdomsThreadParams {
+    TPMState *tpm_state;
+    TPMRecvDataCB *recv_data_callback;
+    TPMBackend *tb;
+} TPMXenstubdomsThreadParams;
+
+struct TPMXenstubdomsState {
+    TPMBackend parent;
+    TPMBackendThread tbt;
+    TPMXenstubdomsThreadParams tpm_thread_params;
+    bool had_startup_error;
+};
+
+typedef struct TPMXenstubdomsState TPMXenstubdomsState;
+
+/* Functions */
+static void tpm_xenstubdoms_cancel_cmd(TPMBackend *tb);
+
+static int tpm_xenstubdoms_unix_transfer(const TPMLocality *locty_data,
+                                         bool *selftest_done)
+{
+    size_t rlen;
+    struct XenDevice *xendev;
+    int ret;
+    bool is_selftest;
+    const struct tpm_resp_hdr *hdr;
+
+    is_selftest = tpm_util_is_selftest(locty_data->w_buffer.buffer,
+                                       locty_data->w_buffer.size);
+
+    xendev = xen_find_xendev("vtpm", xen_domid, xenstore_dev);
+    if (xendev == NULL) {
+        xen_be_printf(xendev, 0, "Can not find vtpm device.\n");
+        return -1;
+    }
+
+    ret = vtpm_send(xendev, locty_data->w_buffer.buffer,
+                    locty_data->w_offset);
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "Can not send vtpm command.\n");
+        goto err_exit;
+    }
+
+    ret = vtpm_recv(xendev, locty_data->r_buffer.buffer, &rlen);
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "vtpm reception command error.\n");
+        goto err_exit;
+    }
+
+    if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+        hdr = (struct tpm_resp_hdr *)locty_data->r_buffer.buffer;
+        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
+    }
+
+err_exit:
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "vtpm command error.\n");
+    }
+    return ret;
+}
+
+static void tpm_xenstubdoms_worker_thread(gpointer data,
+                                          gpointer user_data)
+{
+    TPMXenstubdomsThreadParams *thr_parms = user_data;
+    TPMBackendCmd cmd = (TPMBackendCmd)data;
+    bool selftest_done = false;
+
+    switch (cmd) {
+    case TPM_BACKEND_CMD_PROCESS_CMD:
+        tpm_xenstubdoms_unix_transfer(thr_parms->tpm_state->locty_data,
+                                      &selftest_done);
+        thr_parms->recv_data_callback(thr_parms->tpm_state,
+                                      thr_parms->tpm_state->locty_number,
+                                      selftest_done);
+        break;
+    case TPM_BACKEND_CMD_INIT:
+    case TPM_BACKEND_CMD_END:
+    case TPM_BACKEND_CMD_TPM_RESET:
+
+        /* nothing to do */
+        break;
+    }
+}
+
+/*
+ *Start the TPM (thread). If it had been started before, then terminate and
+ *start it again.
+ */
+static int tpm_xenstubdoms_startup_tpm(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_tpm_reset(&tpm_xs->tbt, tpm_xenstubdoms_worker_thread,
+                                 &tpm_xs->tpm_thread_params);
+
+    return 0;
+}
+
+static void tpm_xenstubdoms_reset(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_end(&tpm_xs->tbt);
+    tpm_xs->had_startup_error = false;
+}
+
+static int tpm_xenstubdoms_init(TPMBackend *tb, TPMState *s,
+                                TPMRecvDataCB *recv_data_cb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_xs->tpm_thread_params.tpm_state = s;
+    tpm_xs->tpm_thread_params.recv_data_callback = recv_data_cb;
+    tpm_xs->tpm_thread_params.tb = tb;
+    return 0;
+}
+
+static bool tpm_xenstubdoms_get_tpm_established_flag(TPMBackend *tb)
+{
+    return false;
+}
+
+static bool tpm_xenstubdoms_get_startup_error(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    return tpm_xs->had_startup_error;
+}
+
+static size_t tpm_xenstubdoms_realloc_buffer(TPMSizedBuffer *sb)
+{
+    size_t wanted_size = 4096; /* Linux tpm.c buffer size */
+
+    if (sb->size != wanted_size) {
+        sb->buffer = g_realloc(sb->buffer, wanted_size);
+        sb->size = wanted_size;
+    }
+    return sb->size;
+}
+
+static void tpm_xenstubdoms_deliver_request(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_deliver_request(&tpm_xs->tbt);
+}
+
+static void tpm_xenstubdoms_cancel_cmd(TPMBackend *tb)
+{
+}
+
+static const char *tpm_xenstubdoms_create_desc(void)
+{
+    return "Xenstubdoms TPM backend driver";
+}
+
+static TPMBackend *tpm_xenstubdoms_create(QemuOpts *opts, const char *id)
+{
+    Object *obj = object_new(TYPE_TPM_XENSTUBDOMS);
+    TPMBackend *tb = TPM_BACKEND(obj);
+
+    tb->id = g_strdup(id);
+    tb->fe_model = -1;
+    tb->ops = &tpm_xenstubdoms_driver;
+    return tb;
+}
+
+static void tpm_xenstubdoms_destroy(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xh = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_end(&tpm_xh->tbt);
+    g_free(tb->id);
+}
+
+static const QemuOptDesc tpm_xenstubdoms_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {},
+};
+
+static const TPMDriverOps tpm_xenstubdoms_driver = {
+    .type                     = TPM_TYPE_XENSTUBDOMS,
+    .opts                     = tpm_xenstubdoms_cmdline_opts,
+    .desc                     = tpm_xenstubdoms_create_desc,
+    .create                   = tpm_xenstubdoms_create,
+    .destroy                  = tpm_xenstubdoms_destroy,
+    .init                     = tpm_xenstubdoms_init,
+    .startup_tpm              = tpm_xenstubdoms_startup_tpm,
+    .realloc_buffer           = tpm_xenstubdoms_realloc_buffer,
+    .reset                    = tpm_xenstubdoms_reset,
+    .had_startup_error        = tpm_xenstubdoms_get_startup_error,
+    .deliver_request          = tpm_xenstubdoms_deliver_request,
+    .cancel_cmd               = tpm_xenstubdoms_cancel_cmd,
+    .get_tpm_established_flag = tpm_xenstubdoms_get_tpm_established_flag,
+};
+
+static void tpm_xenstubdoms_inst_init(Object *obj)
+{
+}
+
+static void tpm_xenstubdoms_inst_finalize(Object *obj)
+{
+}
+
+static void tpm_xenstubdoms_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->ops = &tpm_xenstubdoms_driver;
+}
+
+static const TypeInfo tpm_xenstubdoms_info = {
+    .name = TYPE_TPM_XENSTUBDOMS,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMXenstubdomsState),
+    .class_init = tpm_xenstubdoms_class_init,
+    .instance_init = tpm_xenstubdoms_inst_init,
+    .instance_finalize = tpm_xenstubdoms_inst_finalize,
+};
+
+static void tpm_xenstubdoms_register(void)
+{
+    type_register_static(&tpm_xenstubdoms_info);
+    tpm_register_driver(&tpm_xenstubdoms_driver);
+}
+
+type_init(tpm_xenstubdoms_register)
-- 
1.8.3.2

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

* [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
                   ` (6 preceding siblings ...)
  2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen Quan Xu
@ 2015-05-04  7:23 ` Quan Xu
  2015-05-04  7:23   ` Quan Xu
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:23 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
stubdom vTPM domain that provides the actual TPM functionality. It
sends data and TPM commends with xen_vtpm_frontend. It is similar as
another two vTPM backens:
  *vTPM passthrough backen Since QEMU 1.5.
  *vTPM libtpms-based backen.

Some details:
This part of the patch provides support for the spawning of a thread
that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
It expects a signal from the frontend to wake and pick up the TPM
command that is supposed to be processed and delivers the response
packet using a callback function provided by the frontend.

The backend connects itself to the frontend by filling out an interface
structure with pointers to the function implementing support for various
operations.

(QEMU) vTPM XenStubdoms backen is initialized by Qemu command line options,
      "-tpmdev xenstubdoms,id=xenvtpm0 -device tpm-tis,tpmdev=xenvtpm0"

Signed-off-by: Quan Xu <quan.xu@intel.com>

--Changes in v6:
 -Add a parameter indicating whether the command that was a selftest,
  and whether it completed successfully.
---
 hw/tpm/Makefile.objs     |   2 +-
 hw/tpm/tpm_xenstubdoms.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 hw/tpm/tpm_xenstubdoms.c

diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index e8fca65..698b9e6 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,3 +1,3 @@
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
-common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
+common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o tpm_xenstubdoms.o
diff --git a/hw/tpm/tpm_xenstubdoms.c b/hw/tpm/tpm_xenstubdoms.c
new file mode 100644
index 0000000..f461323
--- /dev/null
+++ b/hw/tpm/tpm_xenstubdoms.c
@@ -0,0 +1,277 @@
+/*
+ * Xen Stubdom vTPM driver
+ *
+ *  Copyright (c) 2015 Intel Corporation
+ *  Authors:
+ *    Quan Xu <quan.xu@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include <dirent.h>
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qemu/sockets.h"
+#include "qemu/log.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/xen/xen_backend.h"
+#include "sysemu/tpm_backend_int.h"
+#include "tpm_tis.h"
+
+#ifdef DEBUG_TPM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define TYPE_TPM_XENSTUBDOMS "tpm-xenstubdoms"
+#define TPM_XENSTUBDOMS(obj) \
+    OBJECT_CHECK(TPMXenstubdomsState, (obj), TYPE_TPM_XENSTUBDOMS)
+
+static const TPMDriverOps tpm_xenstubdoms_driver;
+
+/* Data structures */
+typedef struct TPMXenstubdomsThreadParams {
+    TPMState *tpm_state;
+    TPMRecvDataCB *recv_data_callback;
+    TPMBackend *tb;
+} TPMXenstubdomsThreadParams;
+
+struct TPMXenstubdomsState {
+    TPMBackend parent;
+    TPMBackendThread tbt;
+    TPMXenstubdomsThreadParams tpm_thread_params;
+    bool had_startup_error;
+};
+
+typedef struct TPMXenstubdomsState TPMXenstubdomsState;
+
+/* Functions */
+static void tpm_xenstubdoms_cancel_cmd(TPMBackend *tb);
+
+static int tpm_xenstubdoms_unix_transfer(const TPMLocality *locty_data,
+                                         bool *selftest_done)
+{
+    size_t rlen;
+    struct XenDevice *xendev;
+    int ret;
+    bool is_selftest;
+    const struct tpm_resp_hdr *hdr;
+
+    is_selftest = tpm_util_is_selftest(locty_data->w_buffer.buffer,
+                                       locty_data->w_buffer.size);
+
+    xendev = xen_find_xendev("vtpm", xen_domid, xenstore_dev);
+    if (xendev == NULL) {
+        xen_be_printf(xendev, 0, "Can not find vtpm device.\n");
+        return -1;
+    }
+
+    ret = vtpm_send(xendev, locty_data->w_buffer.buffer,
+                    locty_data->w_offset);
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "Can not send vtpm command.\n");
+        goto err_exit;
+    }
+
+    ret = vtpm_recv(xendev, locty_data->r_buffer.buffer, &rlen);
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "vtpm reception command error.\n");
+        goto err_exit;
+    }
+
+    if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+        hdr = (struct tpm_resp_hdr *)locty_data->r_buffer.buffer;
+        *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
+    }
+
+err_exit:
+    if (ret < 0) {
+        xen_be_printf(xendev, 0, "vtpm command error.\n");
+    }
+    return ret;
+}
+
+static void tpm_xenstubdoms_worker_thread(gpointer data,
+                                          gpointer user_data)
+{
+    TPMXenstubdomsThreadParams *thr_parms = user_data;
+    TPMBackendCmd cmd = (TPMBackendCmd)data;
+    bool selftest_done = false;
+
+    switch (cmd) {
+    case TPM_BACKEND_CMD_PROCESS_CMD:
+        tpm_xenstubdoms_unix_transfer(thr_parms->tpm_state->locty_data,
+                                      &selftest_done);
+        thr_parms->recv_data_callback(thr_parms->tpm_state,
+                                      thr_parms->tpm_state->locty_number,
+                                      selftest_done);
+        break;
+    case TPM_BACKEND_CMD_INIT:
+    case TPM_BACKEND_CMD_END:
+    case TPM_BACKEND_CMD_TPM_RESET:
+
+        /* nothing to do */
+        break;
+    }
+}
+
+/*
+ *Start the TPM (thread). If it had been started before, then terminate and
+ *start it again.
+ */
+static int tpm_xenstubdoms_startup_tpm(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_tpm_reset(&tpm_xs->tbt, tpm_xenstubdoms_worker_thread,
+                                 &tpm_xs->tpm_thread_params);
+
+    return 0;
+}
+
+static void tpm_xenstubdoms_reset(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_end(&tpm_xs->tbt);
+    tpm_xs->had_startup_error = false;
+}
+
+static int tpm_xenstubdoms_init(TPMBackend *tb, TPMState *s,
+                                TPMRecvDataCB *recv_data_cb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_xs->tpm_thread_params.tpm_state = s;
+    tpm_xs->tpm_thread_params.recv_data_callback = recv_data_cb;
+    tpm_xs->tpm_thread_params.tb = tb;
+    return 0;
+}
+
+static bool tpm_xenstubdoms_get_tpm_established_flag(TPMBackend *tb)
+{
+    return false;
+}
+
+static bool tpm_xenstubdoms_get_startup_error(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    return tpm_xs->had_startup_error;
+}
+
+static size_t tpm_xenstubdoms_realloc_buffer(TPMSizedBuffer *sb)
+{
+    size_t wanted_size = 4096; /* Linux tpm.c buffer size */
+
+    if (sb->size != wanted_size) {
+        sb->buffer = g_realloc(sb->buffer, wanted_size);
+        sb->size = wanted_size;
+    }
+    return sb->size;
+}
+
+static void tpm_xenstubdoms_deliver_request(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xs = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_deliver_request(&tpm_xs->tbt);
+}
+
+static void tpm_xenstubdoms_cancel_cmd(TPMBackend *tb)
+{
+}
+
+static const char *tpm_xenstubdoms_create_desc(void)
+{
+    return "Xenstubdoms TPM backend driver";
+}
+
+static TPMBackend *tpm_xenstubdoms_create(QemuOpts *opts, const char *id)
+{
+    Object *obj = object_new(TYPE_TPM_XENSTUBDOMS);
+    TPMBackend *tb = TPM_BACKEND(obj);
+
+    tb->id = g_strdup(id);
+    tb->fe_model = -1;
+    tb->ops = &tpm_xenstubdoms_driver;
+    return tb;
+}
+
+static void tpm_xenstubdoms_destroy(TPMBackend *tb)
+{
+    TPMXenstubdomsState *tpm_xh = TPM_XENSTUBDOMS(tb);
+
+    tpm_backend_thread_end(&tpm_xh->tbt);
+    g_free(tb->id);
+}
+
+static const QemuOptDesc tpm_xenstubdoms_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {},
+};
+
+static const TPMDriverOps tpm_xenstubdoms_driver = {
+    .type                     = TPM_TYPE_XENSTUBDOMS,
+    .opts                     = tpm_xenstubdoms_cmdline_opts,
+    .desc                     = tpm_xenstubdoms_create_desc,
+    .create                   = tpm_xenstubdoms_create,
+    .destroy                  = tpm_xenstubdoms_destroy,
+    .init                     = tpm_xenstubdoms_init,
+    .startup_tpm              = tpm_xenstubdoms_startup_tpm,
+    .realloc_buffer           = tpm_xenstubdoms_realloc_buffer,
+    .reset                    = tpm_xenstubdoms_reset,
+    .had_startup_error        = tpm_xenstubdoms_get_startup_error,
+    .deliver_request          = tpm_xenstubdoms_deliver_request,
+    .cancel_cmd               = tpm_xenstubdoms_cancel_cmd,
+    .get_tpm_established_flag = tpm_xenstubdoms_get_tpm_established_flag,
+};
+
+static void tpm_xenstubdoms_inst_init(Object *obj)
+{
+}
+
+static void tpm_xenstubdoms_inst_finalize(Object *obj)
+{
+}
+
+static void tpm_xenstubdoms_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+
+    tbc->ops = &tpm_xenstubdoms_driver;
+}
+
+static const TypeInfo tpm_xenstubdoms_info = {
+    .name = TYPE_TPM_XENSTUBDOMS,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMXenstubdomsState),
+    .class_init = tpm_xenstubdoms_class_init,
+    .instance_init = tpm_xenstubdoms_inst_init,
+    .instance_finalize = tpm_xenstubdoms_inst_finalize,
+};
+
+static void tpm_xenstubdoms_register(void)
+{
+    type_register_static(&tpm_xenstubdoms_info);
+    tpm_register_driver(&tpm_xenstubdoms_driver);
+}
+
+type_init(tpm_xenstubdoms_register)
-- 
1.8.3.2

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

* [Qemu-devel] [PATCH v6 6/6] Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init()
  2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
@ 2015-05-04  7:23   ` Quan Xu
  2015-05-04  7:22 ` Quan Xu
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:23 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

make sure QEMU machine class is initialized and QEMU has registered
Xen stubdom vTPM driver when call tpm_init()

Signed-off-by: Quan Xu <quan.xu@intel.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 vl.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/vl.c b/vl.c
index 74c2681..7bc87f1 100644
--- a/vl.c
+++ b/vl.c
@@ -4131,12 +4131,6 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
-#ifdef CONFIG_TPM
-    if (tpm_init() < 0) {
-        exit(1);
-    }
-#endif
-
     /* init the bluetooth world */
     if (foreach_device_config(DEV_BT, bt_parse))
         exit(1);
@@ -4239,6 +4233,17 @@ int main(int argc, char **argv, char **envp)
             exit(1);
     }
 
+    /*
+     * For compatible with Xen stubdom vTPM driver, make
+     * sure QEMU machine class is initialized and QEMU has
+     * registered Xen stubdom vTPM driver.
+     */
+#ifdef CONFIG_TPM
+    if (tpm_init() < 0) {
+        exit(1);
+    }
+#endif
+
     /* init generic devices */
     if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
         exit(1);
-- 
1.8.3.2

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

* [PATCH v6 6/6] Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init()
@ 2015-05-04  7:23   ` Quan Xu
  0 siblings, 0 replies; 48+ messages in thread
From: Quan Xu @ 2015-05-04  7:23 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, Quan Xu, xen-devel

make sure QEMU machine class is initialized and QEMU has registered
Xen stubdom vTPM driver when call tpm_init()

Signed-off-by: Quan Xu <quan.xu@intel.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 vl.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/vl.c b/vl.c
index 74c2681..7bc87f1 100644
--- a/vl.c
+++ b/vl.c
@@ -4131,12 +4131,6 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
-#ifdef CONFIG_TPM
-    if (tpm_init() < 0) {
-        exit(1);
-    }
-#endif
-
     /* init the bluetooth world */
     if (foreach_device_config(DEV_BT, bt_parse))
         exit(1);
@@ -4239,6 +4233,17 @@ int main(int argc, char **argv, char **envp)
             exit(1);
     }
 
+    /*
+     * For compatible with Xen stubdom vTPM driver, make
+     * sure QEMU machine class is initialized and QEMU has
+     * registered Xen stubdom vTPM driver.
+     */
+#ifdef CONFIG_TPM
+    if (tpm_init() < 0) {
+        exit(1);
+    }
+#endif
+
     /* init generic devices */
     if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
         exit(1);
-- 
1.8.3.2

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
  (?)
@ 2015-05-04 12:57   ` Xu, Quan
  -1 siblings, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-04 12:57 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

I find out the subject is wrong in v5/v6. Just update the subject as below. 

Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Register Xen stubdom vTPM frontend
 driver

This drvier transfers any request/repond between TPM xenstubdoms
driver and Xen vTPM stubdom, and facilitates communications between
Xen vTPM stubdom domain and vTPM xenstubdoms driver. It is a glue for
the TPM xenstubdoms driver and Xen stubdom vTPM domain that provides
the actual TPM functionality.

(Xen) Xen backend driver should run before running this frontend, and
initialize XenStore as the following for communication.

[XenStore]

for example:

Domain 0: runs QEMU for guest A
Domain 1: vtpmmgr
Domain 2: vTPM for guest A
Domain 3: HVM guest A

[...]
 local = ""
   domain = ""
    0 = ""
     frontend = ""
      vtpm = ""
       2 = ""
        0 = ""
         backend = "/local/domain/2/backend/vtpm/0/0"
         backend-id = "2"
         state = "*"
         handle = "0"
         domain = "Domain3's name"
         ring-ref = "*"
         event-channel = "*"
         feature-protocol-v2 = "1"
     backend = ""
      qdisk = ""
       [...]
      console = ""
      vif = ""
       [...]
    2 = ""
     [...]
     backend = ""
      vtpm = ""
       0 = ""
        0 = ""
         frontend = "/local/domain/0/frontend/vtpm/2/0"
         frontend-id = "0" ('0', frontend is running in Domain-0)
         [...]
    3 = ""
     [...]
     device = "" (frontend device, the backend is running in QEMU/.etc)
      vkbd = ""
       [...]
      vif = ""
       [...]

 ..

(QEMU) xen_vtpmdev_ops is initialized with the following process:
  xen_hvm_init()
    [...]
    -->xen_fe_register("vtpm", ...)
      -->xenstore_fe_scan()
        -->xen_fe_try_init(ops)
          --> XenDevOps.init()
        -->xen_fe_get_xendev()
          --> XenDevOps.alloc()
        -->xen_fe_check()
          -->xen_fe_try_initialise()
            --> XenDevOps.initialise()
          -->xen_fe_try_connected()
            --> XenDevOps.connected()
        -->xs_watch()
    [...]

-Quan

> -----Original Message-----
> From: Xu, Quan
> Sent: Monday, May 04, 2015 3:23 PM
> To: stefano.stabellini@eu.citrix.com; stefanb@linux.vnet.ibm.com;
> eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org; Xu, Quan
> Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> This patch adds infrastructure for xen front drivers living in qemu, so drivers don't
> need to implement common stuff on their own.  It's mostly xenbus
> management stuff: some functions to access XenStore, setting up XenStore
> watches, callbacks on device discovery and state changes, and handle event
> channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
>          [...]
>     3 = ""
>      [...]
>      device = "" (frontend device, the backend is running in QEMU/.etc)
>       vkbd = ""
>        [...]
>       vif = ""
>        [...]
> 
>  ..
> 
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>   xen_hvm_init()
>     [...]
>     -->xen_fe_register("vtpm", ...)
>       -->xenstore_fe_scan()
>         -->xen_fe_try_init(ops)
>           --> XenDevOps.init()
>         -->xen_fe_get_xendev()
>           --> XenDevOps.alloc()
>         -->xen_fe_check()
>           -->xen_fe_try_initialise()
>             --> XenDevOps.initialise()
>           -->xen_fe_try_connected()
>             --> XenDevOps.connected()
>         -->xs_watch()
>     [...]
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Replace buf_size with PAGE_SIZE and use length rather than
>   shr->length.
> ---
>  hw/tpm/Makefile.objs         |   1 +
>  hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
>  hw/xen/xen_frontend.c        |  20 +++
>  include/hw/xen/xen_backend.h |   5 +
>  include/hw/xen/xen_common.h  |   6 +
>  xen-hvm.c                    |   5 +
>  6 files changed, 352 insertions(+)
>  create mode 100644 hw/tpm/xen_vtpm_frontend.c
> 
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644 index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see
> +<http://www.gnu.org/licenses/>  */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif
> +
> +enum tpmif_state {
> +    /* No contents, vTPM idle, cancel complete */
> +    TPMIF_STATE_IDLE,
> +    /* Request ready or vTPM working */
> +    TPMIF_STATE_SUBMIT,
> +    /* Response ready or vTPM idle */
> +    TPMIF_STATE_FINISH,
> +    /* Cancel requested or vTPM working */
> +    TPMIF_STATE_CANCEL,
> +};
> +
> +static AioContext *vtpm_aio_ctx;
> +
> +enum status_bits {
> +    VTPM_STATUS_RUNNING  = 0x1,
> +    VTPM_STATUS_IDLE     = 0x2,
> +    VTPM_STATUS_RESULT   = 0x4,
> +    VTPM_STATUS_CANCELED = 0x8,
> +};
> +
> +struct tpmif_shared_page {
> +    /* Request and response length in bytes */
> +    uint32_t length;
> +    /* Enum tpmif_state */
> +    uint8_t  state;
> +    /* For the current request */
> +    uint8_t  locality;
> +    /* Should be zero */
> +    uint8_t  pad;
> +    /* Extra pages for long packets; may be zero */
> +    uint8_t  nr_extra_pages;
> +    /*
> +     * Grant IDs, the length is actually nr_extra_pages.
> +     * beyond the extra_pages entries is the actual request
> +     * and response.
> +     */
> +    uint32_t extra_pages[0];
> +};
> +
> +struct xen_vtpm_dev {
> +    struct XenDevice xendev;  /* must be first */
> +    struct           tpmif_shared_page *shr;
> +    xc_gntshr        *xen_xcs;
> +    int              ring_ref;
> +    int              bedomid;
> +    QEMUBH           *sr_bh;
> +};
> +
> +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev) {
> +    switch (vtpmdev->shr->state) {
> +    case TPMIF_STATE_IDLE:
> +    case TPMIF_STATE_FINISH:
> +        return VTPM_STATUS_IDLE;
> +    case TPMIF_STATE_SUBMIT:
> +    case TPMIF_STATE_CANCEL:
> +        return VTPM_STATUS_RUNNING;
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static bool vtpm_aio_wait(AioContext *ctx) {
> +    return aio_poll(ctx, true);
> +}
> +
> +static void sr_bh_handler(void *opaque) { }
> +
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset;
> +    size_t length = shr->length;
> +
> +    if (shr->state == TPMIF_STATE_IDLE) {
> +        return -ECANCELED;
> +    }
> +
> +    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + length > PAGE_SIZE) {
> +        length = PAGE_SIZE - offset;
> +    }
> +
> +    memcpy(buf, offset + (uint8_t *)shr, length);
> +    *count = length;
> +
> +    return 0;
> +}
> +
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset = sizeof(*shr) +
> +
> +sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + count > PAGE_SIZE) {
> +        return -ECANCELED;
> +    }
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    memcpy(offset + (uint8_t *)shr, buf, count);
> +    shr->length = count;
> +    barrier();
> +    shr->state = TPMIF_STATE_SUBMIT;
> +    xen_wmb();
> +    xen_be_send_notify(&vtpmdev->xendev);
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    return count;
> +}
> +
> +static int vtpm_initialise(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    xs_transaction_t xbt = XBT_NULL;
> +    unsigned int ring_ref;
> +
> +    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev,
> "frontend");
> +    if (vtpmdev->xendev.fe == NULL) {
> +        return -1;
> +    }
> +
> +    /* Get backend domid */
> +    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
> +                             &vtpmdev->bedomid)) {
> +        return -1;
> +    }
> +
> +    /* Alloc shared page */
> +    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs,
> vtpmdev->bedomid, 1,
> +                                         &ring_ref,
> PROT_READ|PROT_WRITE);
> +    vtpmdev->ring_ref = ring_ref;
> +    if (vtpmdev->shr == NULL) {
> +        return -1;
> +    }
> +
> +    /* Create event channel */
> +    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +        return -1;
> +    }
> +
> +    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
> +                     vtpmdev->xendev.local_port);
> +
> +again:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
> +                           vtpmdev->ring_ref)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
> +                           vtpmdev->xendev.local_port)) {
> +        goto abort_transaction;
> +    }
> +
> +    /* Publish protocol v2 feature */
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto again;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}
> +
> +static int vtpm_free(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    aio_poll(vtpm_aio_ctx, false);
> +    qemu_bh_delete(vtpmdev->sr_bh);
> +    if (vtpmdev->shr) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    }
> +    xc_interface_close(vtpmdev->xen_xcs);
> +    return 0;
> +}
> +
> +static int vtpm_init(struct XenDevice *xendev) {
> +    char path[XEN_BUFSIZE];
> +    char *value;
> +    unsigned int stubdom_vtpm = 0;
> +
> +    snprintf(path, sizeof(path),
> "/local/domain/%d/platform/acpi_stubdom_vtpm",
> +             xen_domid);
> +    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
> +    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
> +        free(value);
> +        return -1;
> +    }
> +    free(value);
> +    return 0;
> +}
> +
> +static void vtpm_alloc(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    vtpm_aio_ctx = aio_context_new(NULL);
> +    if (vtpm_aio_ctx == NULL) {
> +        return;
> +    }
> +    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0); }
> +
> +static void vtpm_event(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +}
> +
> +struct XenDevOps xen_vtpmdev_ops = {
> +    .size             = sizeof(struct xen_vtpm_dev),
> +    .flags            = DEVOPS_FLAG_IGNORE_STATE |
> +                        DEVOPS_FLAG_FE,
> +    .event            = vtpm_event,
> +    .free             = vtpm_free,
> +    .init             = vtpm_init,
> +    .alloc            = vtpm_alloc,
> +    .initialise       = vtpm_initialise,
> +    .backend_changed  = vtpm_backend_changed, };
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c index
> 55af45a..1ca7342 100644
> --- a/hw/xen/xen_frontend.c
> +++ b/hw/xen/xen_frontend.c
> @@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
> 
>  /* ------------------------------------------------------------- */
> 
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node) {
> +    int be_state;
> +
> +    if (strcmp(node, "state") == 0) {
> +        xenstore_read_be_int(xendev, node, &be_state);
> +        switch (be_state) {
> +        case XenbusStateConnected:
> +            /* TODO */
> +            break;
> +        case XenbusStateClosing:
> +        case XenbusStateClosed:
> +            xenbus_switch_state(xendev, XenbusStateClosing);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +}
> +
>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
> {
>      xendev->local_port =
> xc_evtchn_bind_unbound_port(xendev->evtchndev,
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index bb0b303..b959413 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps
> *ops);  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> remote_dom);  int xenbus_switch_state(struct XenDevice *xendev, enum
> xenbus_state xbus);
> 
> +/* Xen vtpm */
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node);
> +
>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
>  extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
> diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
> index 38f29fb..7268d0c 100644
> --- a/include/hw/xen/xen_common.h
> +++ b/include/hw/xen/xen_common.h
> @@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger,
> void *dombuild_logger,
>      return xc_interface_open(logger, dombuild_logger, open_flags);  }
> 
> +static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
> +                                            unsigned int open_flags) {
> +    return xc_gntshr_open(logger, open_flags); }
> +
>  /* FIXME There is now way to have the xen fd */  static inline int
> xc_fd(xc_interface *xen_xc)  { diff --git a/xen-hvm.c b/xen-hvm.c index
> 315864c..b2403dc 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size,
> ram_addr_t *above_4g_mem_size,
>          fprintf(stderr, "%s: xen backend core setup failed\n",
> __FUNCTION__);
>          return -1;
>      }
> +
> +#ifdef CONFIG_TPM_XENSTUBDOMS
> +    xen_fe_register("vtpm", &xen_vtpmdev_ops); #endif
> +
>      xen_be_register("console", &xen_console_ops);
>      xen_be_register("vkbd", &xen_kbdmouse_ops);
>      xen_be_register("qdisk", &xen_blkdev_ops);
> --
> 1.8.3.2

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
  (?)
  (?)
@ 2015-05-04 12:57   ` Xu, Quan
  -1 siblings, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-04 12:57 UTC (permalink / raw)
  To: stefano.stabellini, stefanb, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

I find out the subject is wrong in v5/v6. Just update the subject as below. 

Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Register Xen stubdom vTPM frontend
 driver

This drvier transfers any request/repond between TPM xenstubdoms
driver and Xen vTPM stubdom, and facilitates communications between
Xen vTPM stubdom domain and vTPM xenstubdoms driver. It is a glue for
the TPM xenstubdoms driver and Xen stubdom vTPM domain that provides
the actual TPM functionality.

(Xen) Xen backend driver should run before running this frontend, and
initialize XenStore as the following for communication.

[XenStore]

for example:

Domain 0: runs QEMU for guest A
Domain 1: vtpmmgr
Domain 2: vTPM for guest A
Domain 3: HVM guest A

[...]
 local = ""
   domain = ""
    0 = ""
     frontend = ""
      vtpm = ""
       2 = ""
        0 = ""
         backend = "/local/domain/2/backend/vtpm/0/0"
         backend-id = "2"
         state = "*"
         handle = "0"
         domain = "Domain3's name"
         ring-ref = "*"
         event-channel = "*"
         feature-protocol-v2 = "1"
     backend = ""
      qdisk = ""
       [...]
      console = ""
      vif = ""
       [...]
    2 = ""
     [...]
     backend = ""
      vtpm = ""
       0 = ""
        0 = ""
         frontend = "/local/domain/0/frontend/vtpm/2/0"
         frontend-id = "0" ('0', frontend is running in Domain-0)
         [...]
    3 = ""
     [...]
     device = "" (frontend device, the backend is running in QEMU/.etc)
      vkbd = ""
       [...]
      vif = ""
       [...]

 ..

(QEMU) xen_vtpmdev_ops is initialized with the following process:
  xen_hvm_init()
    [...]
    -->xen_fe_register("vtpm", ...)
      -->xenstore_fe_scan()
        -->xen_fe_try_init(ops)
          --> XenDevOps.init()
        -->xen_fe_get_xendev()
          --> XenDevOps.alloc()
        -->xen_fe_check()
          -->xen_fe_try_initialise()
            --> XenDevOps.initialise()
          -->xen_fe_try_connected()
            --> XenDevOps.connected()
        -->xs_watch()
    [...]

-Quan

> -----Original Message-----
> From: Xu, Quan
> Sent: Monday, May 04, 2015 3:23 PM
> To: stefano.stabellini@eu.citrix.com; stefanb@linux.vnet.ibm.com;
> eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org; Xu, Quan
> Subject: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> This patch adds infrastructure for xen front drivers living in qemu, so drivers don't
> need to implement common stuff on their own.  It's mostly xenbus
> management stuff: some functions to access XenStore, setting up XenStore
> watches, callbacks on device discovery and state changes, and handle event
> channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
>          [...]
>     3 = ""
>      [...]
>      device = "" (frontend device, the backend is running in QEMU/.etc)
>       vkbd = ""
>        [...]
>       vif = ""
>        [...]
> 
>  ..
> 
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>   xen_hvm_init()
>     [...]
>     -->xen_fe_register("vtpm", ...)
>       -->xenstore_fe_scan()
>         -->xen_fe_try_init(ops)
>           --> XenDevOps.init()
>         -->xen_fe_get_xendev()
>           --> XenDevOps.alloc()
>         -->xen_fe_check()
>           -->xen_fe_try_initialise()
>             --> XenDevOps.initialise()
>           -->xen_fe_try_connected()
>             --> XenDevOps.connected()
>         -->xs_watch()
>     [...]
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Replace buf_size with PAGE_SIZE and use length rather than
>   shr->length.
> ---
>  hw/tpm/Makefile.objs         |   1 +
>  hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
>  hw/xen/xen_frontend.c        |  20 +++
>  include/hw/xen/xen_backend.h |   5 +
>  include/hw/xen/xen_common.h  |   6 +
>  xen-hvm.c                    |   5 +
>  6 files changed, 352 insertions(+)
>  create mode 100644 hw/tpm/xen_vtpm_frontend.c
> 
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644 index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see
> +<http://www.gnu.org/licenses/>  */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif
> +
> +enum tpmif_state {
> +    /* No contents, vTPM idle, cancel complete */
> +    TPMIF_STATE_IDLE,
> +    /* Request ready or vTPM working */
> +    TPMIF_STATE_SUBMIT,
> +    /* Response ready or vTPM idle */
> +    TPMIF_STATE_FINISH,
> +    /* Cancel requested or vTPM working */
> +    TPMIF_STATE_CANCEL,
> +};
> +
> +static AioContext *vtpm_aio_ctx;
> +
> +enum status_bits {
> +    VTPM_STATUS_RUNNING  = 0x1,
> +    VTPM_STATUS_IDLE     = 0x2,
> +    VTPM_STATUS_RESULT   = 0x4,
> +    VTPM_STATUS_CANCELED = 0x8,
> +};
> +
> +struct tpmif_shared_page {
> +    /* Request and response length in bytes */
> +    uint32_t length;
> +    /* Enum tpmif_state */
> +    uint8_t  state;
> +    /* For the current request */
> +    uint8_t  locality;
> +    /* Should be zero */
> +    uint8_t  pad;
> +    /* Extra pages for long packets; may be zero */
> +    uint8_t  nr_extra_pages;
> +    /*
> +     * Grant IDs, the length is actually nr_extra_pages.
> +     * beyond the extra_pages entries is the actual request
> +     * and response.
> +     */
> +    uint32_t extra_pages[0];
> +};
> +
> +struct xen_vtpm_dev {
> +    struct XenDevice xendev;  /* must be first */
> +    struct           tpmif_shared_page *shr;
> +    xc_gntshr        *xen_xcs;
> +    int              ring_ref;
> +    int              bedomid;
> +    QEMUBH           *sr_bh;
> +};
> +
> +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev) {
> +    switch (vtpmdev->shr->state) {
> +    case TPMIF_STATE_IDLE:
> +    case TPMIF_STATE_FINISH:
> +        return VTPM_STATUS_IDLE;
> +    case TPMIF_STATE_SUBMIT:
> +    case TPMIF_STATE_CANCEL:
> +        return VTPM_STATUS_RUNNING;
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static bool vtpm_aio_wait(AioContext *ctx) {
> +    return aio_poll(ctx, true);
> +}
> +
> +static void sr_bh_handler(void *opaque) { }
> +
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset;
> +    size_t length = shr->length;
> +
> +    if (shr->state == TPMIF_STATE_IDLE) {
> +        return -ECANCELED;
> +    }
> +
> +    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + length > PAGE_SIZE) {
> +        length = PAGE_SIZE - offset;
> +    }
> +
> +    memcpy(buf, offset + (uint8_t *)shr, length);
> +    *count = length;
> +
> +    return 0;
> +}
> +
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset = sizeof(*shr) +
> +
> +sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + count > PAGE_SIZE) {
> +        return -ECANCELED;
> +    }
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    memcpy(offset + (uint8_t *)shr, buf, count);
> +    shr->length = count;
> +    barrier();
> +    shr->state = TPMIF_STATE_SUBMIT;
> +    xen_wmb();
> +    xen_be_send_notify(&vtpmdev->xendev);
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    return count;
> +}
> +
> +static int vtpm_initialise(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +    xs_transaction_t xbt = XBT_NULL;
> +    unsigned int ring_ref;
> +
> +    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev,
> "frontend");
> +    if (vtpmdev->xendev.fe == NULL) {
> +        return -1;
> +    }
> +
> +    /* Get backend domid */
> +    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
> +                             &vtpmdev->bedomid)) {
> +        return -1;
> +    }
> +
> +    /* Alloc shared page */
> +    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs,
> vtpmdev->bedomid, 1,
> +                                         &ring_ref,
> PROT_READ|PROT_WRITE);
> +    vtpmdev->ring_ref = ring_ref;
> +    if (vtpmdev->shr == NULL) {
> +        return -1;
> +    }
> +
> +    /* Create event channel */
> +    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +        return -1;
> +    }
> +
> +    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
> +                     vtpmdev->xendev.local_port);
> +
> +again:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
> +                           vtpmdev->ring_ref)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
> +                           vtpmdev->xendev.local_port)) {
> +        goto abort_transaction;
> +    }
> +
> +    /* Publish protocol v2 feature */
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto again;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}
> +
> +static int vtpm_free(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    aio_poll(vtpm_aio_ctx, false);
> +    qemu_bh_delete(vtpmdev->sr_bh);
> +    if (vtpmdev->shr) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    }
> +    xc_interface_close(vtpmdev->xen_xcs);
> +    return 0;
> +}
> +
> +static int vtpm_init(struct XenDevice *xendev) {
> +    char path[XEN_BUFSIZE];
> +    char *value;
> +    unsigned int stubdom_vtpm = 0;
> +
> +    snprintf(path, sizeof(path),
> "/local/domain/%d/platform/acpi_stubdom_vtpm",
> +             xen_domid);
> +    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
> +    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
> +        free(value);
> +        return -1;
> +    }
> +    free(value);
> +    return 0;
> +}
> +
> +static void vtpm_alloc(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    vtpm_aio_ctx = aio_context_new(NULL);
> +    if (vtpm_aio_ctx == NULL) {
> +        return;
> +    }
> +    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0); }
> +
> +static void vtpm_event(struct XenDevice *xendev) {
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct
> xen_vtpm_dev,
> +                                                xendev);
> +
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +}
> +
> +struct XenDevOps xen_vtpmdev_ops = {
> +    .size             = sizeof(struct xen_vtpm_dev),
> +    .flags            = DEVOPS_FLAG_IGNORE_STATE |
> +                        DEVOPS_FLAG_FE,
> +    .event            = vtpm_event,
> +    .free             = vtpm_free,
> +    .init             = vtpm_init,
> +    .alloc            = vtpm_alloc,
> +    .initialise       = vtpm_initialise,
> +    .backend_changed  = vtpm_backend_changed, };
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c index
> 55af45a..1ca7342 100644
> --- a/hw/xen/xen_frontend.c
> +++ b/hw/xen/xen_frontend.c
> @@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
> 
>  /* ------------------------------------------------------------- */
> 
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node) {
> +    int be_state;
> +
> +    if (strcmp(node, "state") == 0) {
> +        xenstore_read_be_int(xendev, node, &be_state);
> +        switch (be_state) {
> +        case XenbusStateConnected:
> +            /* TODO */
> +            break;
> +        case XenbusStateClosing:
> +        case XenbusStateClosed:
> +            xenbus_switch_state(xendev, XenbusStateClosing);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +}
> +
>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
> {
>      xendev->local_port =
> xc_evtchn_bind_unbound_port(xendev->evtchndev,
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index bb0b303..b959413 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps
> *ops);  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> remote_dom);  int xenbus_switch_state(struct XenDevice *xendev, enum
> xenbus_state xbus);
> 
> +/* Xen vtpm */
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node);
> +
>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
>  extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
> diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
> index 38f29fb..7268d0c 100644
> --- a/include/hw/xen/xen_common.h
> +++ b/include/hw/xen/xen_common.h
> @@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger,
> void *dombuild_logger,
>      return xc_interface_open(logger, dombuild_logger, open_flags);  }
> 
> +static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
> +                                            unsigned int open_flags) {
> +    return xc_gntshr_open(logger, open_flags); }
> +
>  /* FIXME There is now way to have the xen fd */  static inline int
> xc_fd(xc_interface *xen_xc)  { diff --git a/xen-hvm.c b/xen-hvm.c index
> 315864c..b2403dc 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size,
> ram_addr_t *above_4g_mem_size,
>          fprintf(stderr, "%s: xen backend core setup failed\n",
> __FUNCTION__);
>          return -1;
>      }
> +
> +#ifdef CONFIG_TPM_XENSTUBDOMS
> +    xen_fe_register("vtpm", &xen_vtpmdev_ops); #endif
> +
>      xen_be_register("console", &xen_console_ops);
>      xen_be_register("vkbd", &xen_kbdmouse_ops);
>      xen_be_register("qdisk", &xen_blkdev_ops);
> --
> 1.8.3.2

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

* Re: [Qemu-devel] [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04  7:22 ` [Qemu-devel] " Quan Xu
  2015-05-04 15:25   ` Stefan Berger
@ 2015-05-04 15:25   ` Stefan Berger
  2015-05-05  2:33     ` Xu, Quan
  2015-05-05  2:33     ` Xu, Quan
  1 sibling, 2 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:25 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:22 AM, Quan Xu wrote:
> and rename it to tpm_util_is_selftest().
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

Thanks,
   Stefan




>
> --Changes in v6:
>   -Remove the redundant copy right.
>   -Reduce the includes to its minimum.
> ---
>   hw/tpm/Makefile.objs             |  2 +-
>   hw/tpm/tpm_passthrough.c         | 13 +------------
>   hw/tpm/tpm_util.c                | 39 +++++++++++++++++++++++++++++++++++++++
>   include/sysemu/tpm_backend_int.h |  1 +
>   4 files changed, 42 insertions(+), 13 deletions(-)
>   create mode 100644 hw/tpm/tpm_util.c
>
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 57919fa..e8fca65 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,3 +1,3 @@
> -common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
>   common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 2a45071..ff08e15 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
>       }
>   }
>
> -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
> -{
> -    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> -
> -    if (in_len >= sizeof(*hdr)) {
> -        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> -    }
> -
> -    return false;
> -}
> -
>   static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>                                           const uint8_t *in, uint32_t in_len,
>                                           uint8_t *out, uint32_t out_len,
> @@ -136,7 +125,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>       tpm_pt->tpm_executing = true;
>       *selftest_done = false;
>
> -    is_selftest = tpm_passthrough_is_selftest(in, in_len);
> +    is_selftest = tpm_util_is_selftest(in, in_len);
>
>       ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
>       if (ret != in_len) {
> diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
> new file mode 100644
> index 0000000..73be8c5
> --- /dev/null
> +++ b/hw/tpm/tpm_util.c
> @@ -0,0 +1,39 @@
> +/*
> + *  TPM util functions
> + *
> + * *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + *  Copyright (c) 2010 - 2013 IBM Corporation
> + *  Authors:
> + *    Stefan Berger <stefanb@us.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "sysemu/tpm_backend.h"
> +#include "tpm_int.h"
> +#include "sysemu/tpm_backend_int.h"
> +
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
> +{
> +    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> +
> +    if (in_len >= sizeof(*hdr)) {
> +        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> +    }
> +
> +    return false;
> +}
> diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
> index 05d94d0..e18acab 100644
> --- a/include/sysemu/tpm_backend_int.h
> +++ b/include/sysemu/tpm_backend_int.h
> @@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread *tbt,
>   void tpm_backend_thread_end(TPMBackendThread *tbt);
>   void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
>                                     GFunc func, gpointer user_data);
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
>
>   typedef enum TPMBackendCmd {
>       TPM_BACKEND_CMD_INIT = 1,

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

* Re: [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04  7:22 ` [Qemu-devel] " Quan Xu
@ 2015-05-04 15:25   ` Stefan Berger
  2015-05-04 15:25   ` [Qemu-devel] " Stefan Berger
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:25 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:22 AM, Quan Xu wrote:
> and rename it to tpm_util_is_selftest().
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

Thanks,
   Stefan




>
> --Changes in v6:
>   -Remove the redundant copy right.
>   -Reduce the includes to its minimum.
> ---
>   hw/tpm/Makefile.objs             |  2 +-
>   hw/tpm/tpm_passthrough.c         | 13 +------------
>   hw/tpm/tpm_util.c                | 39 +++++++++++++++++++++++++++++++++++++++
>   include/sysemu/tpm_backend_int.h |  1 +
>   4 files changed, 42 insertions(+), 13 deletions(-)
>   create mode 100644 hw/tpm/tpm_util.c
>
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 57919fa..e8fca65 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,3 +1,3 @@
> -common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
>   common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 2a45071..ff08e15 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
>       }
>   }
>
> -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
> -{
> -    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> -
> -    if (in_len >= sizeof(*hdr)) {
> -        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> -    }
> -
> -    return false;
> -}
> -
>   static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>                                           const uint8_t *in, uint32_t in_len,
>                                           uint8_t *out, uint32_t out_len,
> @@ -136,7 +125,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>       tpm_pt->tpm_executing = true;
>       *selftest_done = false;
>
> -    is_selftest = tpm_passthrough_is_selftest(in, in_len);
> +    is_selftest = tpm_util_is_selftest(in, in_len);
>
>       ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
>       if (ret != in_len) {
> diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
> new file mode 100644
> index 0000000..73be8c5
> --- /dev/null
> +++ b/hw/tpm/tpm_util.c
> @@ -0,0 +1,39 @@
> +/*
> + *  TPM util functions
> + *
> + * *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + *  Copyright (c) 2010 - 2013 IBM Corporation
> + *  Authors:
> + *    Stefan Berger <stefanb@us.ibm.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include "sysemu/tpm_backend.h"
> +#include "tpm_int.h"
> +#include "sysemu/tpm_backend_int.h"
> +
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
> +{
> +    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> +
> +    if (in_len >= sizeof(*hdr)) {
> +        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> +    }
> +
> +    return false;
> +}
> diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
> index 05d94d0..e18acab 100644
> --- a/include/sysemu/tpm_backend_int.h
> +++ b/include/sysemu/tpm_backend_int.h
> @@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread *tbt,
>   void tpm_backend_thread_end(TPMBackendThread *tbt);
>   void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
>                                     GFunc func, gpointer user_data);
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
>
>   typedef enum TPMBackendCmd {
>       TPM_BACKEND_CMD_INIT = 1,

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

* Re: [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen Quan Xu
@ 2015-05-04 15:30   ` Stefan Berger
  2015-05-05  2:34     ` Xu, Quan
  2015-05-05  2:34     ` Xu, Quan
  2015-05-04 15:30   ` Stefan Berger
  1 sibling, 2 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:30 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:23 AM, Quan Xu wrote:
> This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
> stubdom vTPM domain that provides the actual TPM functionality. It
> sends data and TPM commends with xen_vtpm_frontend. It is similar as
> another two vTPM backens:
>    *vTPM passthrough backen Since QEMU 1.5.
>    *vTPM libtpms-based backen.
>
> Some details:
> This part of the patch provides support for the spawning of a thread
> that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
> It expects a signal from the frontend to wake and pick up the TPM
> command that is supposed to be processed and delivers the response
> packet using a callback function provided by the frontend.
>
> The backend connects itself to the frontend by filling out an interface
> structure with pointers to the function implementing support for various
> operations.
>
> (QEMU) vTPM XenStubdoms backen is initialized by Qemu command line options,
>        "-tpmdev xenstubdoms,id=xenvtpm0 -device tpm-tis,tpmdev=xenvtpm0"
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>

Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

+
+#ifdef DEBUG_TPM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif


In case some other parts needs revision, please use the following instead:

#define DEBUG_TPM 0

#define DPRINTF(fmt, ...) do { \
     if (DEBUG_TPM) { \
         fprintf(stderr, fmt, ## __VA_ARGS__); \
     } \
} while (0);


    Stefan

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

* Re: [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen Quan Xu
  2015-05-04 15:30   ` Stefan Berger
@ 2015-05-04 15:30   ` Stefan Berger
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:30 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:23 AM, Quan Xu wrote:
> This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
> stubdom vTPM domain that provides the actual TPM functionality. It
> sends data and TPM commends with xen_vtpm_frontend. It is similar as
> another two vTPM backens:
>    *vTPM passthrough backen Since QEMU 1.5.
>    *vTPM libtpms-based backen.
>
> Some details:
> This part of the patch provides support for the spawning of a thread
> that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
> It expects a signal from the frontend to wake and pick up the TPM
> command that is supposed to be processed and delivers the response
> packet using a callback function provided by the frontend.
>
> The backend connects itself to the frontend by filling out an interface
> structure with pointers to the function implementing support for various
> operations.
>
> (QEMU) vTPM XenStubdoms backen is initialized by Qemu command line options,
>        "-tpmdev xenstubdoms,id=xenvtpm0 -device tpm-tis,tpmdev=xenvtpm0"
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>

Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

+
+#ifdef DEBUG_TPM
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif


In case some other parts needs revision, please use the following instead:

#define DEBUG_TPM 0

#define DPRINTF(fmt, ...) do { \
     if (DEBUG_TPM) { \
         fprintf(stderr, fmt, ## __VA_ARGS__); \
     } \
} while (0);


    Stefan

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
                     ` (3 preceding siblings ...)
  (?)
@ 2015-05-04 15:36   ` Stefan Berger
  2015-05-05  2:41     ` Xu, Quan
                       ` (2 more replies)
  -1 siblings, 3 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:36 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:22 AM, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
>
> Call xen_fe_register() function to register XenDevOps, and make sure,
>           [...]
>      3 = ""
>       [...]
>       device = "" (frontend device, the backend is running in QEMU/.etc)
>        vkbd = ""
>         [...]
>        vif = ""
>         [...]
>
>   ..
>
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>    xen_hvm_init()
>      [...]
>      -->xen_fe_register("vtpm", ...)
>        -->xenstore_fe_scan()
>          -->xen_fe_try_init(ops)
>            --> XenDevOps.init()
>          -->xen_fe_get_xendev()
>            --> XenDevOps.alloc()
>          -->xen_fe_check()
>            -->xen_fe_try_initialise()
>              --> XenDevOps.initialise()
>            -->xen_fe_try_connected()
>              --> XenDevOps.connected()
>          -->xs_watch()
>      [...]
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>
>
> --Changes in v6:
>   -Replace buf_size with PAGE_SIZE and use length rather than
>    shr->length.
> ---
>   hw/tpm/Makefile.objs         |   1 +
>   hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
>   hw/xen/xen_frontend.c        |  20 +++
>   include/hw/xen/xen_backend.h |   5 +
>   include/hw/xen/xen_common.h  |   6 +
>   xen-hvm.c                    |   5 +
>   6 files changed, 352 insertions(+)
>   create mode 100644 hw/tpm/xen_vtpm_frontend.c
>
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644
> index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif

You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.

With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

Regards,
     Stefan

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
                     ` (2 preceding siblings ...)
  (?)
@ 2015-05-04 15:36   ` Stefan Berger
  -1 siblings, 0 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-04 15:36 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, eblake
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

On 05/04/2015 03:22 AM, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
>
> Call xen_fe_register() function to register XenDevOps, and make sure,
>           [...]
>      3 = ""
>       [...]
>       device = "" (frontend device, the backend is running in QEMU/.etc)
>        vkbd = ""
>         [...]
>        vif = ""
>         [...]
>
>   ..
>
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>    xen_hvm_init()
>      [...]
>      -->xen_fe_register("vtpm", ...)
>        -->xenstore_fe_scan()
>          -->xen_fe_try_init(ops)
>            --> XenDevOps.init()
>          -->xen_fe_get_xendev()
>            --> XenDevOps.alloc()
>          -->xen_fe_check()
>            -->xen_fe_try_initialise()
>              --> XenDevOps.initialise()
>            -->xen_fe_try_connected()
>              --> XenDevOps.connected()
>          -->xs_watch()
>      [...]
>
> Signed-off-by: Quan Xu <quan.xu@intel.com>
>
> --Changes in v6:
>   -Replace buf_size with PAGE_SIZE and use length rather than
>    shr->length.
> ---
>   hw/tpm/Makefile.objs         |   1 +
>   hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
>   hw/xen/xen_frontend.c        |  20 +++
>   include/hw/xen/xen_backend.h |   5 +
>   include/hw/xen/xen_common.h  |   6 +
>   xen-hvm.c                    |   5 +
>   6 files changed, 352 insertions(+)
>   create mode 100644 hw/tpm/xen_vtpm_frontend.c
>
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644
> index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif

You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.

With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

Regards,
     Stefan

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

* Re: [Qemu-devel] [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04 15:25   ` [Qemu-devel] " Stefan Berger
@ 2015-05-05  2:33     ` Xu, Quan
  2015-05-05  2:33     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:33 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:26 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 4/6] Qemu-Xen-vTPM: Move
> tpm_passthrough_is_selftest() into tpm_util.c
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > and rename it to tpm_util_is_selftest().
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> Thanks,
>    Stefan
> 

Stefan, thanks for your help and review.


thanks
Quan


> 
> 
> 
> >
> > --Changes in v6:
> >   -Remove the redundant copy right.
> >   -Reduce the includes to its minimum.
> > ---
> >   hw/tpm/Makefile.objs             |  2 +-
> >   hw/tpm/tpm_passthrough.c         | 13 +------------
> >   hw/tpm/tpm_util.c                | 39
> +++++++++++++++++++++++++++++++++++++++
> >   include/sysemu/tpm_backend_int.h |  1 +
> >   4 files changed, 42 insertions(+), 13 deletions(-)
> >   create mode 100644 hw/tpm/tpm_util.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 57919fa..e8fca65 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,3 +1,3 @@
> > -common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> > +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> >   common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff
> > --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index
> > 2a45071..ff08e15 100644
> > --- a/hw/tpm/tpm_passthrough.c
> > +++ b/hw/tpm/tpm_passthrough.c
> > @@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t
> *out, uint32_t out_len)
> >       }
> >   }
> >
> > -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t
> > in_len) -{
> > -    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> > -
> > -    if (in_len >= sizeof(*hdr)) {
> > -        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> > -    }
> > -
> > -    return false;
> > -}
> > -
> >   static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> >                                           const uint8_t *in, uint32_t
> in_len,
> >                                           uint8_t *out, uint32_t
> > out_len, @@ -136,7 +125,7 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> >       tpm_pt->tpm_executing = true;
> >       *selftest_done = false;
> >
> > -    is_selftest = tpm_passthrough_is_selftest(in, in_len);
> > +    is_selftest = tpm_util_is_selftest(in, in_len);
> >
> >       ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
> >       if (ret != in_len) {
> > diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c new file mode
> > 100644 index 0000000..73be8c5
> > --- /dev/null
> > +++ b/hw/tpm/tpm_util.c
> > @@ -0,0 +1,39 @@
> > +/*
> > + *  TPM util functions
> > + *
> > + * *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + *  Copyright (c) 2010 - 2013 IBM Corporation
> > + *  Authors:
> > + *    Stefan Berger <stefanb@us.ibm.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include "sysemu/tpm_backend.h"
> > +#include "tpm_int.h"
> > +#include "sysemu/tpm_backend_int.h"
> > +
> > +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) {
> > +    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> > +
> > +    if (in_len >= sizeof(*hdr)) {
> > +        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> > +    }
> > +
> > +    return false;
> > +}
> > diff --git a/include/sysemu/tpm_backend_int.h
> > b/include/sysemu/tpm_backend_int.h
> > index 05d94d0..e18acab 100644
> > --- a/include/sysemu/tpm_backend_int.h
> > +++ b/include/sysemu/tpm_backend_int.h
> > @@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread
> *tbt,
> >   void tpm_backend_thread_end(TPMBackendThread *tbt);
> >   void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
> >                                     GFunc func, gpointer user_data);
> > +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
> >
> >   typedef enum TPMBackendCmd {
> >       TPM_BACKEND_CMD_INIT = 1,

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

* Re: [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c
  2015-05-04 15:25   ` [Qemu-devel] " Stefan Berger
  2015-05-05  2:33     ` Xu, Quan
@ 2015-05-05  2:33     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:33 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:26 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 4/6] Qemu-Xen-vTPM: Move
> tpm_passthrough_is_selftest() into tpm_util.c
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > and rename it to tpm_util_is_selftest().
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> Thanks,
>    Stefan
> 

Stefan, thanks for your help and review.


thanks
Quan


> 
> 
> 
> >
> > --Changes in v6:
> >   -Remove the redundant copy right.
> >   -Reduce the includes to its minimum.
> > ---
> >   hw/tpm/Makefile.objs             |  2 +-
> >   hw/tpm/tpm_passthrough.c         | 13 +------------
> >   hw/tpm/tpm_util.c                | 39
> +++++++++++++++++++++++++++++++++++++++
> >   include/sysemu/tpm_backend_int.h |  1 +
> >   4 files changed, 42 insertions(+), 13 deletions(-)
> >   create mode 100644 hw/tpm/tpm_util.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 57919fa..e8fca65 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,3 +1,3 @@
> > -common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> > +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o tpm_util.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> >   common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff
> > --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index
> > 2a45071..ff08e15 100644
> > --- a/hw/tpm/tpm_passthrough.c
> > +++ b/hw/tpm/tpm_passthrough.c
> > @@ -112,17 +112,6 @@ static void tpm_write_fatal_error_response(uint8_t
> *out, uint32_t out_len)
> >       }
> >   }
> >
> > -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t
> > in_len) -{
> > -    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> > -
> > -    if (in_len >= sizeof(*hdr)) {
> > -        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> > -    }
> > -
> > -    return false;
> > -}
> > -
> >   static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> >                                           const uint8_t *in, uint32_t
> in_len,
> >                                           uint8_t *out, uint32_t
> > out_len, @@ -136,7 +125,7 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> >       tpm_pt->tpm_executing = true;
> >       *selftest_done = false;
> >
> > -    is_selftest = tpm_passthrough_is_selftest(in, in_len);
> > +    is_selftest = tpm_util_is_selftest(in, in_len);
> >
> >       ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
> >       if (ret != in_len) {
> > diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c new file mode
> > 100644 index 0000000..73be8c5
> > --- /dev/null
> > +++ b/hw/tpm/tpm_util.c
> > @@ -0,0 +1,39 @@
> > +/*
> > + *  TPM util functions
> > + *
> > + * *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + *  Copyright (c) 2010 - 2013 IBM Corporation
> > + *  Authors:
> > + *    Stefan Berger <stefanb@us.ibm.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include "sysemu/tpm_backend.h"
> > +#include "tpm_int.h"
> > +#include "sysemu/tpm_backend_int.h"
> > +
> > +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) {
> > +    struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> > +
> > +    if (in_len >= sizeof(*hdr)) {
> > +        return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> > +    }
> > +
> > +    return false;
> > +}
> > diff --git a/include/sysemu/tpm_backend_int.h
> > b/include/sysemu/tpm_backend_int.h
> > index 05d94d0..e18acab 100644
> > --- a/include/sysemu/tpm_backend_int.h
> > +++ b/include/sysemu/tpm_backend_int.h
> > @@ -34,6 +34,7 @@ void tpm_backend_thread_create(TPMBackendThread
> *tbt,
> >   void tpm_backend_thread_end(TPMBackendThread *tbt);
> >   void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
> >                                     GFunc func, gpointer user_data);
> > +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
> >
> >   typedef enum TPMBackendCmd {
> >       TPM_BACKEND_CMD_INIT = 1,

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

* Re: [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04 15:30   ` Stefan Berger
@ 2015-05-05  2:34     ` Xu, Quan
  2015-05-05  2:34     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:34 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:30 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms
> backen.
> 
> On 05/04/2015 03:23 AM, Quan Xu wrote:
> > This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
> > stubdom vTPM domain that provides the actual TPM functionality. It
> > sends data and TPM commends with xen_vtpm_frontend. It is similar as
> > another two vTPM backens:
> >    *vTPM passthrough backen Since QEMU 1.5.
> >    *vTPM libtpms-based backen.
> >
> > Some details:
> > This part of the patch provides support for the spawning of a thread
> > that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
> > It expects a signal from the frontend to wake and pick up the TPM
> > command that is supposed to be processed and delivers the response
> > packet using a callback function provided by the frontend.
> >
> > The backend connects itself to the frontend by filling out an
> > interface structure with pointers to the function implementing support
> > for various operations.
> >
> > (QEMU) vTPM XenStubdoms backen is initialized by Qemu command line
> options,
> >        "-tpmdev xenstubdoms,id=xenvtpm0 -device
> tpm-tis,tpmdev=xenvtpm0"
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 

Stefan, thanks again for your help and review. I will add the below code in next version.


thanks
Quan
> +
> +#ifdef DEBUG_TPM
> +#define DPRINTF(fmt, ...) \
> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else
> +#define DPRINTF(fmt, ...) \
> +    do { } while (0)
> +#endif
> 
> 
> In case some other parts needs revision, please use the following instead:
> 
> #define DEBUG_TPM 0
> 
> #define DPRINTF(fmt, ...) do { \
>      if (DEBUG_TPM) { \
>          fprintf(stderr, fmt, ## __VA_ARGS__); \
>      } \
> } while (0);
> 
> 
>     Stefan

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

* Re: [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen.
  2015-05-04 15:30   ` Stefan Berger
  2015-05-05  2:34     ` Xu, Quan
@ 2015-05-05  2:34     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:34 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:30 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms
> backen.
> 
> On 05/04/2015 03:23 AM, Quan Xu wrote:
> > This Patch provides the glue for the TPM_TIS(Qemu frontend) to Xen
> > stubdom vTPM domain that provides the actual TPM functionality. It
> > sends data and TPM commends with xen_vtpm_frontend. It is similar as
> > another two vTPM backens:
> >    *vTPM passthrough backen Since QEMU 1.5.
> >    *vTPM libtpms-based backen.
> >
> > Some details:
> > This part of the patch provides support for the spawning of a thread
> > that will interact with stubdom vTPM domain by the xen_vtpm_frontend.
> > It expects a signal from the frontend to wake and pick up the TPM
> > command that is supposed to be processed and delivers the response
> > packet using a callback function provided by the frontend.
> >
> > The backend connects itself to the frontend by filling out an
> > interface structure with pointers to the function implementing support
> > for various operations.
> >
> > (QEMU) vTPM XenStubdoms backen is initialized by Qemu command line
> options,
> >        "-tpmdev xenstubdoms,id=xenvtpm0 -device
> tpm-tis,tpmdev=xenvtpm0"
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 

Stefan, thanks again for your help and review. I will add the below code in next version.


thanks
Quan
> +
> +#ifdef DEBUG_TPM
> +#define DPRINTF(fmt, ...) \
> +    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else
> +#define DPRINTF(fmt, ...) \
> +    do { } while (0)
> +#endif
> 
> 
> In case some other parts needs revision, please use the following instead:
> 
> #define DEBUG_TPM 0
> 
> #define DPRINTF(fmt, ...) do { \
>      if (DEBUG_TPM) { \
>          fprintf(stderr, fmt, ## __VA_ARGS__); \
>      } \
> } while (0);
> 
> 
>     Stefan

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04 15:36   ` [Qemu-devel] " Stefan Berger
  2015-05-05  2:41     ` Xu, Quan
@ 2015-05-05  2:41     ` Xu, Quan
  2015-05-05 10:23       ` Stefan Berger
  2015-05-11 12:56       ` Xu, Quan
  2 siblings, 1 reply; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:41 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:36 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> >           [...]
> >      3 = ""
> >       [...]
> >       device = "" (frontend device, the backend is running in QEMU/.etc)
> >        vkbd = ""
> >         [...]
> >        vif = ""
> >         [...]
> >
> >   ..
> >
> > (QEMU) xen_vtpmdev_ops is initialized with the following process:
> >    xen_hvm_init()
> >      [...]
> >      -->xen_fe_register("vtpm", ...)
> >        -->xenstore_fe_scan()
> >          -->xen_fe_try_init(ops)
> >            --> XenDevOps.init()
> >          -->xen_fe_get_xendev()
> >            --> XenDevOps.alloc()
> >          -->xen_fe_check()
> >            -->xen_fe_try_initialise()
> >              --> XenDevOps.initialise()
> >            -->xen_fe_try_connected()
> >              --> XenDevOps.connected()
> >          -->xs_watch()
> >      [...]
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >   -Replace buf_size with PAGE_SIZE and use length rather than
> >    shr->length.
> > ---
> >   hw/tpm/Makefile.objs         |   1 +
> >   hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
> >   hw/xen/xen_frontend.c        |  20 +++
> >   include/hw/xen/xen_backend.h |   5 +
> >   include/hw/xen/xen_common.h  |   6 +
> >   xen-hvm.c                    |   5 +
> >   6 files changed, 352 insertions(+)
> >   create mode 100644 hw/tpm/xen_vtpm_frontend.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 99f5983..57919fa 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,2 +1,3 @@
> >   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> > +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> > diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> > new file mode 100644 index 0000000..d6e7cc6
> > --- /dev/null
> > +++ b/hw/tpm/xen_vtpm_frontend.c
> > @@ -0,0 +1,315 @@
> > +/*
> > + * Connect to Xen vTPM stubdom domain
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <signal.h>
> > +#include <inttypes.h>
> > +#include <time.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/uio.h>
> > +
> > +#include "hw/hw.h"
> > +#include "block/aio.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#ifndef XS_STUBDOM_VTPM_ENABLE
> > +#define XS_STUBDOM_VTPM_ENABLE    "1"
> > +#endif
> > +
> > +#ifndef PAGE_SIZE
> > +#define PAGE_SIZE      4096
> > +#endif
> 
> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> 
> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 


Stefan, thanks.
I will use TARGET_PAGE_SIZE from exec/cpu-all.h in next version.
Could I redefine PAGE_SIZE as kvm-all.c?
+#define PAGE_SIZE TARGET_PAGE_SIZE


thanks
Quan


> Regards,
>      Stefan

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04 15:36   ` [Qemu-devel] " Stefan Berger
@ 2015-05-05  2:41     ` Xu, Quan
  2015-05-05  2:41     ` [Qemu-devel] " Xu, Quan
  2015-05-11 12:56       ` Xu, Quan
  2 siblings, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-05  2:41 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:36 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> >           [...]
> >      3 = ""
> >       [...]
> >       device = "" (frontend device, the backend is running in QEMU/.etc)
> >        vkbd = ""
> >         [...]
> >        vif = ""
> >         [...]
> >
> >   ..
> >
> > (QEMU) xen_vtpmdev_ops is initialized with the following process:
> >    xen_hvm_init()
> >      [...]
> >      -->xen_fe_register("vtpm", ...)
> >        -->xenstore_fe_scan()
> >          -->xen_fe_try_init(ops)
> >            --> XenDevOps.init()
> >          -->xen_fe_get_xendev()
> >            --> XenDevOps.alloc()
> >          -->xen_fe_check()
> >            -->xen_fe_try_initialise()
> >              --> XenDevOps.initialise()
> >            -->xen_fe_try_connected()
> >              --> XenDevOps.connected()
> >          -->xs_watch()
> >      [...]
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >   -Replace buf_size with PAGE_SIZE and use length rather than
> >    shr->length.
> > ---
> >   hw/tpm/Makefile.objs         |   1 +
> >   hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
> >   hw/xen/xen_frontend.c        |  20 +++
> >   include/hw/xen/xen_backend.h |   5 +
> >   include/hw/xen/xen_common.h  |   6 +
> >   xen-hvm.c                    |   5 +
> >   6 files changed, 352 insertions(+)
> >   create mode 100644 hw/tpm/xen_vtpm_frontend.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 99f5983..57919fa 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,2 +1,3 @@
> >   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> > +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> > diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> > new file mode 100644 index 0000000..d6e7cc6
> > --- /dev/null
> > +++ b/hw/tpm/xen_vtpm_frontend.c
> > @@ -0,0 +1,315 @@
> > +/*
> > + * Connect to Xen vTPM stubdom domain
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <signal.h>
> > +#include <inttypes.h>
> > +#include <time.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/uio.h>
> > +
> > +#include "hw/hw.h"
> > +#include "block/aio.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#ifndef XS_STUBDOM_VTPM_ENABLE
> > +#define XS_STUBDOM_VTPM_ENABLE    "1"
> > +#endif
> > +
> > +#ifndef PAGE_SIZE
> > +#define PAGE_SIZE      4096
> > +#endif
> 
> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> 
> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 


Stefan, thanks.
I will use TARGET_PAGE_SIZE from exec/cpu-all.h in next version.
Could I redefine PAGE_SIZE as kvm-all.c?
+#define PAGE_SIZE TARGET_PAGE_SIZE


thanks
Quan


> Regards,
>      Stefan

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-05  2:41     ` [Qemu-devel] " Xu, Quan
@ 2015-05-05 10:23       ` Stefan Berger
  0 siblings, 0 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-05 10:23 UTC (permalink / raw)
  To: Xu, Quan; +Cc: dgdegra, xen-devel, wei.liu2, qemu-devel, stefano.stabellini

On 05/04/2015 10:41 PM, Xu, Quan wrote:
>
>> -----Original Message-----
>> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
>> Sent: Monday, May 04, 2015 11:36 PM
>> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
>> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
>> xen-devel@lists.xen.org
>> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
>>
>> On 05/04/2015 03:22 AM, Quan Xu wrote:
>>> This patch adds infrastructure for xen front drivers living in qemu,
>>> so drivers don't need to implement common stuff on their own.  It's
>>> mostly xenbus management stuff: some functions to access XenStore,
>>> setting up XenStore watches, callbacks on device discovery and state
>>> changes, and handle event channel between the virtual machines.
>>>
>>> Call xen_fe_register() function to register XenDevOps, and make sure,
>>>            [...]
>>>       3 = ""
>>>        [...]
>>>        device = "" (frontend device, the backend is running in QEMU/.etc)
>>>         vkbd = ""
>>>          [...]
>>>         vif = ""
>>>          [...]
>>>
>>>    ..
>>>
>>> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>>>     xen_hvm_init()
>>>       [...]
>>>       -->xen_fe_register("vtpm", ...)
>>>         -->xenstore_fe_scan()
>>>           -->xen_fe_try_init(ops)
>>>             --> XenDevOps.init()
>>>           -->xen_fe_get_xendev()
>>>             --> XenDevOps.alloc()
>>>           -->xen_fe_check()
>>>             -->xen_fe_try_initialise()
>>>               --> XenDevOps.initialise()
>>>             -->xen_fe_try_connected()
>>>               --> XenDevOps.connected()
>>>           -->xs_watch()
>>>       [...]
>>>
>>> Signed-off-by: Quan Xu <quan.xu@intel.com>
>>>
>>> --Changes in v6:
>>>    -Replace buf_size with PAGE_SIZE and use length rather than
>>>     shr->length.
>>> ---
>>>    hw/tpm/Makefile.objs         |   1 +
>>>    hw/tpm/xen_vtpm_frontend.c   | 315
>> +++++++++++++++++++++++++++++++++++++++++++
>>>    hw/xen/xen_frontend.c        |  20 +++
>>>    include/hw/xen/xen_backend.h |   5 +
>>>    include/hw/xen/xen_common.h  |   6 +
>>>    xen-hvm.c                    |   5 +
>>>    6 files changed, 352 insertions(+)
>>>    create mode 100644 hw/tpm/xen_vtpm_frontend.c
>>>
>>> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
>>> 99f5983..57919fa 100644
>>> --- a/hw/tpm/Makefile.objs
>>> +++ b/hw/tpm/Makefile.objs
>>> @@ -1,2 +1,3 @@
>>>    common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>>>    common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
>>> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
>>> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
>>> new file mode 100644 index 0000000..d6e7cc6
>>> --- /dev/null
>>> +++ b/hw/tpm/xen_vtpm_frontend.c
>>> @@ -0,0 +1,315 @@
>>> +/*
>>> + * Connect to Xen vTPM stubdom domain
>>> + *
>>> + *  Copyright (c) 2015 Intel Corporation
>>> + *  Authors:
>>> + *    Quan Xu <quan.xu@intel.com>
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2 of the License, or (at your option) any later version.
>>> + *
>>> + * This library is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library; if not, see
>>> +<http://www.gnu.org/licenses/>  */
>>> +
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <stdarg.h>
>>> +#include <string.h>
>>> +#include <unistd.h>
>>> +#include <signal.h>
>>> +#include <inttypes.h>
>>> +#include <time.h>
>>> +#include <fcntl.h>
>>> +#include <errno.h>
>>> +#include <sys/ioctl.h>
>>> +#include <sys/types.h>
>>> +#include <sys/stat.h>
>>> +#include <sys/mman.h>
>>> +#include <sys/uio.h>
>>> +
>>> +#include "hw/hw.h"
>>> +#include "block/aio.h"
>>> +#include "hw/xen/xen_backend.h"
>>> +
>>> +#ifndef XS_STUBDOM_VTPM_ENABLE
>>> +#define XS_STUBDOM_VTPM_ENABLE    "1"
>>> +#endif
>>> +
>>> +#ifndef PAGE_SIZE
>>> +#define PAGE_SIZE      4096
>>> +#endif
>> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
>>
>> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>
> Stefan, thanks.
> I will use TARGET_PAGE_SIZE from exec/cpu-all.h in next version.
> Could I redefine PAGE_SIZE as kvm-all.c?
> +#define PAGE_SIZE TARGET_PAGE_SIZE

I guess it would be ok.

    Stefan

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

* Re: [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Quan Xu
  2015-05-05 14:28   ` Eric Blake
@ 2015-05-05 14:28   ` Eric Blake
  2015-05-06  2:02     ` Xu, Quan
  2015-05-06  2:02     ` Xu, Quan
  1 sibling, 2 replies; 48+ messages in thread
From: Eric Blake @ 2015-05-05 14:28 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, stefanb
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel

[-- Attachment #1: Type: text/plain, Size: 545 bytes --]

On 05/04/2015 01:22 AM, Quan Xu wrote:
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Remove stray insertion.
> ---
>  configure        | 14 ++++++++++++++
>  hmp.c            |  2 ++
>  qapi-schema.json | 16 ++++++++++++++--
>  qemu-options.hx  | 13 +++++++++++--
>  tpm.c            |  7 ++++++-
>  5 files changed, 47 insertions(+), 5 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

* Re: [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Quan Xu
@ 2015-05-05 14:28   ` Eric Blake
  2015-05-05 14:28   ` [Qemu-devel] " Eric Blake
  1 sibling, 0 replies; 48+ messages in thread
From: Eric Blake @ 2015-05-05 14:28 UTC (permalink / raw)
  To: Quan Xu, stefano.stabellini, stefanb
  Cc: dgdegra, wei.liu2, qemu-devel, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 545 bytes --]

On 05/04/2015 01:22 AM, Quan Xu wrote:
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Remove stray insertion.
> ---
>  configure        | 14 ++++++++++++++
>  hmp.c            |  2 ++
>  qapi-schema.json | 16 ++++++++++++++--
>  qemu-options.hx  | 13 +++++++++++--
>  tpm.c            |  7 ++++++-
>  5 files changed, 47 insertions(+), 5 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-05 14:28   ` [Qemu-devel] " Eric Blake
@ 2015-05-06  2:02     ` Xu, Quan
  2015-05-06  2:02     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-06  2:02 UTC (permalink / raw)
  To: Eric Blake
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Eric Blake [mailto:eblake@redhat.com]
> Sent: Tuesday, May 05, 2015 10:29 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; stefanb@linux.vnet.ibm.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM
> command line options
> 
> On 05/04/2015 01:22 AM, Quan Xu wrote:
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >  -Remove stray insertion.
> > ---
> >  configure        | 14 ++++++++++++++
> >  hmp.c            |  2 ++
> >  qapi-schema.json | 16 ++++++++++++++--  qemu-options.hx  | 13
> > +++++++++++--
> >  tpm.c            |  7 ++++++-
> >  5 files changed, 47 insertions(+), 5 deletions(-)
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
> 

Eric, thanks for your review! :)

-Quan

> --
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org


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

* Re: [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options
  2015-05-05 14:28   ` [Qemu-devel] " Eric Blake
  2015-05-06  2:02     ` Xu, Quan
@ 2015-05-06  2:02     ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-06  2:02 UTC (permalink / raw)
  To: Eric Blake
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Eric Blake [mailto:eblake@redhat.com]
> Sent: Tuesday, May 05, 2015 10:29 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; stefanb@linux.vnet.ibm.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM
> command line options
> 
> On 05/04/2015 01:22 AM, Quan Xu wrote:
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >  -Remove stray insertion.
> > ---
> >  configure        | 14 ++++++++++++++
> >  hmp.c            |  2 ++
> >  qapi-schema.json | 16 ++++++++++++++--  qemu-options.hx  | 13
> > +++++++++++--
> >  tpm.c            |  7 ++++++-
> >  5 files changed, 47 insertions(+), 5 deletions(-)
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
> 

Eric, thanks for your review! :)

-Quan

> --
> Eric Blake   eblake redhat com    +1-919-301-3266
> Libvirt virtualization library http://libvirt.org

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

* Re: [Qemu-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
  (?)
  (?)
@ 2015-05-07 17:25   ` Stefano Stabellini
  2015-05-12  1:28     ` Xu, Quan
  2015-05-12  1:28     ` [Qemu-devel] [Xen-devel] " Xu, Quan
  -1 siblings, 2 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-07 17:25 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel, dgdegra

On Mon, 4 May 2015, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
> XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> the XenDevOps is Xen frontend.
> 
> Create a new file xen_pvdev.c for some common part of xen frontend
> and backend, such as xendevs queue and xenstore update functions.
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>

Better than the early versions, thanks.

However the patch is too big and it is too difficult to read as is.
Could you please split it in two: a patch that creates xen_pvdev.c and
moves a few functions from xen_backend.c to it and a second patch that
introduces xen_frontend.c.


>  hw/display/xenfb.c           |   4 +-
>  hw/xen/Makefile.objs         |   2 +-
>  hw/xen/xen_backend.c         | 353 -------------------------------
>  hw/xen/xen_frontend.c        | 345 +++++++++++++++++++++++++++++++
>  hw/xen/xen_pvdev.c           | 481 +++++++++++++++++++++++++++++++++++++++++++
>  include/hw/xen/xen_backend.h |  22 +-
>  6 files changed, 850 insertions(+), 357 deletions(-)
>  create mode 100644 hw/xen/xen_frontend.c
>  create mode 100644 hw/xen/xen_pvdev.c
> 
> diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
> index 5e324ef..10751df 100644
> --- a/hw/display/xenfb.c
> +++ b/hw/display/xenfb.c
> @@ -988,8 +988,8 @@ void xen_init_display(int domid)
>  wait_more:
>      i++;
>      main_loop_wait(true);
> -    xfb = xen_be_find_xendev("vfb", domid, 0);
> -    xin = xen_be_find_xendev("vkbd", domid, 0);
> +    xfb = xen_find_xendev("vfb", domid, 0);
> +    xin = xen_find_xendev("vkbd", domid, 0);
>      if (!xfb || !xin) {
>          if (i < 256) {
>              usleep(10000);
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
> index a0ca0aa..95eb9d0 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -1,5 +1,5 @@
>  # xen backend driver support
> -common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o xen_frontend.o xen_pvdev.o
>  
>  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
>  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
> diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
> index b2cb22b..844f918 100644
> --- a/hw/xen/xen_backend.c
> +++ b/hw/xen/xen_backend.c
> @@ -44,86 +44,11 @@
>  /* ------------------------------------------------------------- */
>  
>  /* public */
> -XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> -struct xs_handle *xenstore = NULL;
>  const char *xen_protocol;
>  
>  /* private */
> -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
>  static int debug = 0;
>  
> -/* ------------------------------------------------------------- */
> -
> -int xenstore_write_str(const char *base, const char *node, const char *val)
> -{
> -    char abspath[XEN_BUFSIZE];
> -
> -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> -    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> -        return -1;
> -    }
> -    return 0;
> -}
> -
> -char *xenstore_read_str(const char *base, const char *node)
> -{
> -    char abspath[XEN_BUFSIZE];
> -    unsigned int len;
> -    char *str, *ret = NULL;
> -
> -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> -    str = xs_read(xenstore, 0, abspath, &len);
> -    if (str != NULL) {
> -        /* move to qemu-allocated memory to make sure
> -         * callers can savely g_free() stuff. */
> -        ret = g_strdup(str);
> -        free(str);
> -    }
> -    return ret;
> -}
> -
> -int xenstore_write_int(const char *base, const char *node, int ival)
> -{
> -    char val[12];
> -
> -    snprintf(val, sizeof(val), "%d", ival);
> -    return xenstore_write_str(base, node, val);
> -}
> -
> -int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> -{
> -    char val[21];
> -
> -    snprintf(val, sizeof(val), "%"PRId64, ival);
> -    return xenstore_write_str(base, node, val);
> -}
> -
> -int xenstore_read_int(const char *base, const char *node, int *ival)
> -{
> -    char *val;
> -    int rc = -1;
> -
> -    val = xenstore_read_str(base, node);
> -    if (val && 1 == sscanf(val, "%d", ival)) {
> -        rc = 0;
> -    }
> -    g_free(val);
> -    return rc;
> -}
> -
> -int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> -{
> -    char *val;
> -    int rc = -1;
> -
> -    val = xenstore_read_str(base, node);
> -    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> -        rc = 0;
> -    }
> -    g_free(val);
> -    return rc;
> -}
> -
>  int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
>  {
>      return xenstore_write_str(xendev->be, node, val);
> @@ -195,183 +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
>  }
>  
>  /* ------------------------------------------------------------- */
> -
> -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
> -{
> -    struct XenDevice *xendev;
> -
> -    QTAILQ_FOREACH(xendev, &xendevs, next) {
> -        if (xendev->dom != dom) {
> -            continue;
> -        }
> -        if (xendev->dev != dev) {
> -            continue;
> -        }
> -        if (strcmp(xendev->type, type) != 0) {
> -            continue;
> -        }
> -        return xendev;
> -    }
> -    return NULL;
> -}
> -
> -/*
> - * get xen backend device, allocate a new one if it doesn't exist.
> - */
> -static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> -                                           struct XenDevOps *ops)
> -{
> -    struct XenDevice *xendev;
> -
> -    xendev = xen_be_find_xendev(type, dom, dev);
> -    if (xendev) {
> -        return xendev;
> -    }
> -
> -    /* init new xendev */
> -    xendev = g_malloc0(ops->size);
> -    xendev->type  = type;
> -    xendev->dom   = dom;
> -    xendev->dev   = dev;
> -    xendev->ops   = ops;
> -
> -    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> -             xendev->type, xendev->dom, xendev->dev);
> -    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> -             xendev->type, xendev->dev);
> -
> -    xendev->debug      = debug;
> -    xendev->local_port = -1;
> -
> -    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> -    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> -        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> -        g_free(xendev);
> -        return NULL;
> -    }
> -    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> -
> -    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> -        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> -        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> -            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> -            xc_evtchn_close(xendev->evtchndev);
> -            g_free(xendev);
> -            return NULL;
> -        }
> -    } else {
> -        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> -    }
> -
> -    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> -
> -    if (xendev->ops->alloc) {
> -        xendev->ops->alloc(xendev);
> -    }
> -
> -    return xendev;
> -}
> -
> -/*
> - * release xen backend device.
> - */
> -static struct XenDevice *xen_be_del_xendev(int dom, int dev)
> -{
> -    struct XenDevice *xendev, *xnext;
> -
> -    /*
> -     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
> -     * we save the next pointer in xnext because we might free xendev.
> -     */
> -    xnext = xendevs.tqh_first;
> -    while (xnext) {
> -        xendev = xnext;
> -        xnext = xendev->next.tqe_next;
> -
> -        if (xendev->dom != dom) {
> -            continue;
> -        }
> -        if (xendev->dev != dev && dev != -1) {
> -            continue;
> -        }
> -
> -        if (xendev->ops->free) {
> -            xendev->ops->free(xendev);
> -        }
> -
> -        if (xendev->fe) {
> -            char token[XEN_BUFSIZE];
> -            snprintf(token, sizeof(token), "fe:%p", xendev);
> -            xs_unwatch(xenstore, xendev->fe, token);
> -            g_free(xendev->fe);
> -        }
> -
> -        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> -            xc_evtchn_close(xendev->evtchndev);
> -        }
> -        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> -            xc_gnttab_close(xendev->gnttabdev);
> -        }
> -
> -        QTAILQ_REMOVE(&xendevs, xendev, next);
> -        g_free(xendev);
> -    }
> -    return NULL;
> -}
> -
> -/*
> - * Sync internal data structures on xenstore updates.
> - * Node specifies the changed field.  node = NULL means
> - * update all fields (used for initialization).
> - */
> -static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
> -{
> -    if (node == NULL  ||  strcmp(node, "online") == 0) {
> -        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
> -            xendev->online = 0;
> -        }
> -    }
> -
> -    if (node) {
> -        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> -        if (xendev->ops->backend_changed) {
> -            xendev->ops->backend_changed(xendev, node);
> -        }
> -    }
> -}
> -
> -static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
> -{
> -    int fe_state;
> -
> -    if (node == NULL  ||  strcmp(node, "state") == 0) {
> -        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> -            fe_state = XenbusStateUnknown;
> -        }
> -        if (xendev->fe_state != fe_state) {
> -            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> -                          xenbus_strstate(xendev->fe_state),
> -                          xenbus_strstate(fe_state));
> -        }
> -        xendev->fe_state = fe_state;
> -    }
> -    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> -        g_free(xendev->protocol);
> -        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> -        if (xendev->protocol) {
> -            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
> -        }
> -    }
> -
> -    if (node) {
> -        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> -        if (xendev->ops->frontend_changed) {
> -            xendev->ops->frontend_changed(xendev, node);
> -        }
> -    }
> -}
> -
> -/* ------------------------------------------------------------- */
>  /* Check for possible state transitions and perform them.        */
>  
>  /*
> @@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
>      return 0;
>  }
>  
> -static void xenstore_update_be(char *watch, char *type, int dom,
> -                               struct XenDevOps *ops)
> -{
> -    struct XenDevice *xendev;
> -    char path[XEN_BUFSIZE], *bepath;
> -    unsigned int len, dev;
> -
> -    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> -    if (strncmp(path, watch, len) != 0) {
> -        return;
> -    }
> -    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> -        strcpy(path, "");
> -        if (sscanf(watch+len, "/%u", &dev) != 1) {
> -            dev = -1;
> -        }
> -    }
> -    if (dev == -1) {
> -        return;
> -    }
> -
> -    xendev = xen_be_get_xendev(type, dom, dev, ops);
> -    if (xendev != NULL) {
> -        bepath = xs_read(xenstore, 0, xendev->be, &len);
> -        if (bepath == NULL) {
> -            xen_be_del_xendev(dom, dev);
> -        } else {
> -            free(bepath);
> -            xen_be_backend_changed(xendev, path);
> -            xen_be_check_state(xendev);
> -        }
> -    }
> -}
> -
> -static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> -{
> -    char *node;
> -    unsigned int len;
> -
> -    len = strlen(xendev->fe);
> -    if (strncmp(xendev->fe, watch, len) != 0) {
> -        return;
> -    }
> -    if (watch[len] != '/') {
> -        return;
> -    }
> -    node = watch + len + 1;
> -
> -    xen_be_frontend_changed(xendev, node);
> -    xen_be_check_state(xendev);
> -}
> -
> -static void xenstore_update(void *unused)
> -{
> -    char **vec = NULL;
> -    intptr_t type, ops, ptr;
> -    unsigned int dom, count;
> -
> -    vec = xs_read_watch(xenstore, &count);
> -    if (vec == NULL) {
> -        goto cleanup;
> -    }
> -
> -    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> -               &type, &dom, &ops) == 3) {
> -        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
> -    }
> -    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> -        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
> -    }
> -
> -cleanup:
> -    free(vec);
> -}
> -
>  static void xen_be_evtchn_event(void *opaque)
>  {
>      struct XenDevice *xendev = opaque;
> @@ -706,32 +379,6 @@ static void xen_be_evtchn_event(void *opaque)
>  
>  /* -------------------------------------------------------------------- */
>  
> -int xen_be_init(void)
> -{
> -    xenstore = xs_daemon_open();
> -    if (!xenstore) {
> -        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> -        return -1;
> -    }
> -
> -    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
> -        goto err;
> -    }
> -
> -    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> -        /* Check if xen_init() have been called */
> -        goto err;
> -    }
> -    return 0;
> -
> -err:
> -    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> -    xs_daemon_close(xenstore);
> -    xenstore = NULL;
> -
> -    return -1;
> -}
> -
>  int xen_be_register(const char *type, struct XenDevOps *ops)
>  {
>      return xenstore_scan(type, xen_domid, ops);
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
> new file mode 100644
> index 0000000..55af45a
> --- /dev/null
> +++ b/hw/xen/xen_frontend.c
> @@ -0,0 +1,345 @@
> +/*
> + * Xen frontend driver infrastructure
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +
> +#include "hw/hw.h"
> +#include "sysemu/char.h"
> +#include "qemu/log.h"
> +#include "hw/xen/xen_backend.h"
> +#include <xen/grant_table.h>
> +
> +int xenstore_dev;
> +
> +/* private */
> +static int debug;
> +
> +static void xen_fe_evtchn_event(void *opaque)
> +{
> +    struct XenDevice *xendev = opaque;
> +    evtchn_port_t port;
> +
> +    port = xc_evtchn_pending(xendev->evtchndev);
> +    if (port != xendev->local_port) {
> +        return;
> +    }
> +    xc_evtchn_unmask(xendev->evtchndev, port);
> +
> +    if (xendev->ops->event) {
> +        xendev->ops->event(xendev);
> +    }
> +}

This function is basically identical to xen_be_evtchn_event: could we
find a way to generalize it and have only one?


> +/* ------------------------------------------------------------- */
> +
> +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
> +{
> +    xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
> +                                                     remote_dom);
> +    if (xendev->local_port == -1) {
> +        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
> +        return -1;
> +    }
> +    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
> +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
> +                        xen_fe_evtchn_event, NULL, xendev);
> +    return 0;
> +}
> +
> +/*
> + * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
> + * xendev->ops->initialize()
> + */
> +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus)
> +{
> +    xs_transaction_t xbt = XBT_NULL;
> +
> +    if (xendev->fe_state == xbus) {
> +        return 0;
> +    }
> +
> +    xendev->fe_state = xbus;
> +    if (xendev->fe == NULL) {
> +        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
> +        return -1;
> +    }
> +
> +retry_transaction:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(xendev->fe, "state", xbus)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto retry_transaction;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}

This function could probably be unified with xen_be_set_state.


> +/*
> + * Simplify QEMU side, a thread is running in Xen backend, which will
> + * connect frontend when the frontend is initialised. Call these initialised
> + * functions.
> + */
> +static int xen_fe_try_init(void *opaque)
> +{
> +    struct XenDevOps *ops = opaque;
> +    int rc = -1;
> +
> +    if (ops->init) {
> +        rc = ops->init(NULL);
> +    }
> +
> +    return rc;
> +}
> +
> +static int xen_fe_try_initialise(struct XenDevice *xendev)
> +{
> +    int rc = 0, fe_state;
> +
> +    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> +        fe_state = XenbusStateUnknown;
> +    }
> +    xendev->fe_state = fe_state;
> +
> +    if (xendev->ops->initialise) {
> +        rc = xendev->ops->initialise(xendev);
> +    }
> +    if (rc != 0) {
> +        xen_fe_printf(xendev, 0, "initialise() failed\n");
> +        return rc;
> +    }
> +
> +    xenbus_switch_state(xendev, XenbusStateInitialised);
> +    return 0;
> +}
> +
> +static void xen_fe_try_connected(struct XenDevice *xendev)
> +{
> +    if (!xendev->ops->connected) {
> +        return;
> +    }
> +
> +    if (xendev->fe_state != XenbusStateConnected) {
> +        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
> +            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
> +        } else {
> +            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
> +            return;
> +        }
> +    }
> +
> +    xendev->ops->connected(xendev);
> +}
> +
> +static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
> +                        int handle)
> +{
> +    int rc = 0;
> +
> +    rc = xen_fe_try_initialise(xendev);
> +    if (rc != 0) {
> +        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
> +                      xendev->name);
> +        goto err;
> +    }
> +    xen_fe_try_connected(xendev);
> +
> +    return rc;
> +
> +err:
> +    xen_del_xendev(domid, handle);
> +    return -1;
> +}
> +
> +static char *xenstore_fe_get_backend(const char *type, int be_domid,
> +                                     uint32_t domid, int *hdl)
> +{
> +    char *name, *str, *ret = NULL;
> +    uint32_t i, cdev;
> +    int handle = 0;
> +    char path[XEN_BUFSIZE];
> +    char **dev = NULL;
> +
> +    name = xenstore_get_domain_name(domid);
> +    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
> +    dev = xs_directory(xenstore, 0, path, &cdev);
> +    for (i = 0; i < cdev; i++) {
> +        handle = i;
> +        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> +        type, be_domid, handle);
> +        str = xenstore_read_str(path, "domain");
> +        if (!strcmp(name, str)) {
> +            break;
> +        }
> +
> +        free(str);
> +
> +        /* Not the backend domain */
> +        if (handle == (cdev - 1)) {
> +            goto err;
> +        }
> +    }
> +
> +    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> +    type, be_domid, handle);
> +    str = xenstore_read_str(path, "backend");
> +    if (str != NULL) {
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +
> +    *hdl = handle;
> +    free(dev);
> +
> +    return ret;
> +err:
> +    *hdl = -1;
> +    free(dev);
> +    return NULL;
> +}
> +
> +static int xenstore_fe_scan(const char *type, uint32_t domid,
> +                            struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
> +    unsigned int cdev, j;
> +    char *backend;
> +    char **dev = NULL;
> +    int rc;
> +
> +    /* ops .init check, xendev is NOT initialized */
> +    rc = xen_fe_try_init(ops);
> +    if (rc != 0) {
> +        return -1;
> +    }
> +
> +    /* Get /local/domain/0/${type}/{} directory */
> +    snprintf(path, sizeof(path), "frontend/%s", type);
> +    dev = xs_directory(xenstore, 0, path, &cdev);
> +    if (dev == NULL) {
> +        return 0;
> +    }
> +
> +    for (j = 0; j < cdev; j++) {
> +
> +        /* Get backend via domain name */
> +        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
> +                                          domid, &xenstore_dev);
> +        if (backend == NULL) {
> +            continue;
> +        }
> +
> +        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend, ops);
> +        free(backend);
> +        if (xendev == NULL) {
> +            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
> +            continue;
> +        }
> +
> +        /*
> +         * Simplify QEMU side, a thread is running in Xen backend, which will
> +         * connect frontend when the frontend is initialised.
> +         */
> +        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
> +            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
> +            continue;
> +        }
> +
> +        /* Setup watch */
> +        snprintf(token, sizeof(token), "be:%p:%d:%p",
> +                 type, domid, xendev->ops);
> +        if (!xs_watch(xenstore, xendev->be, token)) {
> +            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
> +            continue;
> +        }
> +    }
> +
> +    free(dev);
> +    return 0;
> +}
> +
> +int xen_fe_register(const char *type, struct XenDevOps *ops)
> +{
> +    return xenstore_fe_scan(type, xen_domid, ops);
> +}
> +
> +/*
> + * msg_level:
> + *  0 == errors (stderr + logfile).
> + *  1 == informative debug messages (logfile only).
> + *  2 == noisy debug messages (logfile only).
> + *  3 == will flood your log (logfile only).
> + */
> +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> +                   const char *fmt, ...)
> +{
> +    va_list args;
> +
> +    if (xendev) {
> +        if (msg_level > xendev->debug) {
> +            return;
> +        }
> +        qemu_log("xen fe: %s: ", xendev->name);
> +        if (msg_level == 0) {
> +            fprintf(stderr, "xen fe: %s: ", xendev->name);
> +        }
> +    } else {
> +        if (msg_level > debug) {
> +            return;
> +        }
> +        qemu_log("xen fe core: ");
> +        if (msg_level == 0) {
> +            fprintf(stderr, "xen fe core: ");
> +        }
> +    }
> +    va_start(args, fmt);
> +    qemu_log_vprintf(fmt, args);
> +    va_end(args);
> +    if (msg_level == 0) {
> +        va_start(args, fmt);
> +        vfprintf(stderr, fmt, args);
> +        va_end(args);
> +    }
> +    qemu_log_flush();

There is no need to introduce another one of these. Just rename
xen_be_printf to xen_pv_printf and move it it xen_pvdev.c.

In general we should try to share as many functions as possible between
the frontend and the backend code. To do that we need to modify the
existing backend functions, such as xen_be_printf, generalize them so
that they can also be used by frontends (in this case renaming
xen_be_printf to xen_pv_printf should be enough), and move them to
xen_pvdev.c.


> diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
> new file mode 100644
> index 0000000..dac8639
> --- /dev/null
> +++ b/hw/xen/xen_pvdev.c
> @@ -0,0 +1,481 @@
> +/*
> + * Xen para-virtualization device
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +
> +#include "hw/hw.h"
> +#include "sysemu/char.h"
> +#include "qemu/log.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#include <xen/grant_table.h>
> +
> +static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> +           QTAILQ_HEAD_INITIALIZER(xendevs);
> +static int debug;
> +
> +/* public */
> +XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> +struct xs_handle *xenstore;
> +
> +/*
> + * find Xen device
> + */
> +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
> +{
> +    struct XenDevice *xendev;
> +
> +    QTAILQ_FOREACH(xendev, &xendevs, next) {
> +        if (xendev->dom != dom) {
> +            continue;
> +        }
> +        if (xendev->dev != dev) {
> +            continue;
> +        }
> +        if (strcmp(xendev->type, type) != 0) {
> +            continue;
> +        }
> +        return xendev;
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * get xen backend device, allocate a new one if it doesn't exist.
> + */
> +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> +                                    struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +
> +    xendev = xen_find_xendev(type, dom, dev);
> +    if (xendev) {
> +        return xendev;
> +    }
> +
> +    /* init new xendev */
> +    xendev = g_malloc0(ops->size);
> +    xendev->type  = type;
> +    xendev->dom   = dom;
> +    xendev->dev   = dev;
> +    xendev->ops   = ops;
> +
> +    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> +             xendev->type, xendev->dom, xendev->dev);
> +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> +             xendev->type, xendev->dev);
> +
> +    xendev->debug      = debug;
> +    xendev->local_port = -1;
> +
> +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> +        g_free(xendev);
> +        return NULL;
> +    }
> +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> +
> +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> +            xc_evtchn_close(xendev->evtchndev);
> +            g_free(xendev);
> +            return NULL;
> +        }
> +    } else {
> +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> +    }
> +
> +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> +
> +    if (xendev->ops->alloc) {
> +        xendev->ops->alloc(xendev);
> +    }
> +
> +    return xendev;
> +}

Only functions that are shared between frontends and backends should be
here, like xen_find_xendev. Otherwise there is no benefit in moving them
to a separete, shared, source file.


> +/*
> + * get xen fe device, allocate a new one if it doesn't exist.
> + */
> +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> +                                    char *backend, struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +
> +    xendev = xen_find_xendev(type, dom, dev);
> +    if (xendev) {
> +        return xendev;
> +    }
> +
> +    /* init new xendev */
> +    xendev = g_malloc0(ops->size);
> +    xendev->type  = type;
> +    xendev->dom   = dom;
> +    xendev->dev   = dev;
> +    xendev->ops   = ops;
> +
> +    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
> +    if (!(ops->flags & DEVOPS_FLAG_FE)) {
> +        return NULL;
> +    }
> +
> +    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
> +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> +             xendev->type, xendev->dev);
> +
> +    xendev->debug = debug;
> +    xendev->local_port = -1;
> +
> +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> +        g_free(xendev);
> +        return NULL;
> +    }
> +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> +
> +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> +            xc_evtchn_close(xendev->evtchndev);
> +            g_free(xendev);
> +            return NULL;
> +        }
> +    } else {
> +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> +    }
> +
> +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> +
> +    if (xendev->ops->alloc) {
> +        xendev->ops->alloc(xendev);
> +    }
> +
> +    return xendev;
> +}

same here


> +/*
> + * release xen device
> + */
> +
> +struct XenDevice *xen_del_xendev(int dom, int dev)
> +{
> +    struct XenDevice *xendev, *xnext;
> +
> +    /*
> +     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
> +     * we save the next pointer in xnext because we might free xendev.
> +     */
> +    xnext = xendevs.tqh_first;
> +    while (xnext) {
> +        xendev = xnext;
> +        xnext = xendev->next.tqe_next;
> +
> +        if (xendev->dom != dom) {
> +            continue;
> +        }
> +        if (xendev->dev != dev && dev != -1) {
> +            continue;
> +        }
> +
> +        if (xendev->ops->free) {
> +            xendev->ops->free(xendev);
> +        }
> +
> +        if (xendev->fe) {
> +            char token[XEN_BUFSIZE];
> +            snprintf(token, sizeof(token), "fe:%p", xendev);
> +            xs_unwatch(xenstore, xendev->fe, token);
> +            g_free(xendev->fe);
> +        }
> +
> +        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> +            xc_evtchn_close(xendev->evtchndev);
> +        }
> +        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> +            xc_gnttab_close(xendev->gnttabdev);
> +        }
> +
> +        QTAILQ_REMOVE(&xendevs, xendev, next);
> +        g_free(xendev);
> +    }
> +    return NULL;
> +}
> +
> +/* ------------------------------------------------------------- */
> +
> +int xenstore_write_str(const char *base, const char *node, const char *val)
> +{
> +    char abspath[XEN_BUFSIZE];
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +char *xenstore_read_str(const char *base, const char *node)
> +{
> +    char abspath[XEN_BUFSIZE];
> +    unsigned int len;
> +    char *str, *ret = NULL;
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    str = xs_read(xenstore, 0, abspath, &len);
> +    if (str != NULL) {
> +        /* move to qemu-allocated memory to make sure
> +         * callers can savely g_free() stuff. */
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +    return ret;
> +}
> +
> +int xenstore_write_int(const char *base, const char *node, int ival)
> +{
> +    char val[12];
> +
> +    snprintf(val, sizeof(val), "%d", ival);
> +    return xenstore_write_str(base, node, val);
> +}
> +
> +int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> +{
> +    char val[21];
> +
> +    snprintf(val, sizeof(val), "%"PRId64, ival);
> +    return xenstore_write_str(base, node, val);
> +}
> +
> +int xenstore_read_int(const char *base, const char *node, int *ival)
> +{
> +    char *val;
> +    int rc = -1;
> +
> +    val = xenstore_read_str(base, node);
> +    if (val && 1 == sscanf(val, "%d", ival)) {
> +        rc = 0;
> +    }
> +    g_free(val);
> +    return rc;
> +}
> +
> +int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> +{
> +    char *val;
> +    int rc = -1;
> +
> +    val = xenstore_read_str(base, node);
> +    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> +        rc = 0;
> +    }
> +    g_free(val);
> +    return rc;
> +}
> +
> +char *xenstore_get_domain_name(uint32_t domid)
> +{
> +    char *dom_path, *str, *ret = NULL;;
> +
> +    dom_path = xs_get_domain_path(xenstore, domid);
> +    str = xenstore_read_str(dom_path, "name");
> +    free(dom_path);
> +    if (str != NULL) {
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * Sync internal data structures on xenstore updates.
> + * Node specifies the changed field.  node = NULL means
> + * update all fields (used for initialization).
> + */
> +void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    if (node == NULL  ||  strcmp(node, "online") == 0) {
> +        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
> +            xendev->online = 0;
> +        }
> +    }
> +
> +    if (node) {
> +        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> +        if (xendev->ops->backend_changed) {
> +            xendev->ops->backend_changed(xendev, node);
> +        }
> +    }
> +}
> +
> +void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    int fe_state;
> +
> +    if (node == NULL  ||  strcmp(node, "state") == 0) {
> +        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> +            fe_state = XenbusStateUnknown;
> +        }
> +        if (xendev->fe_state != fe_state) {
> +            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> +                          xenbus_strstate(xendev->fe_state),
> +                          xenbus_strstate(fe_state));
> +        }
> +        xendev->fe_state = fe_state;
> +    }
> +    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> +        g_free(xendev->protocol);
> +        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> +        if (xendev->protocol) {
> +            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> +                          xendev->protocol);
> +        }
> +    }
> +
> +    if (node) {
> +        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> +        if (xendev->ops->frontend_changed) {
> +            xendev->ops->frontend_changed(xendev, node);
> +        }
> +    }
> +}

Anything backend or frontend specific, like these two functions, should either:
    
1) be made generic, shared between frontends and backends, moved to this file
2) left in the corresponding xen_backend.c or xen_frontend.c source file

The first option is better, when possible.


> +static void xenstore_update_be(char *watch, char *type, int dom,
> +                        struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +    char path[XEN_BUFSIZE], *bepath;
> +    unsigned int len, dev;
> +
> +    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> +
> +    if (strstr(watch, path) == NULL) {
> +        return;
> +    }
> +    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> +        strcpy(path, "");
> +        if (sscanf(watch+len, "/%u", &dev) != 1) {
> +            dev = -1;
> +        }
> +    }
> +    if (dev == -1) {
> +        return;
> +    }
> +
> +    xendev = xen_be_get_xendev(type, dom, dev, ops);
> +    if (xendev != NULL) {
> +        bepath = xs_read(xenstore, 0, xendev->be, &len);
> +        if (bepath == NULL) {
> +            xen_del_xendev(dom, dev);
> +        } else {
> +            free(bepath);
> +            xen_be_backend_changed(xendev, path);
> +            if (!(ops->flags & DEVOPS_FLAG_FE)) {
> +                xen_be_check_state(xendev);
> +            }
> +        }
> +    }
> +}
> +
> +static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> +{
> +    char *node;
> +    unsigned int len;
> +
> +    len = strlen(xendev->fe);
> +    if (strncmp(xendev->fe, watch, len) != 0) {
> +        return;
> +    }
> +    if (watch[len] != '/') {
> +        return;
> +    }
> +    node = watch + len + 1;
> +
> +    xen_be_frontend_changed(xendev, node);
> +    xen_be_check_state(xendev);
> +}
> +
> +static void xenstore_update(void *unused)
> +{
> +    char **vec = NULL;
> +    intptr_t type, ops, ptr;
> +    unsigned int dom, count;
> +
> +    vec = xs_read_watch(xenstore, &count);
> +    if (vec == NULL) {
> +        goto cleanup;
> +    }
> +
> +    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> +               &type, &dom, &ops) == 3) {
> +        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void *)ops);
> +    }
> +    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> +        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
> +    }
> +
> +cleanup:
> +    free(vec);
> +}
> +
> +int xen_be_init(void)
> +{
> +    xenstore = xs_daemon_open();
> +    if (!xenstore) {
> +        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> +        return -1;
> +    }
> +
> +    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
> +        NULL, NULL) < 0) {
> +        goto err;
> +    }
> +
> +    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> +
> +        /* Check if xen_init() have been called */
> +        goto err;
> +    }
> +    return 0;
> +
> +err:
> +    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> +    xs_daemon_close(xenstore);
> +    xenstore = NULL;
> +
> +    return -1;
> +}
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index 3b4125e..bb0b303 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -15,6 +15,8 @@ struct XenDevice;
>  #define DEVOPS_FLAG_NEED_GNTDEV   1
>  /* don't expect frontend doing correct state transitions (aka console quirk) */
>  #define DEVOPS_FLAG_IGNORE_STATE  2
> +/*dev is frontend device*/
> +#define DEVOPS_FLAG_FE            4
>  
>  struct XenDevOps {
>      size_t    size;
> @@ -59,6 +61,7 @@ struct XenDevice {
>  extern XenXC xen_xc;
>  extern struct xs_handle *xenstore;
>  extern const char *xen_protocol;
> +extern int xenstore_dev;
>  
>  /* xenstore helper functions */
>  int xenstore_write_str(const char *base, const char *node, const char *val);
> @@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
>  int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval);
>  int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval);
>  
> +char *xenstore_get_domain_name(uint32_t domid);
> +
>  const char *xenbus_strstate(enum xenbus_state state);
> -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
> +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
> +struct XenDevice *xen_del_xendev(int dom, int dev);
> +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> +                                    struct XenDevOps *ops);
> +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> +                                    char *backend, struct XenDevOps *ops);
>  void xen_be_check_state(struct XenDevice *xendev);
> +void xen_be_backend_changed(struct XenDevice *xendev, const char *node);
> +void xen_be_frontend_changed(struct XenDevice *xendev, const char *node);
>  
>  /* xen backend driver bits */
>  int xen_be_init(void);
> @@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice *xendev);
>  int xen_be_send_notify(struct XenDevice *xendev);
>  void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
>      GCC_FMT_ATTR(3, 4);
> +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> +                   const char *fmt, ...)
> +    GCC_FMT_ATTR(3, 4);
> +/* Xen frontend driver */
> +int xen_fe_register(const char *type, struct XenDevOps *ops);
> +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
> +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
>  
>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
> @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
>  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
>  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> +extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/
>  
>  void xen_init_display(int domid);
>  
> -- 
> 1.8.3.2
> 

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

* Re: [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
  (?)
@ 2015-05-07 17:25   ` Stefano Stabellini
  -1 siblings, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-07 17:25 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel,
	dgdegra, eblake

On Mon, 4 May 2015, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
> XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> the XenDevOps is Xen frontend.
> 
> Create a new file xen_pvdev.c for some common part of xen frontend
> and backend, such as xendevs queue and xenstore update functions.
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>

Better than the early versions, thanks.

However the patch is too big and it is too difficult to read as is.
Could you please split it in two: a patch that creates xen_pvdev.c and
moves a few functions from xen_backend.c to it and a second patch that
introduces xen_frontend.c.


>  hw/display/xenfb.c           |   4 +-
>  hw/xen/Makefile.objs         |   2 +-
>  hw/xen/xen_backend.c         | 353 -------------------------------
>  hw/xen/xen_frontend.c        | 345 +++++++++++++++++++++++++++++++
>  hw/xen/xen_pvdev.c           | 481 +++++++++++++++++++++++++++++++++++++++++++
>  include/hw/xen/xen_backend.h |  22 +-
>  6 files changed, 850 insertions(+), 357 deletions(-)
>  create mode 100644 hw/xen/xen_frontend.c
>  create mode 100644 hw/xen/xen_pvdev.c
> 
> diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
> index 5e324ef..10751df 100644
> --- a/hw/display/xenfb.c
> +++ b/hw/display/xenfb.c
> @@ -988,8 +988,8 @@ void xen_init_display(int domid)
>  wait_more:
>      i++;
>      main_loop_wait(true);
> -    xfb = xen_be_find_xendev("vfb", domid, 0);
> -    xin = xen_be_find_xendev("vkbd", domid, 0);
> +    xfb = xen_find_xendev("vfb", domid, 0);
> +    xin = xen_find_xendev("vkbd", domid, 0);
>      if (!xfb || !xin) {
>          if (i < 256) {
>              usleep(10000);
> diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
> index a0ca0aa..95eb9d0 100644
> --- a/hw/xen/Makefile.objs
> +++ b/hw/xen/Makefile.objs
> @@ -1,5 +1,5 @@
>  # xen backend driver support
> -common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o xen_frontend.o xen_pvdev.o
>  
>  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
>  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
> diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
> index b2cb22b..844f918 100644
> --- a/hw/xen/xen_backend.c
> +++ b/hw/xen/xen_backend.c
> @@ -44,86 +44,11 @@
>  /* ------------------------------------------------------------- */
>  
>  /* public */
> -XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> -struct xs_handle *xenstore = NULL;
>  const char *xen_protocol;
>  
>  /* private */
> -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
>  static int debug = 0;
>  
> -/* ------------------------------------------------------------- */
> -
> -int xenstore_write_str(const char *base, const char *node, const char *val)
> -{
> -    char abspath[XEN_BUFSIZE];
> -
> -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> -    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> -        return -1;
> -    }
> -    return 0;
> -}
> -
> -char *xenstore_read_str(const char *base, const char *node)
> -{
> -    char abspath[XEN_BUFSIZE];
> -    unsigned int len;
> -    char *str, *ret = NULL;
> -
> -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> -    str = xs_read(xenstore, 0, abspath, &len);
> -    if (str != NULL) {
> -        /* move to qemu-allocated memory to make sure
> -         * callers can savely g_free() stuff. */
> -        ret = g_strdup(str);
> -        free(str);
> -    }
> -    return ret;
> -}
> -
> -int xenstore_write_int(const char *base, const char *node, int ival)
> -{
> -    char val[12];
> -
> -    snprintf(val, sizeof(val), "%d", ival);
> -    return xenstore_write_str(base, node, val);
> -}
> -
> -int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> -{
> -    char val[21];
> -
> -    snprintf(val, sizeof(val), "%"PRId64, ival);
> -    return xenstore_write_str(base, node, val);
> -}
> -
> -int xenstore_read_int(const char *base, const char *node, int *ival)
> -{
> -    char *val;
> -    int rc = -1;
> -
> -    val = xenstore_read_str(base, node);
> -    if (val && 1 == sscanf(val, "%d", ival)) {
> -        rc = 0;
> -    }
> -    g_free(val);
> -    return rc;
> -}
> -
> -int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> -{
> -    char *val;
> -    int rc = -1;
> -
> -    val = xenstore_read_str(base, node);
> -    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> -        rc = 0;
> -    }
> -    g_free(val);
> -    return rc;
> -}
> -
>  int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
>  {
>      return xenstore_write_str(xendev->be, node, val);
> @@ -195,183 +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
>  }
>  
>  /* ------------------------------------------------------------- */
> -
> -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
> -{
> -    struct XenDevice *xendev;
> -
> -    QTAILQ_FOREACH(xendev, &xendevs, next) {
> -        if (xendev->dom != dom) {
> -            continue;
> -        }
> -        if (xendev->dev != dev) {
> -            continue;
> -        }
> -        if (strcmp(xendev->type, type) != 0) {
> -            continue;
> -        }
> -        return xendev;
> -    }
> -    return NULL;
> -}
> -
> -/*
> - * get xen backend device, allocate a new one if it doesn't exist.
> - */
> -static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> -                                           struct XenDevOps *ops)
> -{
> -    struct XenDevice *xendev;
> -
> -    xendev = xen_be_find_xendev(type, dom, dev);
> -    if (xendev) {
> -        return xendev;
> -    }
> -
> -    /* init new xendev */
> -    xendev = g_malloc0(ops->size);
> -    xendev->type  = type;
> -    xendev->dom   = dom;
> -    xendev->dev   = dev;
> -    xendev->ops   = ops;
> -
> -    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> -             xendev->type, xendev->dom, xendev->dev);
> -    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> -             xendev->type, xendev->dev);
> -
> -    xendev->debug      = debug;
> -    xendev->local_port = -1;
> -
> -    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> -    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> -        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> -        g_free(xendev);
> -        return NULL;
> -    }
> -    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> -
> -    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> -        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> -        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> -            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> -            xc_evtchn_close(xendev->evtchndev);
> -            g_free(xendev);
> -            return NULL;
> -        }
> -    } else {
> -        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> -    }
> -
> -    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> -
> -    if (xendev->ops->alloc) {
> -        xendev->ops->alloc(xendev);
> -    }
> -
> -    return xendev;
> -}
> -
> -/*
> - * release xen backend device.
> - */
> -static struct XenDevice *xen_be_del_xendev(int dom, int dev)
> -{
> -    struct XenDevice *xendev, *xnext;
> -
> -    /*
> -     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
> -     * we save the next pointer in xnext because we might free xendev.
> -     */
> -    xnext = xendevs.tqh_first;
> -    while (xnext) {
> -        xendev = xnext;
> -        xnext = xendev->next.tqe_next;
> -
> -        if (xendev->dom != dom) {
> -            continue;
> -        }
> -        if (xendev->dev != dev && dev != -1) {
> -            continue;
> -        }
> -
> -        if (xendev->ops->free) {
> -            xendev->ops->free(xendev);
> -        }
> -
> -        if (xendev->fe) {
> -            char token[XEN_BUFSIZE];
> -            snprintf(token, sizeof(token), "fe:%p", xendev);
> -            xs_unwatch(xenstore, xendev->fe, token);
> -            g_free(xendev->fe);
> -        }
> -
> -        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> -            xc_evtchn_close(xendev->evtchndev);
> -        }
> -        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> -            xc_gnttab_close(xendev->gnttabdev);
> -        }
> -
> -        QTAILQ_REMOVE(&xendevs, xendev, next);
> -        g_free(xendev);
> -    }
> -    return NULL;
> -}
> -
> -/*
> - * Sync internal data structures on xenstore updates.
> - * Node specifies the changed field.  node = NULL means
> - * update all fields (used for initialization).
> - */
> -static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
> -{
> -    if (node == NULL  ||  strcmp(node, "online") == 0) {
> -        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
> -            xendev->online = 0;
> -        }
> -    }
> -
> -    if (node) {
> -        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> -        if (xendev->ops->backend_changed) {
> -            xendev->ops->backend_changed(xendev, node);
> -        }
> -    }
> -}
> -
> -static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
> -{
> -    int fe_state;
> -
> -    if (node == NULL  ||  strcmp(node, "state") == 0) {
> -        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> -            fe_state = XenbusStateUnknown;
> -        }
> -        if (xendev->fe_state != fe_state) {
> -            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> -                          xenbus_strstate(xendev->fe_state),
> -                          xenbus_strstate(fe_state));
> -        }
> -        xendev->fe_state = fe_state;
> -    }
> -    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> -        g_free(xendev->protocol);
> -        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> -        if (xendev->protocol) {
> -            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
> -        }
> -    }
> -
> -    if (node) {
> -        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> -        if (xendev->ops->frontend_changed) {
> -            xendev->ops->frontend_changed(xendev, node);
> -        }
> -    }
> -}
> -
> -/* ------------------------------------------------------------- */
>  /* Check for possible state transitions and perform them.        */
>  
>  /*
> @@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
>      return 0;
>  }
>  
> -static void xenstore_update_be(char *watch, char *type, int dom,
> -                               struct XenDevOps *ops)
> -{
> -    struct XenDevice *xendev;
> -    char path[XEN_BUFSIZE], *bepath;
> -    unsigned int len, dev;
> -
> -    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> -    if (strncmp(path, watch, len) != 0) {
> -        return;
> -    }
> -    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> -        strcpy(path, "");
> -        if (sscanf(watch+len, "/%u", &dev) != 1) {
> -            dev = -1;
> -        }
> -    }
> -    if (dev == -1) {
> -        return;
> -    }
> -
> -    xendev = xen_be_get_xendev(type, dom, dev, ops);
> -    if (xendev != NULL) {
> -        bepath = xs_read(xenstore, 0, xendev->be, &len);
> -        if (bepath == NULL) {
> -            xen_be_del_xendev(dom, dev);
> -        } else {
> -            free(bepath);
> -            xen_be_backend_changed(xendev, path);
> -            xen_be_check_state(xendev);
> -        }
> -    }
> -}
> -
> -static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> -{
> -    char *node;
> -    unsigned int len;
> -
> -    len = strlen(xendev->fe);
> -    if (strncmp(xendev->fe, watch, len) != 0) {
> -        return;
> -    }
> -    if (watch[len] != '/') {
> -        return;
> -    }
> -    node = watch + len + 1;
> -
> -    xen_be_frontend_changed(xendev, node);
> -    xen_be_check_state(xendev);
> -}
> -
> -static void xenstore_update(void *unused)
> -{
> -    char **vec = NULL;
> -    intptr_t type, ops, ptr;
> -    unsigned int dom, count;
> -
> -    vec = xs_read_watch(xenstore, &count);
> -    if (vec == NULL) {
> -        goto cleanup;
> -    }
> -
> -    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> -               &type, &dom, &ops) == 3) {
> -        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
> -    }
> -    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> -        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
> -    }
> -
> -cleanup:
> -    free(vec);
> -}
> -
>  static void xen_be_evtchn_event(void *opaque)
>  {
>      struct XenDevice *xendev = opaque;
> @@ -706,32 +379,6 @@ static void xen_be_evtchn_event(void *opaque)
>  
>  /* -------------------------------------------------------------------- */
>  
> -int xen_be_init(void)
> -{
> -    xenstore = xs_daemon_open();
> -    if (!xenstore) {
> -        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> -        return -1;
> -    }
> -
> -    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
> -        goto err;
> -    }
> -
> -    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> -        /* Check if xen_init() have been called */
> -        goto err;
> -    }
> -    return 0;
> -
> -err:
> -    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> -    xs_daemon_close(xenstore);
> -    xenstore = NULL;
> -
> -    return -1;
> -}
> -
>  int xen_be_register(const char *type, struct XenDevOps *ops)
>  {
>      return xenstore_scan(type, xen_domid, ops);
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
> new file mode 100644
> index 0000000..55af45a
> --- /dev/null
> +++ b/hw/xen/xen_frontend.c
> @@ -0,0 +1,345 @@
> +/*
> + * Xen frontend driver infrastructure
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +
> +#include "hw/hw.h"
> +#include "sysemu/char.h"
> +#include "qemu/log.h"
> +#include "hw/xen/xen_backend.h"
> +#include <xen/grant_table.h>
> +
> +int xenstore_dev;
> +
> +/* private */
> +static int debug;
> +
> +static void xen_fe_evtchn_event(void *opaque)
> +{
> +    struct XenDevice *xendev = opaque;
> +    evtchn_port_t port;
> +
> +    port = xc_evtchn_pending(xendev->evtchndev);
> +    if (port != xendev->local_port) {
> +        return;
> +    }
> +    xc_evtchn_unmask(xendev->evtchndev, port);
> +
> +    if (xendev->ops->event) {
> +        xendev->ops->event(xendev);
> +    }
> +}

This function is basically identical to xen_be_evtchn_event: could we
find a way to generalize it and have only one?


> +/* ------------------------------------------------------------- */
> +
> +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
> +{
> +    xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
> +                                                     remote_dom);
> +    if (xendev->local_port == -1) {
> +        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
> +        return -1;
> +    }
> +    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
> +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
> +                        xen_fe_evtchn_event, NULL, xendev);
> +    return 0;
> +}
> +
> +/*
> + * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
> + * xendev->ops->initialize()
> + */
> +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus)
> +{
> +    xs_transaction_t xbt = XBT_NULL;
> +
> +    if (xendev->fe_state == xbus) {
> +        return 0;
> +    }
> +
> +    xendev->fe_state = xbus;
> +    if (xendev->fe == NULL) {
> +        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
> +        return -1;
> +    }
> +
> +retry_transaction:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(xendev->fe, "state", xbus)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto retry_transaction;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}

This function could probably be unified with xen_be_set_state.


> +/*
> + * Simplify QEMU side, a thread is running in Xen backend, which will
> + * connect frontend when the frontend is initialised. Call these initialised
> + * functions.
> + */
> +static int xen_fe_try_init(void *opaque)
> +{
> +    struct XenDevOps *ops = opaque;
> +    int rc = -1;
> +
> +    if (ops->init) {
> +        rc = ops->init(NULL);
> +    }
> +
> +    return rc;
> +}
> +
> +static int xen_fe_try_initialise(struct XenDevice *xendev)
> +{
> +    int rc = 0, fe_state;
> +
> +    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> +        fe_state = XenbusStateUnknown;
> +    }
> +    xendev->fe_state = fe_state;
> +
> +    if (xendev->ops->initialise) {
> +        rc = xendev->ops->initialise(xendev);
> +    }
> +    if (rc != 0) {
> +        xen_fe_printf(xendev, 0, "initialise() failed\n");
> +        return rc;
> +    }
> +
> +    xenbus_switch_state(xendev, XenbusStateInitialised);
> +    return 0;
> +}
> +
> +static void xen_fe_try_connected(struct XenDevice *xendev)
> +{
> +    if (!xendev->ops->connected) {
> +        return;
> +    }
> +
> +    if (xendev->fe_state != XenbusStateConnected) {
> +        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
> +            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
> +        } else {
> +            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
> +            return;
> +        }
> +    }
> +
> +    xendev->ops->connected(xendev);
> +}
> +
> +static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
> +                        int handle)
> +{
> +    int rc = 0;
> +
> +    rc = xen_fe_try_initialise(xendev);
> +    if (rc != 0) {
> +        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
> +                      xendev->name);
> +        goto err;
> +    }
> +    xen_fe_try_connected(xendev);
> +
> +    return rc;
> +
> +err:
> +    xen_del_xendev(domid, handle);
> +    return -1;
> +}
> +
> +static char *xenstore_fe_get_backend(const char *type, int be_domid,
> +                                     uint32_t domid, int *hdl)
> +{
> +    char *name, *str, *ret = NULL;
> +    uint32_t i, cdev;
> +    int handle = 0;
> +    char path[XEN_BUFSIZE];
> +    char **dev = NULL;
> +
> +    name = xenstore_get_domain_name(domid);
> +    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
> +    dev = xs_directory(xenstore, 0, path, &cdev);
> +    for (i = 0; i < cdev; i++) {
> +        handle = i;
> +        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> +        type, be_domid, handle);
> +        str = xenstore_read_str(path, "domain");
> +        if (!strcmp(name, str)) {
> +            break;
> +        }
> +
> +        free(str);
> +
> +        /* Not the backend domain */
> +        if (handle == (cdev - 1)) {
> +            goto err;
> +        }
> +    }
> +
> +    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> +    type, be_domid, handle);
> +    str = xenstore_read_str(path, "backend");
> +    if (str != NULL) {
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +
> +    *hdl = handle;
> +    free(dev);
> +
> +    return ret;
> +err:
> +    *hdl = -1;
> +    free(dev);
> +    return NULL;
> +}
> +
> +static int xenstore_fe_scan(const char *type, uint32_t domid,
> +                            struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
> +    unsigned int cdev, j;
> +    char *backend;
> +    char **dev = NULL;
> +    int rc;
> +
> +    /* ops .init check, xendev is NOT initialized */
> +    rc = xen_fe_try_init(ops);
> +    if (rc != 0) {
> +        return -1;
> +    }
> +
> +    /* Get /local/domain/0/${type}/{} directory */
> +    snprintf(path, sizeof(path), "frontend/%s", type);
> +    dev = xs_directory(xenstore, 0, path, &cdev);
> +    if (dev == NULL) {
> +        return 0;
> +    }
> +
> +    for (j = 0; j < cdev; j++) {
> +
> +        /* Get backend via domain name */
> +        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
> +                                          domid, &xenstore_dev);
> +        if (backend == NULL) {
> +            continue;
> +        }
> +
> +        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend, ops);
> +        free(backend);
> +        if (xendev == NULL) {
> +            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
> +            continue;
> +        }
> +
> +        /*
> +         * Simplify QEMU side, a thread is running in Xen backend, which will
> +         * connect frontend when the frontend is initialised.
> +         */
> +        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
> +            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
> +            continue;
> +        }
> +
> +        /* Setup watch */
> +        snprintf(token, sizeof(token), "be:%p:%d:%p",
> +                 type, domid, xendev->ops);
> +        if (!xs_watch(xenstore, xendev->be, token)) {
> +            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
> +            continue;
> +        }
> +    }
> +
> +    free(dev);
> +    return 0;
> +}
> +
> +int xen_fe_register(const char *type, struct XenDevOps *ops)
> +{
> +    return xenstore_fe_scan(type, xen_domid, ops);
> +}
> +
> +/*
> + * msg_level:
> + *  0 == errors (stderr + logfile).
> + *  1 == informative debug messages (logfile only).
> + *  2 == noisy debug messages (logfile only).
> + *  3 == will flood your log (logfile only).
> + */
> +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> +                   const char *fmt, ...)
> +{
> +    va_list args;
> +
> +    if (xendev) {
> +        if (msg_level > xendev->debug) {
> +            return;
> +        }
> +        qemu_log("xen fe: %s: ", xendev->name);
> +        if (msg_level == 0) {
> +            fprintf(stderr, "xen fe: %s: ", xendev->name);
> +        }
> +    } else {
> +        if (msg_level > debug) {
> +            return;
> +        }
> +        qemu_log("xen fe core: ");
> +        if (msg_level == 0) {
> +            fprintf(stderr, "xen fe core: ");
> +        }
> +    }
> +    va_start(args, fmt);
> +    qemu_log_vprintf(fmt, args);
> +    va_end(args);
> +    if (msg_level == 0) {
> +        va_start(args, fmt);
> +        vfprintf(stderr, fmt, args);
> +        va_end(args);
> +    }
> +    qemu_log_flush();

There is no need to introduce another one of these. Just rename
xen_be_printf to xen_pv_printf and move it it xen_pvdev.c.

In general we should try to share as many functions as possible between
the frontend and the backend code. To do that we need to modify the
existing backend functions, such as xen_be_printf, generalize them so
that they can also be used by frontends (in this case renaming
xen_be_printf to xen_pv_printf should be enough), and move them to
xen_pvdev.c.


> diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
> new file mode 100644
> index 0000000..dac8639
> --- /dev/null
> +++ b/hw/xen/xen_pvdev.c
> @@ -0,0 +1,481 @@
> +/*
> + * Xen para-virtualization device
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/signal.h>
> +
> +#include "hw/hw.h"
> +#include "sysemu/char.h"
> +#include "qemu/log.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#include <xen/grant_table.h>
> +
> +static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> +           QTAILQ_HEAD_INITIALIZER(xendevs);
> +static int debug;
> +
> +/* public */
> +XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> +struct xs_handle *xenstore;
> +
> +/*
> + * find Xen device
> + */
> +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
> +{
> +    struct XenDevice *xendev;
> +
> +    QTAILQ_FOREACH(xendev, &xendevs, next) {
> +        if (xendev->dom != dom) {
> +            continue;
> +        }
> +        if (xendev->dev != dev) {
> +            continue;
> +        }
> +        if (strcmp(xendev->type, type) != 0) {
> +            continue;
> +        }
> +        return xendev;
> +    }
> +    return NULL;
> +}
> +
> +/*
> + * get xen backend device, allocate a new one if it doesn't exist.
> + */
> +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> +                                    struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +
> +    xendev = xen_find_xendev(type, dom, dev);
> +    if (xendev) {
> +        return xendev;
> +    }
> +
> +    /* init new xendev */
> +    xendev = g_malloc0(ops->size);
> +    xendev->type  = type;
> +    xendev->dom   = dom;
> +    xendev->dev   = dev;
> +    xendev->ops   = ops;
> +
> +    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> +             xendev->type, xendev->dom, xendev->dev);
> +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> +             xendev->type, xendev->dev);
> +
> +    xendev->debug      = debug;
> +    xendev->local_port = -1;
> +
> +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> +        g_free(xendev);
> +        return NULL;
> +    }
> +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> +
> +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> +            xc_evtchn_close(xendev->evtchndev);
> +            g_free(xendev);
> +            return NULL;
> +        }
> +    } else {
> +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> +    }
> +
> +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> +
> +    if (xendev->ops->alloc) {
> +        xendev->ops->alloc(xendev);
> +    }
> +
> +    return xendev;
> +}

Only functions that are shared between frontends and backends should be
here, like xen_find_xendev. Otherwise there is no benefit in moving them
to a separete, shared, source file.


> +/*
> + * get xen fe device, allocate a new one if it doesn't exist.
> + */
> +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> +                                    char *backend, struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +
> +    xendev = xen_find_xendev(type, dom, dev);
> +    if (xendev) {
> +        return xendev;
> +    }
> +
> +    /* init new xendev */
> +    xendev = g_malloc0(ops->size);
> +    xendev->type  = type;
> +    xendev->dom   = dom;
> +    xendev->dev   = dev;
> +    xendev->ops   = ops;
> +
> +    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
> +    if (!(ops->flags & DEVOPS_FLAG_FE)) {
> +        return NULL;
> +    }
> +
> +    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
> +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> +             xendev->type, xendev->dev);
> +
> +    xendev->debug = debug;
> +    xendev->local_port = -1;
> +
> +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> +        g_free(xendev);
> +        return NULL;
> +    }
> +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> +
> +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> +            xc_evtchn_close(xendev->evtchndev);
> +            g_free(xendev);
> +            return NULL;
> +        }
> +    } else {
> +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> +    }
> +
> +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> +
> +    if (xendev->ops->alloc) {
> +        xendev->ops->alloc(xendev);
> +    }
> +
> +    return xendev;
> +}

same here


> +/*
> + * release xen device
> + */
> +
> +struct XenDevice *xen_del_xendev(int dom, int dev)
> +{
> +    struct XenDevice *xendev, *xnext;
> +
> +    /*
> +     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
> +     * we save the next pointer in xnext because we might free xendev.
> +     */
> +    xnext = xendevs.tqh_first;
> +    while (xnext) {
> +        xendev = xnext;
> +        xnext = xendev->next.tqe_next;
> +
> +        if (xendev->dom != dom) {
> +            continue;
> +        }
> +        if (xendev->dev != dev && dev != -1) {
> +            continue;
> +        }
> +
> +        if (xendev->ops->free) {
> +            xendev->ops->free(xendev);
> +        }
> +
> +        if (xendev->fe) {
> +            char token[XEN_BUFSIZE];
> +            snprintf(token, sizeof(token), "fe:%p", xendev);
> +            xs_unwatch(xenstore, xendev->fe, token);
> +            g_free(xendev->fe);
> +        }
> +
> +        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> +            xc_evtchn_close(xendev->evtchndev);
> +        }
> +        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> +            xc_gnttab_close(xendev->gnttabdev);
> +        }
> +
> +        QTAILQ_REMOVE(&xendevs, xendev, next);
> +        g_free(xendev);
> +    }
> +    return NULL;
> +}
> +
> +/* ------------------------------------------------------------- */
> +
> +int xenstore_write_str(const char *base, const char *node, const char *val)
> +{
> +    char abspath[XEN_BUFSIZE];
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +char *xenstore_read_str(const char *base, const char *node)
> +{
> +    char abspath[XEN_BUFSIZE];
> +    unsigned int len;
> +    char *str, *ret = NULL;
> +
> +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> +    str = xs_read(xenstore, 0, abspath, &len);
> +    if (str != NULL) {
> +        /* move to qemu-allocated memory to make sure
> +         * callers can savely g_free() stuff. */
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +    return ret;
> +}
> +
> +int xenstore_write_int(const char *base, const char *node, int ival)
> +{
> +    char val[12];
> +
> +    snprintf(val, sizeof(val), "%d", ival);
> +    return xenstore_write_str(base, node, val);
> +}
> +
> +int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> +{
> +    char val[21];
> +
> +    snprintf(val, sizeof(val), "%"PRId64, ival);
> +    return xenstore_write_str(base, node, val);
> +}
> +
> +int xenstore_read_int(const char *base, const char *node, int *ival)
> +{
> +    char *val;
> +    int rc = -1;
> +
> +    val = xenstore_read_str(base, node);
> +    if (val && 1 == sscanf(val, "%d", ival)) {
> +        rc = 0;
> +    }
> +    g_free(val);
> +    return rc;
> +}
> +
> +int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> +{
> +    char *val;
> +    int rc = -1;
> +
> +    val = xenstore_read_str(base, node);
> +    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> +        rc = 0;
> +    }
> +    g_free(val);
> +    return rc;
> +}
> +
> +char *xenstore_get_domain_name(uint32_t domid)
> +{
> +    char *dom_path, *str, *ret = NULL;;
> +
> +    dom_path = xs_get_domain_path(xenstore, domid);
> +    str = xenstore_read_str(dom_path, "name");
> +    free(dom_path);
> +    if (str != NULL) {
> +        ret = g_strdup(str);
> +        free(str);
> +    }
> +
> +    return ret;
> +}
> +
> +/*
> + * Sync internal data structures on xenstore updates.
> + * Node specifies the changed field.  node = NULL means
> + * update all fields (used for initialization).
> + */
> +void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    if (node == NULL  ||  strcmp(node, "online") == 0) {
> +        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
> +            xendev->online = 0;
> +        }
> +    }
> +
> +    if (node) {
> +        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> +        if (xendev->ops->backend_changed) {
> +            xendev->ops->backend_changed(xendev, node);
> +        }
> +    }
> +}
> +
> +void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    int fe_state;
> +
> +    if (node == NULL  ||  strcmp(node, "state") == 0) {
> +        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> +            fe_state = XenbusStateUnknown;
> +        }
> +        if (xendev->fe_state != fe_state) {
> +            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> +                          xenbus_strstate(xendev->fe_state),
> +                          xenbus_strstate(fe_state));
> +        }
> +        xendev->fe_state = fe_state;
> +    }
> +    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> +        g_free(xendev->protocol);
> +        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> +        if (xendev->protocol) {
> +            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> +                          xendev->protocol);
> +        }
> +    }
> +
> +    if (node) {
> +        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> +        if (xendev->ops->frontend_changed) {
> +            xendev->ops->frontend_changed(xendev, node);
> +        }
> +    }
> +}

Anything backend or frontend specific, like these two functions, should either:
    
1) be made generic, shared between frontends and backends, moved to this file
2) left in the corresponding xen_backend.c or xen_frontend.c source file

The first option is better, when possible.


> +static void xenstore_update_be(char *watch, char *type, int dom,
> +                        struct XenDevOps *ops)
> +{
> +    struct XenDevice *xendev;
> +    char path[XEN_BUFSIZE], *bepath;
> +    unsigned int len, dev;
> +
> +    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> +
> +    if (strstr(watch, path) == NULL) {
> +        return;
> +    }
> +    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> +        strcpy(path, "");
> +        if (sscanf(watch+len, "/%u", &dev) != 1) {
> +            dev = -1;
> +        }
> +    }
> +    if (dev == -1) {
> +        return;
> +    }
> +
> +    xendev = xen_be_get_xendev(type, dom, dev, ops);
> +    if (xendev != NULL) {
> +        bepath = xs_read(xenstore, 0, xendev->be, &len);
> +        if (bepath == NULL) {
> +            xen_del_xendev(dom, dev);
> +        } else {
> +            free(bepath);
> +            xen_be_backend_changed(xendev, path);
> +            if (!(ops->flags & DEVOPS_FLAG_FE)) {
> +                xen_be_check_state(xendev);
> +            }
> +        }
> +    }
> +}
> +
> +static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> +{
> +    char *node;
> +    unsigned int len;
> +
> +    len = strlen(xendev->fe);
> +    if (strncmp(xendev->fe, watch, len) != 0) {
> +        return;
> +    }
> +    if (watch[len] != '/') {
> +        return;
> +    }
> +    node = watch + len + 1;
> +
> +    xen_be_frontend_changed(xendev, node);
> +    xen_be_check_state(xendev);
> +}
> +
> +static void xenstore_update(void *unused)
> +{
> +    char **vec = NULL;
> +    intptr_t type, ops, ptr;
> +    unsigned int dom, count;
> +
> +    vec = xs_read_watch(xenstore, &count);
> +    if (vec == NULL) {
> +        goto cleanup;
> +    }
> +
> +    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> +               &type, &dom, &ops) == 3) {
> +        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void *)ops);
> +    }
> +    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> +        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
> +    }
> +
> +cleanup:
> +    free(vec);
> +}
> +
> +int xen_be_init(void)
> +{
> +    xenstore = xs_daemon_open();
> +    if (!xenstore) {
> +        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> +        return -1;
> +    }
> +
> +    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
> +        NULL, NULL) < 0) {
> +        goto err;
> +    }
> +
> +    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> +
> +        /* Check if xen_init() have been called */
> +        goto err;
> +    }
> +    return 0;
> +
> +err:
> +    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> +    xs_daemon_close(xenstore);
> +    xenstore = NULL;
> +
> +    return -1;
> +}
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index 3b4125e..bb0b303 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -15,6 +15,8 @@ struct XenDevice;
>  #define DEVOPS_FLAG_NEED_GNTDEV   1
>  /* don't expect frontend doing correct state transitions (aka console quirk) */
>  #define DEVOPS_FLAG_IGNORE_STATE  2
> +/*dev is frontend device*/
> +#define DEVOPS_FLAG_FE            4
>  
>  struct XenDevOps {
>      size_t    size;
> @@ -59,6 +61,7 @@ struct XenDevice {
>  extern XenXC xen_xc;
>  extern struct xs_handle *xenstore;
>  extern const char *xen_protocol;
> +extern int xenstore_dev;
>  
>  /* xenstore helper functions */
>  int xenstore_write_str(const char *base, const char *node, const char *val);
> @@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
>  int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval);
>  int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval);
>  
> +char *xenstore_get_domain_name(uint32_t domid);
> +
>  const char *xenbus_strstate(enum xenbus_state state);
> -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
> +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
> +struct XenDevice *xen_del_xendev(int dom, int dev);
> +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> +                                    struct XenDevOps *ops);
> +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> +                                    char *backend, struct XenDevOps *ops);
>  void xen_be_check_state(struct XenDevice *xendev);
> +void xen_be_backend_changed(struct XenDevice *xendev, const char *node);
> +void xen_be_frontend_changed(struct XenDevice *xendev, const char *node);
>  
>  /* xen backend driver bits */
>  int xen_be_init(void);
> @@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice *xendev);
>  int xen_be_send_notify(struct XenDevice *xendev);
>  void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
>      GCC_FMT_ATTR(3, 4);
> +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> +                   const char *fmt, ...)
> +    GCC_FMT_ATTR(3, 4);
> +/* Xen frontend driver */
> +int xen_fe_register(const char *type, struct XenDevOps *ops);
> +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
> +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
>  
>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
> @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
>  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
>  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> +extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/
>  
>  void xen_init_display(int domid);
>  
> -- 
> 1.8.3.2
> 

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
@ 2015-05-08  9:52     ` Stefano Stabellini
  -1 siblings, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-08  9:52 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel, dgdegra

On Mon, 4 May 2015, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
>          [...]
>     3 = ""
>      [...]
>      device = "" (frontend device, the backend is running in QEMU/.etc)
>       vkbd = ""
>        [...]
>       vif = ""
>        [...]
> 
>  ..
> 
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>   xen_hvm_init()
>     [...]
>     -->xen_fe_register("vtpm", ...)
>       -->xenstore_fe_scan()
>         -->xen_fe_try_init(ops)
>           --> XenDevOps.init()
>         -->xen_fe_get_xendev()
>           --> XenDevOps.alloc()
>         -->xen_fe_check()
>           -->xen_fe_try_initialise()
>             --> XenDevOps.initialise()
>           -->xen_fe_try_connected()
>             --> XenDevOps.connected()
>         -->xs_watch()
>     [...]
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Replace buf_size with PAGE_SIZE and use length rather than
>   shr->length.
> ---
>  hw/tpm/Makefile.objs         |   1 +
>  hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
>  hw/xen/xen_frontend.c        |  20 +++
>  include/hw/xen/xen_backend.h |   5 +
>  include/hw/xen/xen_common.h  |   6 +
>  xen-hvm.c                    |   5 +
>  6 files changed, 352 insertions(+)
>  create mode 100644 hw/tpm/xen_vtpm_frontend.c
> 
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644
> index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif
> +
> +enum tpmif_state {
> +    /* No contents, vTPM idle, cancel complete */
> +    TPMIF_STATE_IDLE,
> +    /* Request ready or vTPM working */
> +    TPMIF_STATE_SUBMIT,
> +    /* Response ready or vTPM idle */
> +    TPMIF_STATE_FINISH,
> +    /* Cancel requested or vTPM working */
> +    TPMIF_STATE_CANCEL,
> +};
> +
> +static AioContext *vtpm_aio_ctx;
> +
> +enum status_bits {
> +    VTPM_STATUS_RUNNING  = 0x1,
> +    VTPM_STATUS_IDLE     = 0x2,
> +    VTPM_STATUS_RESULT   = 0x4,
> +    VTPM_STATUS_CANCELED = 0x8,
> +};
> +
> +struct tpmif_shared_page {
> +    /* Request and response length in bytes */
> +    uint32_t length;
> +    /* Enum tpmif_state */
> +    uint8_t  state;
> +    /* For the current request */
> +    uint8_t  locality;
> +    /* Should be zero */
> +    uint8_t  pad;
> +    /* Extra pages for long packets; may be zero */
> +    uint8_t  nr_extra_pages;
> +    /*
> +     * Grant IDs, the length is actually nr_extra_pages.
> +     * beyond the extra_pages entries is the actual request
> +     * and response.
> +     */
> +    uint32_t extra_pages[0];
> +};
> +
> +struct xen_vtpm_dev {
> +    struct XenDevice xendev;  /* must be first */
> +    struct           tpmif_shared_page *shr;
> +    xc_gntshr        *xen_xcs;
> +    int              ring_ref;
> +    int              bedomid;
> +    QEMUBH           *sr_bh;
> +};
> +
> +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev)
> +{
> +    switch (vtpmdev->shr->state) {
> +    case TPMIF_STATE_IDLE:
> +    case TPMIF_STATE_FINISH:
> +        return VTPM_STATUS_IDLE;
> +    case TPMIF_STATE_SUBMIT:
> +    case TPMIF_STATE_CANCEL:
> +        return VTPM_STATUS_RUNNING;
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static bool vtpm_aio_wait(AioContext *ctx)
> +{
> +    return aio_poll(ctx, true);
> +}
> +
> +static void sr_bh_handler(void *opaque)
> +{
> +}
> +
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset;
> +    size_t length = shr->length;
> +
> +    if (shr->state == TPMIF_STATE_IDLE) {
> +        return -ECANCELED;
> +    }
> +
> +    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + length > PAGE_SIZE) {
> +        length = PAGE_SIZE - offset;
> +    }
> +
> +    memcpy(buf, offset + (uint8_t *)shr, length);
> +    *count = length;
> +
> +    return 0;
> +}
> +
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset = sizeof(*shr) +
> +                          sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + count > PAGE_SIZE) {
> +        return -ECANCELED;
> +    }
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    memcpy(offset + (uint8_t *)shr, buf, count);
> +    shr->length = count;
> +    barrier();
> +    shr->state = TPMIF_STATE_SUBMIT;
> +    xen_wmb();
> +    xen_be_send_notify(&vtpmdev->xendev);
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    return count;
> +}
> +
> +static int vtpm_initialise(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    xs_transaction_t xbt = XBT_NULL;
> +    unsigned int ring_ref;
> +
> +    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev, "frontend");
> +    if (vtpmdev->xendev.fe == NULL) {
> +        return -1;
> +    }
> +
> +    /* Get backend domid */
> +    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
> +                             &vtpmdev->bedomid)) {
> +        return -1;
> +    }
> +
> +    /* Alloc shared page */
> +    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs, vtpmdev->bedomid, 1,
> +                                         &ring_ref, PROT_READ|PROT_WRITE);
> +    vtpmdev->ring_ref = ring_ref;
> +    if (vtpmdev->shr == NULL) {
> +        return -1;
> +    }
> +
> +    /* Create event channel */
> +    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +        return -1;
> +    }
> +
> +    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
> +                     vtpmdev->xendev.local_port);
> +
> +again:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
> +                           vtpmdev->ring_ref)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
> +                           vtpmdev->xendev.local_port)) {
> +        goto abort_transaction;
> +    }
> +
> +    /* Publish protocol v2 feature */
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto again;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}
> +
> +static int vtpm_free(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    aio_poll(vtpm_aio_ctx, false);
> +    qemu_bh_delete(vtpmdev->sr_bh);
> +    if (vtpmdev->shr) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    }
> +    xc_interface_close(vtpmdev->xen_xcs);
> +    return 0;
> +}
> +
> +static int vtpm_init(struct XenDevice *xendev)
> +{
> +    char path[XEN_BUFSIZE];
> +    char *value;
> +    unsigned int stubdom_vtpm = 0;
> +
> +    snprintf(path, sizeof(path), "/local/domain/%d/platform/acpi_stubdom_vtpm",
> +             xen_domid);
> +    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
> +    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
> +        free(value);
> +        return -1;
> +    }
> +    free(value);
> +    return 0;
> +}
> +
> +static void vtpm_alloc(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    vtpm_aio_ctx = aio_context_new(NULL);
> +    if (vtpm_aio_ctx == NULL) {
> +        return;
> +    }
> +    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0);
> +}
> +
> +static void vtpm_event(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +}
> +
> +struct XenDevOps xen_vtpmdev_ops = {
> +    .size             = sizeof(struct xen_vtpm_dev),
> +    .flags            = DEVOPS_FLAG_IGNORE_STATE |
> +                        DEVOPS_FLAG_FE,
> +    .event            = vtpm_event,
> +    .free             = vtpm_free,
> +    .init             = vtpm_init,
> +    .alloc            = vtpm_alloc,
> +    .initialise       = vtpm_initialise,
> +    .backend_changed  = vtpm_backend_changed,
> +};
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
> index 55af45a..1ca7342 100644
> --- a/hw/xen/xen_frontend.c
> +++ b/hw/xen/xen_frontend.c
> @@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
>  
>  /* ------------------------------------------------------------- */
>  
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    int be_state;
> +
> +    if (strcmp(node, "state") == 0) {
> +        xenstore_read_be_int(xendev, node, &be_state);
> +        switch (be_state) {
> +        case XenbusStateConnected:
> +            /* TODO */
> +            break;
> +        case XenbusStateClosing:
> +        case XenbusStateClosed:
> +            xenbus_switch_state(xendev, XenbusStateClosing);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +}

If this function is vtpm specific, it should be moved to
hw/tpm/xen_vtpm_frontend.c, where the vtpm frontend driver lives.


>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
>  {
>      xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index bb0b303..b959413 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps *ops);
>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
>  int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
>  
> +/* Xen vtpm */
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node);

Then you don't need this anymore.


>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
>  extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
> diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
> index 38f29fb..7268d0c 100644
> --- a/include/hw/xen/xen_common.h
> +++ b/include/hw/xen/xen_common.h
> @@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
>      return xc_interface_open(logger, dombuild_logger, open_flags);
>  }
>  
> +static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
> +                                            unsigned int open_flags)
> +{
> +    return xc_gntshr_open(logger, open_flags);
> +}
> +
>  /* FIXME There is now way to have the xen fd */
>  static inline int xc_fd(xc_interface *xen_xc)
>  {
> diff --git a/xen-hvm.c b/xen-hvm.c
> index 315864c..b2403dc 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
>          fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
>          return -1;
>      }
> +
> +#ifdef CONFIG_TPM_XENSTUBDOMS
> +    xen_fe_register("vtpm", &xen_vtpmdev_ops);
> +#endif
> +
>      xen_be_register("console", &xen_console_ops);
>      xen_be_register("vkbd", &xen_kbdmouse_ops);
>      xen_be_register("qdisk", &xen_blkdev_ops);
> -- 
> 1.8.3.2
> 

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
@ 2015-05-08  9:52     ` Stefano Stabellini
  0 siblings, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-08  9:52 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel,
	dgdegra, eblake

On Mon, 4 May 2015, Quan Xu wrote:
> This patch adds infrastructure for xen front drivers living in qemu,
> so drivers don't need to implement common stuff on their own.  It's
> mostly xenbus management stuff: some functions to access XenStore,
> setting up XenStore watches, callbacks on device discovery and state
> changes, and handle event channel between the virtual machines.
> 
> Call xen_fe_register() function to register XenDevOps, and make sure,
>          [...]
>     3 = ""
>      [...]
>      device = "" (frontend device, the backend is running in QEMU/.etc)
>       vkbd = ""
>        [...]
>       vif = ""
>        [...]
> 
>  ..
> 
> (QEMU) xen_vtpmdev_ops is initialized with the following process:
>   xen_hvm_init()
>     [...]
>     -->xen_fe_register("vtpm", ...)
>       -->xenstore_fe_scan()
>         -->xen_fe_try_init(ops)
>           --> XenDevOps.init()
>         -->xen_fe_get_xendev()
>           --> XenDevOps.alloc()
>         -->xen_fe_check()
>           -->xen_fe_try_initialise()
>             --> XenDevOps.initialise()
>           -->xen_fe_try_connected()
>             --> XenDevOps.connected()
>         -->xs_watch()
>     [...]
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> --Changes in v6:
>  -Replace buf_size with PAGE_SIZE and use length rather than
>   shr->length.
> ---
>  hw/tpm/Makefile.objs         |   1 +
>  hw/tpm/xen_vtpm_frontend.c   | 315 +++++++++++++++++++++++++++++++++++++++++++
>  hw/xen/xen_frontend.c        |  20 +++
>  include/hw/xen/xen_backend.h |   5 +
>  include/hw/xen/xen_common.h  |   6 +
>  xen-hvm.c                    |   5 +
>  6 files changed, 352 insertions(+)
>  create mode 100644 hw/tpm/xen_vtpm_frontend.c
> 
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 99f5983..57919fa 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> new file mode 100644
> index 0000000..d6e7cc6
> --- /dev/null
> +++ b/hw/tpm/xen_vtpm_frontend.c
> @@ -0,0 +1,315 @@
> +/*
> + * Connect to Xen vTPM stubdom domain
> + *
> + *  Copyright (c) 2015 Intel Corporation
> + *  Authors:
> + *    Quan Xu <quan.xu@intel.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <inttypes.h>
> +#include <time.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/uio.h>
> +
> +#include "hw/hw.h"
> +#include "block/aio.h"
> +#include "hw/xen/xen_backend.h"
> +
> +#ifndef XS_STUBDOM_VTPM_ENABLE
> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> +#endif
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE      4096
> +#endif
> +
> +enum tpmif_state {
> +    /* No contents, vTPM idle, cancel complete */
> +    TPMIF_STATE_IDLE,
> +    /* Request ready or vTPM working */
> +    TPMIF_STATE_SUBMIT,
> +    /* Response ready or vTPM idle */
> +    TPMIF_STATE_FINISH,
> +    /* Cancel requested or vTPM working */
> +    TPMIF_STATE_CANCEL,
> +};
> +
> +static AioContext *vtpm_aio_ctx;
> +
> +enum status_bits {
> +    VTPM_STATUS_RUNNING  = 0x1,
> +    VTPM_STATUS_IDLE     = 0x2,
> +    VTPM_STATUS_RESULT   = 0x4,
> +    VTPM_STATUS_CANCELED = 0x8,
> +};
> +
> +struct tpmif_shared_page {
> +    /* Request and response length in bytes */
> +    uint32_t length;
> +    /* Enum tpmif_state */
> +    uint8_t  state;
> +    /* For the current request */
> +    uint8_t  locality;
> +    /* Should be zero */
> +    uint8_t  pad;
> +    /* Extra pages for long packets; may be zero */
> +    uint8_t  nr_extra_pages;
> +    /*
> +     * Grant IDs, the length is actually nr_extra_pages.
> +     * beyond the extra_pages entries is the actual request
> +     * and response.
> +     */
> +    uint32_t extra_pages[0];
> +};
> +
> +struct xen_vtpm_dev {
> +    struct XenDevice xendev;  /* must be first */
> +    struct           tpmif_shared_page *shr;
> +    xc_gntshr        *xen_xcs;
> +    int              ring_ref;
> +    int              bedomid;
> +    QEMUBH           *sr_bh;
> +};
> +
> +static uint8_t vtpm_status(struct xen_vtpm_dev *vtpmdev)
> +{
> +    switch (vtpmdev->shr->state) {
> +    case TPMIF_STATE_IDLE:
> +    case TPMIF_STATE_FINISH:
> +        return VTPM_STATUS_IDLE;
> +    case TPMIF_STATE_SUBMIT:
> +    case TPMIF_STATE_CANCEL:
> +        return VTPM_STATUS_RUNNING;
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static bool vtpm_aio_wait(AioContext *ctx)
> +{
> +    return aio_poll(ctx, true);
> +}
> +
> +static void sr_bh_handler(void *opaque)
> +{
> +}
> +
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset;
> +    size_t length = shr->length;
> +
> +    if (shr->state == TPMIF_STATE_IDLE) {
> +        return -ECANCELED;
> +    }
> +
> +    offset = sizeof(*shr) + sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + length > PAGE_SIZE) {
> +        length = PAGE_SIZE - offset;
> +    }
> +
> +    memcpy(buf, offset + (uint8_t *)shr, length);
> +    *count = length;
> +
> +    return 0;
> +}
> +
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    struct tpmif_shared_page *shr = vtpmdev->shr;
> +    unsigned int offset = sizeof(*shr) +
> +                          sizeof(shr->extra_pages[0])*shr->nr_extra_pages;
> +
> +    if (offset > PAGE_SIZE) {
> +        return -EIO;
> +    }
> +
> +    if (offset + count > PAGE_SIZE) {
> +        return -ECANCELED;
> +    }
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    memcpy(offset + (uint8_t *)shr, buf, count);
> +    shr->length = count;
> +    barrier();
> +    shr->state = TPMIF_STATE_SUBMIT;
> +    xen_wmb();
> +    xen_be_send_notify(&vtpmdev->xendev);
> +
> +    while (vtpm_status(vtpmdev) != VTPM_STATUS_IDLE) {
> +        vtpm_aio_wait(vtpm_aio_ctx);
> +    }
> +
> +    return count;
> +}
> +
> +static int vtpm_initialise(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +    xs_transaction_t xbt = XBT_NULL;
> +    unsigned int ring_ref;
> +
> +    vtpmdev->xendev.fe = xenstore_read_be_str(&vtpmdev->xendev, "frontend");
> +    if (vtpmdev->xendev.fe == NULL) {
> +        return -1;
> +    }
> +
> +    /* Get backend domid */
> +    if (xenstore_read_fe_int(&vtpmdev->xendev, "backend-id",
> +                             &vtpmdev->bedomid)) {
> +        return -1;
> +    }
> +
> +    /* Alloc shared page */
> +    vtpmdev->shr = xc_gntshr_share_pages(vtpmdev->xen_xcs, vtpmdev->bedomid, 1,
> +                                         &ring_ref, PROT_READ|PROT_WRITE);
> +    vtpmdev->ring_ref = ring_ref;
> +    if (vtpmdev->shr == NULL) {
> +        return -1;
> +    }
> +
> +    /* Create event channel */
> +    if (xen_fe_alloc_unbound(&vtpmdev->xendev, 0, vtpmdev->bedomid)) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +        return -1;
> +    }
> +
> +    xc_evtchn_unmask(vtpmdev->xendev.evtchndev,
> +                     vtpmdev->xendev.local_port);
> +
> +again:
> +    xbt = xs_transaction_start(xenstore);
> +    if (xbt == XBT_NULL) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "ring-ref",
> +                           vtpmdev->ring_ref)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "event-channel",
> +                           vtpmdev->xendev.local_port)) {
> +        goto abort_transaction;
> +    }
> +
> +    /* Publish protocol v2 feature */
> +    if (xenstore_write_int(vtpmdev->xendev.fe, "feature-protocol-v2", 1)) {
> +        goto abort_transaction;
> +    }
> +
> +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> +        if (errno == EAGAIN) {
> +            goto again;
> +        }
> +    }
> +
> +    return 0;
> +
> +abort_transaction:
> +    xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    xs_transaction_end(xenstore, xbt, 1);
> +    return -1;
> +}
> +
> +static int vtpm_free(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    aio_poll(vtpm_aio_ctx, false);
> +    qemu_bh_delete(vtpmdev->sr_bh);
> +    if (vtpmdev->shr) {
> +        xc_gntshr_munmap(vtpmdev->xen_xcs, vtpmdev->shr, 1);
> +    }
> +    xc_interface_close(vtpmdev->xen_xcs);
> +    return 0;
> +}
> +
> +static int vtpm_init(struct XenDevice *xendev)
> +{
> +    char path[XEN_BUFSIZE];
> +    char *value;
> +    unsigned int stubdom_vtpm = 0;
> +
> +    snprintf(path, sizeof(path), "/local/domain/%d/platform/acpi_stubdom_vtpm",
> +             xen_domid);
> +    value = xs_read(xenstore, 0, path, &stubdom_vtpm);
> +    if (stubdom_vtpm <= 0 || strcmp(value, XS_STUBDOM_VTPM_ENABLE)) {
> +        free(value);
> +        return -1;
> +    }
> +    free(value);
> +    return 0;
> +}
> +
> +static void vtpm_alloc(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    vtpm_aio_ctx = aio_context_new(NULL);
> +    if (vtpm_aio_ctx == NULL) {
> +        return;
> +    }
> +    vtpmdev->sr_bh = aio_bh_new(vtpm_aio_ctx, sr_bh_handler, vtpmdev);
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +    vtpmdev->xen_xcs = xen_xc_gntshr_open(0, 0);
> +}
> +
> +static void vtpm_event(struct XenDevice *xendev)
> +{
> +    struct xen_vtpm_dev *vtpmdev = container_of(xendev, struct xen_vtpm_dev,
> +                                                xendev);
> +
> +    qemu_bh_schedule(vtpmdev->sr_bh);
> +}
> +
> +struct XenDevOps xen_vtpmdev_ops = {
> +    .size             = sizeof(struct xen_vtpm_dev),
> +    .flags            = DEVOPS_FLAG_IGNORE_STATE |
> +                        DEVOPS_FLAG_FE,
> +    .event            = vtpm_event,
> +    .free             = vtpm_free,
> +    .init             = vtpm_init,
> +    .alloc            = vtpm_alloc,
> +    .initialise       = vtpm_initialise,
> +    .backend_changed  = vtpm_backend_changed,
> +};
> diff --git a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c
> index 55af45a..1ca7342 100644
> --- a/hw/xen/xen_frontend.c
> +++ b/hw/xen/xen_frontend.c
> @@ -60,6 +60,26 @@ static void xen_fe_evtchn_event(void *opaque)
>  
>  /* ------------------------------------------------------------- */
>  
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node)
> +{
> +    int be_state;
> +
> +    if (strcmp(node, "state") == 0) {
> +        xenstore_read_be_int(xendev, node, &be_state);
> +        switch (be_state) {
> +        case XenbusStateConnected:
> +            /* TODO */
> +            break;
> +        case XenbusStateClosing:
> +        case XenbusStateClosed:
> +            xenbus_switch_state(xendev, XenbusStateClosing);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +}

If this function is vtpm specific, it should be moved to
hw/tpm/xen_vtpm_frontend.c, where the vtpm frontend driver lives.


>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom)
>  {
>      xendev->local_port = xc_evtchn_bind_unbound_port(xendev->evtchndev,
> diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> index bb0b303..b959413 100644
> --- a/include/hw/xen/xen_backend.h
> +++ b/include/hw/xen/xen_backend.h
> @@ -110,6 +110,11 @@ int xen_fe_register(const char *type, struct XenDevOps *ops);
>  int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int remote_dom);
>  int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state xbus);
>  
> +/* Xen vtpm */
> +int vtpm_send(struct XenDevice *xendev, uint8_t* buf, size_t count);
> +int vtpm_recv(struct XenDevice *xendev, uint8_t* buf, size_t *count);
> +void vtpm_backend_changed(struct XenDevice *xendev, const char *node);

Then you don't need this anymore.


>  /* actual backend drivers */
>  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
>  extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
> diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
> index 38f29fb..7268d0c 100644
> --- a/include/hw/xen/xen_common.h
> +++ b/include/hw/xen/xen_common.h
> @@ -132,6 +132,12 @@ static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
>      return xc_interface_open(logger, dombuild_logger, open_flags);
>  }
>  
> +static inline xc_gntshr *xen_xc_gntshr_open(void *logger,
> +                                            unsigned int open_flags)
> +{
> +    return xc_gntshr_open(logger, open_flags);
> +}
> +
>  /* FIXME There is now way to have the xen fd */
>  static inline int xc_fd(xc_interface *xen_xc)
>  {
> diff --git a/xen-hvm.c b/xen-hvm.c
> index 315864c..b2403dc 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -1308,6 +1308,11 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size,
>          fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
>          return -1;
>      }
> +
> +#ifdef CONFIG_TPM_XENSTUBDOMS
> +    xen_fe_register("vtpm", &xen_vtpmdev_ops);
> +#endif
> +
>      xen_be_register("console", &xen_console_ops);
>      xen_be_register("vkbd", &xen_kbdmouse_ops);
>      xen_be_register("qdisk", &xen_blkdev_ops);
> -- 
> 1.8.3.2
> 

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

* Re: [Qemu-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04  7:22   ` Quan Xu
@ 2015-05-08  9:52     ` Stefano Stabellini
  -1 siblings, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-08  9:52 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel, dgdegra

On Mon, 4 May 2015, Quan Xu wrote:
> @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
>  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
>  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> +extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/

This should be in the next patch.

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

* Re: [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
@ 2015-05-08  9:52     ` Stefano Stabellini
  0 siblings, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-08  9:52 UTC (permalink / raw)
  To: Quan Xu
  Cc: wei.liu2, stefanb, stefano.stabellini, qemu-devel, xen-devel,
	dgdegra, eblake

On Mon, 4 May 2015, Quan Xu wrote:
> @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
>  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
>  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
>  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> +extern struct XenDevOps xen_vtpmdev_ops;      /* xen_vtpm_frontend.c*/

This should be in the next patch.

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-04 15:36   ` [Qemu-devel] " Stefan Berger
@ 2015-05-11 12:56       ` Xu, Quan
  2015-05-05  2:41     ` [Qemu-devel] " Xu, Quan
  2015-05-11 12:56       ` Xu, Quan
  2 siblings, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-11 12:56 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:36 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> >           [...]
> >      3 = ""
> >       [...]
> >       device = "" (frontend device, the backend is running in QEMU/.etc)
> >        vkbd = ""
> >         [...]
> >        vif = ""
> >         [...]
> >
> >   ..
> >
> > (QEMU) xen_vtpmdev_ops is initialized with the following process:
> >    xen_hvm_init()
> >      [...]
> >      -->xen_fe_register("vtpm", ...)
> >        -->xenstore_fe_scan()
> >          -->xen_fe_try_init(ops)
> >            --> XenDevOps.init()
> >          -->xen_fe_get_xendev()
> >            --> XenDevOps.alloc()
> >          -->xen_fe_check()
> >            -->xen_fe_try_initialise()
> >              --> XenDevOps.initialise()
> >            -->xen_fe_try_connected()
> >              --> XenDevOps.connected()
> >          -->xs_watch()
> >      [...]
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >   -Replace buf_size with PAGE_SIZE and use length rather than
> >    shr->length.
> > ---
> >   hw/tpm/Makefile.objs         |   1 +
> >   hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
> >   hw/xen/xen_frontend.c        |  20 +++
> >   include/hw/xen/xen_backend.h |   5 +
> >   include/hw/xen/xen_common.h  |   6 +
> >   xen-hvm.c                    |   5 +
> >   6 files changed, 352 insertions(+)
> >   create mode 100644 hw/tpm/xen_vtpm_frontend.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 99f5983..57919fa 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,2 +1,3 @@
> >   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> > +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> > diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> > new file mode 100644 index 0000000..d6e7cc6
> > --- /dev/null
> > +++ b/hw/tpm/xen_vtpm_frontend.c
> > @@ -0,0 +1,315 @@
> > +/*
> > + * Connect to Xen vTPM stubdom domain
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <signal.h>
> > +#include <inttypes.h>
> > +#include <time.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/uio.h>
> > +
> > +#include "hw/hw.h"
> > +#include "block/aio.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#ifndef XS_STUBDOM_VTPM_ENABLE
> > +#define XS_STUBDOM_VTPM_ENABLE    "1"
> > +#endif
> > +
> > +#ifndef PAGE_SIZE
> > +#define PAGE_SIZE      4096
> > +#endif
> 
> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> 
> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


Stefan,
     If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c, there are some errors as following:

++++  error ++++ 
In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
/root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
/root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned "BSWAP_NEEDED"
/root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is not defined [-Werror=undef]
/root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
/root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned "TARGET_PAGE_BITS"
/root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned "TARGET_PAGE_MASK"
/root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned "TARGET_PAGE_ALIGN"
/root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned "TARGET_PAGE_MASK"
/root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned "CPUArchState"
/root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name 'CPUArchState'
/root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned "CPUArchState"
/root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name 'CPUArchState'
/root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned "CPU_INTERRUPT_HARD"
/root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned "CPU_INTERRUPT_EXITTB"
/root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned "CPU_INTERRUPT_HALT"
/root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned "CPU_INTERRUPT_DEBUG"
[....]
+++  error +++


------ --- 

Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of TARGET_PAGE_SIZE from exec/cpu-all.h??
+#ifndef VTPM_PAGE_SIZE
+#define VTPM_PAGE_SIZE      4096
+#endif


+ [...]VTPM_PAGE_SIZE ...
 
I send out v7 today. Any comment, I can continue to enhance it. thanks.


Thanks 
Quan Xu





> 
> Regards,
>      Stefan

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
@ 2015-05-11 12:56       ` Xu, Quan
  0 siblings, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-11 12:56 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 04, 2015 11:36 PM
> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/04/2015 03:22 AM, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> >           [...]
> >      3 = ""
> >       [...]
> >       device = "" (frontend device, the backend is running in QEMU/.etc)
> >        vkbd = ""
> >         [...]
> >        vif = ""
> >         [...]
> >
> >   ..
> >
> > (QEMU) xen_vtpmdev_ops is initialized with the following process:
> >    xen_hvm_init()
> >      [...]
> >      -->xen_fe_register("vtpm", ...)
> >        -->xenstore_fe_scan()
> >          -->xen_fe_try_init(ops)
> >            --> XenDevOps.init()
> >          -->xen_fe_get_xendev()
> >            --> XenDevOps.alloc()
> >          -->xen_fe_check()
> >            -->xen_fe_try_initialise()
> >              --> XenDevOps.initialise()
> >            -->xen_fe_try_connected()
> >              --> XenDevOps.connected()
> >          -->xs_watch()
> >      [...]
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> >
> > --Changes in v6:
> >   -Replace buf_size with PAGE_SIZE and use length rather than
> >    shr->length.
> > ---
> >   hw/tpm/Makefile.objs         |   1 +
> >   hw/tpm/xen_vtpm_frontend.c   | 315
> +++++++++++++++++++++++++++++++++++++++++++
> >   hw/xen/xen_frontend.c        |  20 +++
> >   include/hw/xen/xen_backend.h |   5 +
> >   include/hw/xen/xen_common.h  |   6 +
> >   xen-hvm.c                    |   5 +
> >   6 files changed, 352 insertions(+)
> >   create mode 100644 hw/tpm/xen_vtpm_frontend.c
> >
> > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index
> > 99f5983..57919fa 100644
> > --- a/hw/tpm/Makefile.objs
> > +++ b/hw/tpm/Makefile.objs
> > @@ -1,2 +1,3 @@
> >   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> >   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> > +common-obj-$(CONFIG_TPM_XENSTUBDOMS) += xen_vtpm_frontend.o
> > diff --git a/hw/tpm/xen_vtpm_frontend.c b/hw/tpm/xen_vtpm_frontend.c
> > new file mode 100644 index 0000000..d6e7cc6
> > --- /dev/null
> > +++ b/hw/tpm/xen_vtpm_frontend.c
> > @@ -0,0 +1,315 @@
> > +/*
> > + * Connect to Xen vTPM stubdom domain
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <signal.h>
> > +#include <inttypes.h>
> > +#include <time.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <sys/ioctl.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/uio.h>
> > +
> > +#include "hw/hw.h"
> > +#include "block/aio.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#ifndef XS_STUBDOM_VTPM_ENABLE
> > +#define XS_STUBDOM_VTPM_ENABLE    "1"
> > +#endif
> > +
> > +#ifndef PAGE_SIZE
> > +#define PAGE_SIZE      4096
> > +#endif
> 
> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> 
> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


Stefan,
     If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c, there are some errors as following:

++++  error ++++ 
In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
/root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
/root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned "BSWAP_NEEDED"
/root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is not defined [-Werror=undef]
/root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
/root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned "TARGET_PAGE_BITS"
/root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned "TARGET_PAGE_MASK"
/root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned "TARGET_PAGE_ALIGN"
/root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned "TARGET_PAGE_SIZE"
/root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned "TARGET_PAGE_MASK"
/root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned "CPUArchState"
/root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name 'CPUArchState'
/root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned "CPUArchState"
/root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name 'CPUArchState'
/root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned "CPU_INTERRUPT_HARD"
/root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned "CPU_INTERRUPT_EXITTB"
/root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned "CPU_INTERRUPT_HALT"
/root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned "CPU_INTERRUPT_DEBUG"
[....]
+++  error +++


------ --- 

Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of TARGET_PAGE_SIZE from exec/cpu-all.h??
+#ifndef VTPM_PAGE_SIZE
+#define VTPM_PAGE_SIZE      4096
+#endif


+ [...]VTPM_PAGE_SIZE ...
 
I send out v7 today. Any comment, I can continue to enhance it. thanks.


Thanks 
Quan Xu





> 
> Regards,
>      Stefan

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-11 12:56       ` Xu, Quan
  (?)
@ 2015-05-11 14:49       ` Stefan Berger
  2015-05-11 14:51         ` Xu, Quan
  2015-05-11 14:51         ` [Qemu-devel] " Xu, Quan
  -1 siblings, 2 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-11 14:49 UTC (permalink / raw)
  To: Xu, Quan; +Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra

On 05/11/2015 08:56 AM, Xu, Quan wrote:
>
>> -----Original Message-----
>> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
>> Sent: Monday, May 04, 2015 11:36 PM
>> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
>> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
>> xen-devel@lists.xen.org
>> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
>>
>> On 05/04/2015 03:22 AM, Quan Xu wrote:
>>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdarg.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <signal.h>
>> +#include <inttypes.h>
>> +#include <time.h>
>> +#include <fcntl.h>
>> +#include <errno.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <sys/mman.h>
>> +#include <sys/uio.h>
>> +
>> +#include "hw/hw.h"
>> +#include "block/aio.h"
>> +#include "hw/xen/xen_backend.h"
>> +
>> +#ifndef XS_STUBDOM_VTPM_ENABLE
>> +#define XS_STUBDOM_VTPM_ENABLE    "1"
>> +#endif
>> +
>> +#ifndef PAGE_SIZE
>> +#define PAGE_SIZE      4096
>> +#endif
>> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
>>
>> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>
> Stefan,
>       If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c, there are some errors as following:
>
> ++++  error ++++
> In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
> /root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
> /root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned "BSWAP_NEEDED"
> /root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is not defined [-Werror=undef]
> /root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
> /root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned "TARGET_PAGE_BITS"
> /root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned "TARGET_PAGE_MASK"
> /root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned "TARGET_PAGE_ALIGN"
> /root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned "TARGET_PAGE_MASK"
> /root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned "CPUArchState"
> /root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name 'CPUArchState'
> /root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned "CPUArchState"
> /root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name 'CPUArchState'
> /root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned "CPU_INTERRUPT_HARD"
> /root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned "CPU_INTERRUPT_EXITTB"
> /root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned "CPU_INTERRUPT_HALT"
> /root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned "CPU_INTERRUPT_DEBUG"
> [....]
> +++  error +++
>
>
> ------ ---
>
> Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of TARGET_PAGE_SIZE from exec/cpu-all.h??
> +#ifndef VTPM_PAGE_SIZE
> +#define VTPM_PAGE_SIZE      4096
> +#endif

Fine by me.

     Stefan

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-11 12:56       ` Xu, Quan
  (?)
  (?)
@ 2015-05-11 14:49       ` Stefan Berger
  -1 siblings, 0 replies; 48+ messages in thread
From: Stefan Berger @ 2015-05-11 14:49 UTC (permalink / raw)
  To: Xu, Quan
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake

On 05/11/2015 08:56 AM, Xu, Quan wrote:
>
>> -----Original Message-----
>> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
>> Sent: Monday, May 04, 2015 11:36 PM
>> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
>> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
>> xen-devel@lists.xen.org
>> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
>>
>> On 05/04/2015 03:22 AM, Quan Xu wrote:
>>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdarg.h>
>> +#include <string.h>
>> +#include <unistd.h>
>> +#include <signal.h>
>> +#include <inttypes.h>
>> +#include <time.h>
>> +#include <fcntl.h>
>> +#include <errno.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <sys/mman.h>
>> +#include <sys/uio.h>
>> +
>> +#include "hw/hw.h"
>> +#include "block/aio.h"
>> +#include "hw/xen/xen_backend.h"
>> +
>> +#ifndef XS_STUBDOM_VTPM_ENABLE
>> +#define XS_STUBDOM_VTPM_ENABLE    "1"
>> +#endif
>> +
>> +#ifndef PAGE_SIZE
>> +#define PAGE_SIZE      4096
>> +#endif
>> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
>>
>> With this change: Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>
> Stefan,
>       If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c, there are some errors as following:
>
> ++++  error ++++
> In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
> /root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
> /root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned "BSWAP_NEEDED"
> /root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is not defined [-Werror=undef]
> /root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN"
> /root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned "TARGET_PAGE_BITS"
> /root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned "TARGET_PAGE_MASK"
> /root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned "TARGET_PAGE_ALIGN"
> /root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned "TARGET_PAGE_SIZE"
> /root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned "TARGET_PAGE_MASK"
> /root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned "CPUArchState"
> /root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name 'CPUArchState'
> /root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned "CPUArchState"
> /root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name 'CPUArchState'
> /root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned "CPU_INTERRUPT_HARD"
> /root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned "CPU_INTERRUPT_EXITTB"
> /root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned "CPU_INTERRUPT_HALT"
> /root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned "CPU_INTERRUPT_DEBUG"
> [....]
> +++  error +++
>
>
> ------ ---
>
> Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of TARGET_PAGE_SIZE from exec/cpu-all.h??
> +#ifndef VTPM_PAGE_SIZE
> +#define VTPM_PAGE_SIZE      4096
> +#endif

Fine by me.

     Stefan

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

* Re: [Qemu-devel] [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-11 14:49       ` [Qemu-devel] " Stefan Berger
  2015-05-11 14:51         ` Xu, Quan
@ 2015-05-11 14:51         ` Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-11 14:51 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 11, 2015 10:50 PM
> To: Xu, Quan
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/11/2015 08:56 AM, Xu, Quan wrote:
> >
> >> -----Original Message-----
> >> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> >> Sent: Monday, May 04, 2015 11:36 PM
> >> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> >> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com;
> >> dgdegra@tycho.nsa.gov; xen-devel@lists.xen.org
> >> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver
> >> infrastructure
> >>
> >> On 05/04/2015 03:22 AM, Quan Xu wrote:
> >>
> >> +#include <stdio.h>
> >> +#include <stdlib.h>
> >> +#include <stdarg.h>
> >> +#include <string.h>
> >> +#include <unistd.h>
> >> +#include <signal.h>
> >> +#include <inttypes.h>
> >> +#include <time.h>
> >> +#include <fcntl.h>
> >> +#include <errno.h>
> >> +#include <sys/ioctl.h>
> >> +#include <sys/types.h>
> >> +#include <sys/stat.h>
> >> +#include <sys/mman.h>
> >> +#include <sys/uio.h>
> >> +
> >> +#include "hw/hw.h"
> >> +#include "block/aio.h"
> >> +#include "hw/xen/xen_backend.h"
> >> +
> >> +#ifndef XS_STUBDOM_VTPM_ENABLE
> >> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> >> +#endif
> >> +
> >> +#ifndef PAGE_SIZE
> >> +#define PAGE_SIZE      4096
> >> +#endif
> >> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> >>
> >> With this change: Reviewed-by: Stefan Berger
> >> <stefanb@linux.vnet.ibm.com>
> >
> > Stefan,
> >       If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c,
> there are some errors as following:
> >
> > ++++  error ++++
> > In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
> > /root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned
> "TARGET_WORDS_BIGENDIAN"
> > /root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned
> "BSWAP_NEEDED"
> > /root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is
> > not defined [-Werror=undef]
> > /root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned
> "TARGET_WORDS_BIGENDIAN"
> > /root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned
> "TARGET_PAGE_BITS"
> > /root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned
> "TARGET_PAGE_MASK"
> > /root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned
> "TARGET_PAGE_ALIGN"
> > /root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned
> "TARGET_PAGE_MASK"
> > /root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned
> "CPUArchState"
> > /root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name
> 'CPUArchState'
> > /root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned
> "CPUArchState"
> > /root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name
> 'CPUArchState'
> > /root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned
> "CPU_INTERRUPT_HARD"
> > /root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned
> "CPU_INTERRUPT_EXITTB"
> > /root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned
> "CPU_INTERRUPT_HALT"
> > /root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned
> "CPU_INTERRUPT_DEBUG"
> > [....]
> > +++  error +++
> >
> >
> > ------ ---
> >
> > Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of
> TARGET_PAGE_SIZE from exec/cpu-all.h??
> > +#ifndef VTPM_PAGE_SIZE
> > +#define VTPM_PAGE_SIZE      4096
> > +#endif
> 
> Fine by me.
> 
>      Stefan

Thanks. I have sent out v7.



Thanks 
Quan Xu

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

* Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-11 14:49       ` [Qemu-devel] " Stefan Berger
@ 2015-05-11 14:51         ` Xu, Quan
  2015-05-11 14:51         ` [Qemu-devel] " Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-11 14:51 UTC (permalink / raw)
  To: Stefan Berger
  Cc: wei.liu2, stefano.stabellini, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> Sent: Monday, May 11, 2015 10:50 PM
> To: Xu, Quan
> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com; dgdegra@tycho.nsa.gov;
> xen-devel@lists.xen.org; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
> 
> On 05/11/2015 08:56 AM, Xu, Quan wrote:
> >
> >> -----Original Message-----
> >> From: Stefan Berger [mailto:stefanb@linux.vnet.ibm.com]
> >> Sent: Monday, May 04, 2015 11:36 PM
> >> To: Xu, Quan; stefano.stabellini@eu.citrix.com; eblake@redhat.com
> >> Cc: qemu-devel@nongnu.org; wei.liu2@citrix.com;
> >> dgdegra@tycho.nsa.gov; xen-devel@lists.xen.org
> >> Subject: Re: [PATCH v6 3/6] Qemu-Xen-vTPM: Xen frontend driver
> >> infrastructure
> >>
> >> On 05/04/2015 03:22 AM, Quan Xu wrote:
> >>
> >> +#include <stdio.h>
> >> +#include <stdlib.h>
> >> +#include <stdarg.h>
> >> +#include <string.h>
> >> +#include <unistd.h>
> >> +#include <signal.h>
> >> +#include <inttypes.h>
> >> +#include <time.h>
> >> +#include <fcntl.h>
> >> +#include <errno.h>
> >> +#include <sys/ioctl.h>
> >> +#include <sys/types.h>
> >> +#include <sys/stat.h>
> >> +#include <sys/mman.h>
> >> +#include <sys/uio.h>
> >> +
> >> +#include "hw/hw.h"
> >> +#include "block/aio.h"
> >> +#include "hw/xen/xen_backend.h"
> >> +
> >> +#ifndef XS_STUBDOM_VTPM_ENABLE
> >> +#define XS_STUBDOM_VTPM_ENABLE    "1"
> >> +#endif
> >> +
> >> +#ifndef PAGE_SIZE
> >> +#define PAGE_SIZE      4096
> >> +#endif
> >> You should be able to use TARGET_PAGE_SIZE from exec/cpu-all.h I think.
> >>
> >> With this change: Reviewed-by: Stefan Berger
> >> <stefanb@linux.vnet.ibm.com>
> >
> > Stefan,
> >       If I add #include "exec/cpu-all.h" in hw/tpm/xen_vtpm_frontend.c,
> there are some errors as following:
> >
> > ++++  error ++++
> > In file included from hw/tpm/xen_vtpm_frontend.c:41:0:
> > /root/qemu2/include/exec/cpu-all.h:42:46: error: attempt to use poisoned
> "TARGET_WORDS_BIGENDIAN"
> > /root/qemu2/include/exec/cpu-all.h:46:8: error: attempt to use poisoned
> "BSWAP_NEEDED"
> > /root/qemu2/include/exec/cpu-all.h:109:5: error: "TARGET_LONG_SIZE" is
> > not defined [-Werror=undef]
> > /root/qemu2/include/exec/cpu-all.h:122:13: error: attempt to use poisoned
> "TARGET_WORDS_BIGENDIAN"
> > /root/qemu2/include/exec/cpu-all.h:174:9: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:174:32: error: attempt to use poisoned
> "TARGET_PAGE_BITS"
> > /root/qemu2/include/exec/cpu-all.h:175:9: error: attempt to use poisoned
> "TARGET_PAGE_MASK"
> > /root/qemu2/include/exec/cpu-all.h:175:28: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:176:9: error: attempt to use poisoned
> "TARGET_PAGE_ALIGN"
> > /root/qemu2/include/exec/cpu-all.h:176:44: error: attempt to use poisoned
> "TARGET_PAGE_SIZE"
> > /root/qemu2/include/exec/cpu-all.h:176:68: error: attempt to use poisoned
> "TARGET_PAGE_MASK"
> > /root/qemu2/include/exec/cpu-all.h:211:1: error: attempt to use poisoned
> "CPUArchState"
> > /root/qemu2/include/exec/cpu-all.h:211:1: error: unknown type name
> 'CPUArchState'
> > /root/qemu2/include/exec/cpu-all.h:211:24: error: attempt to use poisoned
> "CPUArchState"
> > /root/qemu2/include/exec/cpu-all.h:211:24: error: unknown type name
> 'CPUArchState'
> > /root/qemu2/include/exec/cpu-all.h:222:9: error: attempt to use poisoned
> "CPU_INTERRUPT_HARD"
> > /root/qemu2/include/exec/cpu-all.h:226:9: error: attempt to use poisoned
> "CPU_INTERRUPT_EXITTB"
> > /root/qemu2/include/exec/cpu-all.h:229:9: error: attempt to use poisoned
> "CPU_INTERRUPT_HALT"
> > /root/qemu2/include/exec/cpu-all.h:232:9: error: attempt to use poisoned
> "CPU_INTERRUPT_DEBUG"
> > [....]
> > +++  error +++
> >
> >
> > ------ ---
> >
> > Could I replace PAGE_SIZE with VTPM_ PAGE_SIZE, instead of
> TARGET_PAGE_SIZE from exec/cpu-all.h??
> > +#ifndef VTPM_PAGE_SIZE
> > +#define VTPM_PAGE_SIZE      4096
> > +#endif
> 
> Fine by me.
> 
>      Stefan

Thanks. I have sent out v7.



Thanks 
Quan Xu

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

* Re: [Qemu-devel] [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-07 17:25   ` [Qemu-devel] " Stefano Stabellini
  2015-05-12  1:28     ` Xu, Quan
@ 2015-05-12  1:28     ` Xu, Quan
  2015-05-12 14:12       ` Stefano Stabellini
  2015-05-12 14:12       ` Stefano Stabellini
  1 sibling, 2 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-12  1:28 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: wei.liu2, stefanb, qemu-devel, xen-devel, dgdegra



> -----Original Message-----
> From: xen-devel-bounces@lists.xen.org
> [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of Stefano Stabellini
> Sent: Friday, May 08, 2015 1:26 AM
> To: Xu, Quan
> Cc: wei.liu2@citrix.com; stefanb@linux.vnet.ibm.com;
> stefano.stabellini@eu.citrix.com; qemu-devel@nongnu.org;
> xen-devel@lists.xen.org; dgdegra@tycho.nsa.gov; eblake@redhat.com
> Subject: Re: [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver
> infrastructure
> 
> On Mon, 4 May 2015, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> > XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> > the XenDevOps is Xen frontend.
> >
> > Create a new file xen_pvdev.c for some common part of xen frontend and
> > backend, such as xendevs queue and xenstore update functions.
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> Better than the early versions, thanks.
> 
> However the patch is too big and it is too difficult to read as is.
> Could you please split it in two: a patch that creates xen_pvdev.c and moves a
> few functions from xen_backend.c to it and a second patch that introduces
> xen_frontend.c.
> 

Stefano,
       I missed this comment. Sorry for that.
       Agreed, also I think it is too big. I will do it in v8. 
Quan



> 
> >  hw/display/xenfb.c           |   4 +-
> >  hw/xen/Makefile.objs         |   2 +-
> >  hw/xen/xen_backend.c         | 353 -------------------------------
> >  hw/xen/xen_frontend.c        | 345
> +++++++++++++++++++++++++++++++
> >  hw/xen/xen_pvdev.c           | 481
> +++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/xen/xen_backend.h |  22 +-
> >  6 files changed, 850 insertions(+), 357 deletions(-)  create mode
> > 100644 hw/xen/xen_frontend.c  create mode 100644 hw/xen/xen_pvdev.c
> >
> > diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index
> > 5e324ef..10751df 100644
> > --- a/hw/display/xenfb.c
> > +++ b/hw/display/xenfb.c
> > @@ -988,8 +988,8 @@ void xen_init_display(int domid)
> >  wait_more:
> >      i++;
> >      main_loop_wait(true);
> > -    xfb = xen_be_find_xendev("vfb", domid, 0);
> > -    xin = xen_be_find_xendev("vkbd", domid, 0);
> > +    xfb = xen_find_xendev("vfb", domid, 0);
> > +    xin = xen_find_xendev("vkbd", domid, 0);
> >      if (!xfb || !xin) {
> >          if (i < 256) {
> >              usleep(10000);
> > diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
> > a0ca0aa..95eb9d0 100644
> > --- a/hw/xen/Makefile.objs
> > +++ b/hw/xen/Makefile.objs
> > @@ -1,5 +1,5 @@
> >  # xen backend driver support
> > -common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> > +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> > +xen_frontend.o xen_pvdev.o
> >
> >  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
> >  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o
> > xen_pt_msi.o diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
> > index b2cb22b..844f918 100644
> > --- a/hw/xen/xen_backend.c
> > +++ b/hw/xen/xen_backend.c
> > @@ -44,86 +44,11 @@
> >  /* ------------------------------------------------------------- */
> >
> >  /* public */
> > -XenXC xen_xc = XC_HANDLER_INITIAL_VALUE; -struct xs_handle *xenstore
> > = NULL;  const char *xen_protocol;
> >
> >  /* private */
> > -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> > QTAILQ_HEAD_INITIALIZER(xendevs);  static int debug = 0;
> >
> > -/* ------------------------------------------------------------- */
> > -
> > -int xenstore_write_str(const char *base, const char *node, const char
> > *val) -{
> > -    char abspath[XEN_BUFSIZE];
> > -
> > -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > -    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> > -        return -1;
> > -    }
> > -    return 0;
> > -}
> > -
> > -char *xenstore_read_str(const char *base, const char *node) -{
> > -    char abspath[XEN_BUFSIZE];
> > -    unsigned int len;
> > -    char *str, *ret = NULL;
> > -
> > -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > -    str = xs_read(xenstore, 0, abspath, &len);
> > -    if (str != NULL) {
> > -        /* move to qemu-allocated memory to make sure
> > -         * callers can savely g_free() stuff. */
> > -        ret = g_strdup(str);
> > -        free(str);
> > -    }
> > -    return ret;
> > -}
> > -
> > -int xenstore_write_int(const char *base, const char *node, int ival)
> > -{
> > -    char val[12];
> > -
> > -    snprintf(val, sizeof(val), "%d", ival);
> > -    return xenstore_write_str(base, node, val);
> > -}
> > -
> > -int xenstore_write_int64(const char *base, const char *node, int64_t
> > ival) -{
> > -    char val[21];
> > -
> > -    snprintf(val, sizeof(val), "%"PRId64, ival);
> > -    return xenstore_write_str(base, node, val);
> > -}
> > -
> > -int xenstore_read_int(const char *base, const char *node, int *ival)
> > -{
> > -    char *val;
> > -    int rc = -1;
> > -
> > -    val = xenstore_read_str(base, node);
> > -    if (val && 1 == sscanf(val, "%d", ival)) {
> > -        rc = 0;
> > -    }
> > -    g_free(val);
> > -    return rc;
> > -}
> > -
> > -int xenstore_read_uint64(const char *base, const char *node, uint64_t
> > *uval) -{
> > -    char *val;
> > -    int rc = -1;
> > -
> > -    val = xenstore_read_str(base, node);
> > -    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> > -        rc = 0;
> > -    }
> > -    g_free(val);
> > -    return rc;
> > -}
> > -
> >  int xenstore_write_be_str(struct XenDevice *xendev, const char *node,
> > const char *val)  {
> >      return xenstore_write_str(xendev->be, node, val); @@ -195,183
> > +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum
> > xenbus_state state)  }
> >
> >  /* ------------------------------------------------------------- */
> > -
> > -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int
> > dev) -{
> > -    struct XenDevice *xendev;
> > -
> > -    QTAILQ_FOREACH(xendev, &xendevs, next) {
> > -        if (xendev->dom != dom) {
> > -            continue;
> > -        }
> > -        if (xendev->dev != dev) {
> > -            continue;
> > -        }
> > -        if (strcmp(xendev->type, type) != 0) {
> > -            continue;
> > -        }
> > -        return xendev;
> > -    }
> > -    return NULL;
> > -}
> > -
> > -/*
> > - * get xen backend device, allocate a new one if it doesn't exist.
> > - */
> > -static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int
> dev,
> > -                                           struct XenDevOps *ops)
> > -{
> > -    struct XenDevice *xendev;
> > -
> > -    xendev = xen_be_find_xendev(type, dom, dev);
> > -    if (xendev) {
> > -        return xendev;
> > -    }
> > -
> > -    /* init new xendev */
> > -    xendev = g_malloc0(ops->size);
> > -    xendev->type  = type;
> > -    xendev->dom   = dom;
> > -    xendev->dev   = dev;
> > -    xendev->ops   = ops;
> > -
> > -    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> > -             xendev->type, xendev->dom, xendev->dev);
> > -    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > -             xendev->type, xendev->dev);
> > -
> > -    xendev->debug      = debug;
> > -    xendev->local_port = -1;
> > -
> > -    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > -    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > -        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > -        g_free(xendev);
> > -        return NULL;
> > -    }
> > -    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > -
> > -    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > -        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > -        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > -            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > -            xc_evtchn_close(xendev->evtchndev);
> > -            g_free(xendev);
> > -            return NULL;
> > -        }
> > -    } else {
> > -        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > -    }
> > -
> > -    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > -
> > -    if (xendev->ops->alloc) {
> > -        xendev->ops->alloc(xendev);
> > -    }
> > -
> > -    return xendev;
> > -}
> > -
> > -/*
> > - * release xen backend device.
> > - */
> > -static struct XenDevice *xen_be_del_xendev(int dom, int dev) -{
> > -    struct XenDevice *xendev, *xnext;
> > -
> > -    /*
> > -     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next)
> but
> > -     * we save the next pointer in xnext because we might free xendev.
> > -     */
> > -    xnext = xendevs.tqh_first;
> > -    while (xnext) {
> > -        xendev = xnext;
> > -        xnext = xendev->next.tqe_next;
> > -
> > -        if (xendev->dom != dom) {
> > -            continue;
> > -        }
> > -        if (xendev->dev != dev && dev != -1) {
> > -            continue;
> > -        }
> > -
> > -        if (xendev->ops->free) {
> > -            xendev->ops->free(xendev);
> > -        }
> > -
> > -        if (xendev->fe) {
> > -            char token[XEN_BUFSIZE];
> > -            snprintf(token, sizeof(token), "fe:%p", xendev);
> > -            xs_unwatch(xenstore, xendev->fe, token);
> > -            g_free(xendev->fe);
> > -        }
> > -
> > -        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> > -            xc_evtchn_close(xendev->evtchndev);
> > -        }
> > -        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> > -            xc_gnttab_close(xendev->gnttabdev);
> > -        }
> > -
> > -        QTAILQ_REMOVE(&xendevs, xendev, next);
> > -        g_free(xendev);
> > -    }
> > -    return NULL;
> > -}
> > -
> > -/*
> > - * Sync internal data structures on xenstore updates.
> > - * Node specifies the changed field.  node = NULL means
> > - * update all fields (used for initialization).
> > - */
> > -static void xen_be_backend_changed(struct XenDevice *xendev, const
> > char *node) -{
> > -    if (node == NULL  ||  strcmp(node, "online") == 0) {
> > -        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
> {
> > -            xendev->online = 0;
> > -        }
> > -    }
> > -
> > -    if (node) {
> > -        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> > -        if (xendev->ops->backend_changed) {
> > -            xendev->ops->backend_changed(xendev, node);
> > -        }
> > -    }
> > -}
> > -
> > -static void xen_be_frontend_changed(struct XenDevice *xendev, const
> > char *node) -{
> > -    int fe_state;
> > -
> > -    if (node == NULL  ||  strcmp(node, "state") == 0) {
> > -        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > -            fe_state = XenbusStateUnknown;
> > -        }
> > -        if (xendev->fe_state != fe_state) {
> > -            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> > -                          xenbus_strstate(xendev->fe_state),
> > -                          xenbus_strstate(fe_state));
> > -        }
> > -        xendev->fe_state = fe_state;
> > -    }
> > -    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> > -        g_free(xendev->protocol);
> > -        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> > -        if (xendev->protocol) {
> > -            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> xendev->protocol);
> > -        }
> > -    }
> > -
> > -    if (node) {
> > -        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> > -        if (xendev->ops->frontend_changed) {
> > -            xendev->ops->frontend_changed(xendev, node);
> > -        }
> > -    }
> > -}
> > -
> > -/* ------------------------------------------------------------- */
> >  /* Check for possible state transitions and perform them.        */
> >
> >  /*
> > @@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom,
> struct XenDevOps *ops)
> >      return 0;
> >  }
> >
> > -static void xenstore_update_be(char *watch, char *type, int dom,
> > -                               struct XenDevOps *ops)
> > -{
> > -    struct XenDevice *xendev;
> > -    char path[XEN_BUFSIZE], *bepath;
> > -    unsigned int len, dev;
> > -
> > -    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> > -    if (strncmp(path, watch, len) != 0) {
> > -        return;
> > -    }
> > -    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> > -        strcpy(path, "");
> > -        if (sscanf(watch+len, "/%u", &dev) != 1) {
> > -            dev = -1;
> > -        }
> > -    }
> > -    if (dev == -1) {
> > -        return;
> > -    }
> > -
> > -    xendev = xen_be_get_xendev(type, dom, dev, ops);
> > -    if (xendev != NULL) {
> > -        bepath = xs_read(xenstore, 0, xendev->be, &len);
> > -        if (bepath == NULL) {
> > -            xen_be_del_xendev(dom, dev);
> > -        } else {
> > -            free(bepath);
> > -            xen_be_backend_changed(xendev, path);
> > -            xen_be_check_state(xendev);
> > -        }
> > -    }
> > -}
> > -
> > -static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> > -{
> > -    char *node;
> > -    unsigned int len;
> > -
> > -    len = strlen(xendev->fe);
> > -    if (strncmp(xendev->fe, watch, len) != 0) {
> > -        return;
> > -    }
> > -    if (watch[len] != '/') {
> > -        return;
> > -    }
> > -    node = watch + len + 1;
> > -
> > -    xen_be_frontend_changed(xendev, node);
> > -    xen_be_check_state(xendev);
> > -}
> > -
> > -static void xenstore_update(void *unused) -{
> > -    char **vec = NULL;
> > -    intptr_t type, ops, ptr;
> > -    unsigned int dom, count;
> > -
> > -    vec = xs_read_watch(xenstore, &count);
> > -    if (vec == NULL) {
> > -        goto cleanup;
> > -    }
> > -
> > -    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> > -               &type, &dom, &ops) == 3) {
> > -        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom,
> (void*)ops);
> > -    }
> > -    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> > -        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
> > -    }
> > -
> > -cleanup:
> > -    free(vec);
> > -}
> > -
> >  static void xen_be_evtchn_event(void *opaque)  {
> >      struct XenDevice *xendev = opaque; @@ -706,32 +379,6 @@ static
> > void xen_be_evtchn_event(void *opaque)
> >
> >  /*
> > --------------------------------------------------------------------
> > */
> >
> > -int xen_be_init(void)
> > -{
> > -    xenstore = xs_daemon_open();
> > -    if (!xenstore) {
> > -        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> > -        return -1;
> > -    }
> > -
> > -    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL,
> NULL) < 0) {
> > -        goto err;
> > -    }
> > -
> > -    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> > -        /* Check if xen_init() have been called */
> > -        goto err;
> > -    }
> > -    return 0;
> > -
> > -err:
> > -    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> > -    xs_daemon_close(xenstore);
> > -    xenstore = NULL;
> > -
> > -    return -1;
> > -}
> > -
> >  int xen_be_register(const char *type, struct XenDevOps *ops)  {
> >      return xenstore_scan(type, xen_domid, ops); diff --git
> > a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c new file mode 100644
> > index 0000000..55af45a
> > --- /dev/null
> > +++ b/hw/xen/xen_frontend.c
> > @@ -0,0 +1,345 @@
> > +/*
> > + * Xen frontend driver infrastructure
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <inttypes.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/signal.h>
> > +
> > +#include "hw/hw.h"
> > +#include "sysemu/char.h"
> > +#include "qemu/log.h"
> > +#include "hw/xen/xen_backend.h"
> > +#include <xen/grant_table.h>
> > +
> > +int xenstore_dev;
> > +
> > +/* private */
> > +static int debug;
> > +
> > +static void xen_fe_evtchn_event(void *opaque) {
> > +    struct XenDevice *xendev = opaque;
> > +    evtchn_port_t port;
> > +
> > +    port = xc_evtchn_pending(xendev->evtchndev);
> > +    if (port != xendev->local_port) {
> > +        return;
> > +    }
> > +    xc_evtchn_unmask(xendev->evtchndev, port);
> > +
> > +    if (xendev->ops->event) {
> > +        xendev->ops->event(xendev);
> > +    }
> > +}
> 
> This function is basically identical to xen_be_evtchn_event: could we find a way
> to generalize it and have only one?
> 
> 
> > +/* ------------------------------------------------------------- */
> > +
> > +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> > +remote_dom) {
> > +    xendev->local_port =
> xc_evtchn_bind_unbound_port(xendev->evtchndev,
> > +                                                     remote_dom);
> > +    if (xendev->local_port == -1) {
> > +        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
> > +        return -1;
> > +    }
> > +    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
> > +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
> > +                        xen_fe_evtchn_event, NULL, xendev);
> > +    return 0;
> > +}
> > +
> > +/*
> > + * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
> > + * xendev->ops->initialize()
> > + */
> > +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state
> > +xbus) {
> > +    xs_transaction_t xbt = XBT_NULL;
> > +
> > +    if (xendev->fe_state == xbus) {
> > +        return 0;
> > +    }
> > +
> > +    xendev->fe_state = xbus;
> > +    if (xendev->fe == NULL) {
> > +        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
> > +        return -1;
> > +    }
> > +
> > +retry_transaction:
> > +    xbt = xs_transaction_start(xenstore);
> > +    if (xbt == XBT_NULL) {
> > +        goto abort_transaction;
> > +    }
> > +
> > +    if (xenstore_write_int(xendev->fe, "state", xbus)) {
> > +        goto abort_transaction;
> > +    }
> > +
> > +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> > +        if (errno == EAGAIN) {
> > +            goto retry_transaction;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +
> > +abort_transaction:
> > +    xs_transaction_end(xenstore, xbt, 1);
> > +    return -1;
> > +}
> 
> This function could probably be unified with xen_be_set_state.
> 
> 
> > +/*
> > + * Simplify QEMU side, a thread is running in Xen backend, which will
> > + * connect frontend when the frontend is initialised. Call these
> > +initialised
> > + * functions.
> > + */
> > +static int xen_fe_try_init(void *opaque) {
> > +    struct XenDevOps *ops = opaque;
> > +    int rc = -1;
> > +
> > +    if (ops->init) {
> > +        rc = ops->init(NULL);
> > +    }
> > +
> > +    return rc;
> > +}
> > +
> > +static int xen_fe_try_initialise(struct XenDevice *xendev) {
> > +    int rc = 0, fe_state;
> > +
> > +    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > +        fe_state = XenbusStateUnknown;
> > +    }
> > +    xendev->fe_state = fe_state;
> > +
> > +    if (xendev->ops->initialise) {
> > +        rc = xendev->ops->initialise(xendev);
> > +    }
> > +    if (rc != 0) {
> > +        xen_fe_printf(xendev, 0, "initialise() failed\n");
> > +        return rc;
> > +    }
> > +
> > +    xenbus_switch_state(xendev, XenbusStateInitialised);
> > +    return 0;
> > +}
> > +
> > +static void xen_fe_try_connected(struct XenDevice *xendev) {
> > +    if (!xendev->ops->connected) {
> > +        return;
> > +    }
> > +
> > +    if (xendev->fe_state != XenbusStateConnected) {
> > +        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
> > +            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
> > +        } else {
> > +            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
> > +            return;
> > +        }
> > +    }
> > +
> > +    xendev->ops->connected(xendev);
> > +}
> > +
> > +static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
> > +                        int handle)
> > +{
> > +    int rc = 0;
> > +
> > +    rc = xen_fe_try_initialise(xendev);
> > +    if (rc != 0) {
> > +        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
> > +                      xendev->name);
> > +        goto err;
> > +    }
> > +    xen_fe_try_connected(xendev);
> > +
> > +    return rc;
> > +
> > +err:
> > +    xen_del_xendev(domid, handle);
> > +    return -1;
> > +}
> > +
> > +static char *xenstore_fe_get_backend(const char *type, int be_domid,
> > +                                     uint32_t domid, int *hdl) {
> > +    char *name, *str, *ret = NULL;
> > +    uint32_t i, cdev;
> > +    int handle = 0;
> > +    char path[XEN_BUFSIZE];
> > +    char **dev = NULL;
> > +
> > +    name = xenstore_get_domain_name(domid);
> > +    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
> > +    dev = xs_directory(xenstore, 0, path, &cdev);
> > +    for (i = 0; i < cdev; i++) {
> > +        handle = i;
> > +        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> > +        type, be_domid, handle);
> > +        str = xenstore_read_str(path, "domain");
> > +        if (!strcmp(name, str)) {
> > +            break;
> > +        }
> > +
> > +        free(str);
> > +
> > +        /* Not the backend domain */
> > +        if (handle == (cdev - 1)) {
> > +            goto err;
> > +        }
> > +    }
> > +
> > +    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> > +    type, be_domid, handle);
> > +    str = xenstore_read_str(path, "backend");
> > +    if (str != NULL) {
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +
> > +    *hdl = handle;
> > +    free(dev);
> > +
> > +    return ret;
> > +err:
> > +    *hdl = -1;
> > +    free(dev);
> > +    return NULL;
> > +}
> > +
> > +static int xenstore_fe_scan(const char *type, uint32_t domid,
> > +                            struct XenDevOps *ops) {
> > +    struct XenDevice *xendev;
> > +    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
> > +    unsigned int cdev, j;
> > +    char *backend;
> > +    char **dev = NULL;
> > +    int rc;
> > +
> > +    /* ops .init check, xendev is NOT initialized */
> > +    rc = xen_fe_try_init(ops);
> > +    if (rc != 0) {
> > +        return -1;
> > +    }
> > +
> > +    /* Get /local/domain/0/${type}/{} directory */
> > +    snprintf(path, sizeof(path), "frontend/%s", type);
> > +    dev = xs_directory(xenstore, 0, path, &cdev);
> > +    if (dev == NULL) {
> > +        return 0;
> > +    }
> > +
> > +    for (j = 0; j < cdev; j++) {
> > +
> > +        /* Get backend via domain name */
> > +        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
> > +                                          domid, &xenstore_dev);
> > +        if (backend == NULL) {
> > +            continue;
> > +        }
> > +
> > +        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend,
> ops);
> > +        free(backend);
> > +        if (xendev == NULL) {
> > +            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
> > +            continue;
> > +        }
> > +
> > +        /*
> > +         * Simplify QEMU side, a thread is running in Xen backend, which will
> > +         * connect frontend when the frontend is initialised.
> > +         */
> > +        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
> > +            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
> > +            continue;
> > +        }
> > +
> > +        /* Setup watch */
> > +        snprintf(token, sizeof(token), "be:%p:%d:%p",
> > +                 type, domid, xendev->ops);
> > +        if (!xs_watch(xenstore, xendev->be, token)) {
> > +            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
> > +            continue;
> > +        }
> > +    }
> > +
> > +    free(dev);
> > +    return 0;
> > +}
> > +
> > +int xen_fe_register(const char *type, struct XenDevOps *ops) {
> > +    return xenstore_fe_scan(type, xen_domid, ops); }
> > +
> > +/*
> > + * msg_level:
> > + *  0 == errors (stderr + logfile).
> > + *  1 == informative debug messages (logfile only).
> > + *  2 == noisy debug messages (logfile only).
> > + *  3 == will flood your log (logfile only).
> > + */
> > +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> > +                   const char *fmt, ...)
> > +{
> > +    va_list args;
> > +
> > +    if (xendev) {
> > +        if (msg_level > xendev->debug) {
> > +            return;
> > +        }
> > +        qemu_log("xen fe: %s: ", xendev->name);
> > +        if (msg_level == 0) {
> > +            fprintf(stderr, "xen fe: %s: ", xendev->name);
> > +        }
> > +    } else {
> > +        if (msg_level > debug) {
> > +            return;
> > +        }
> > +        qemu_log("xen fe core: ");
> > +        if (msg_level == 0) {
> > +            fprintf(stderr, "xen fe core: ");
> > +        }
> > +    }
> > +    va_start(args, fmt);
> > +    qemu_log_vprintf(fmt, args);
> > +    va_end(args);
> > +    if (msg_level == 0) {
> > +        va_start(args, fmt);
> > +        vfprintf(stderr, fmt, args);
> > +        va_end(args);
> > +    }
> > +    qemu_log_flush();
> 
> There is no need to introduce another one of these. Just rename
> xen_be_printf to xen_pv_printf and move it it xen_pvdev.c.
> 
> In general we should try to share as many functions as possible between
> the frontend and the backend code. To do that we need to modify the
> existing backend functions, such as xen_be_printf, generalize them so
> that they can also be used by frontends (in this case renaming
> xen_be_printf to xen_pv_printf should be enough), and move them to
> xen_pvdev.c.
> 
> 
> > diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
> > new file mode 100644
> > index 0000000..dac8639
> > --- /dev/null
> > +++ b/hw/xen/xen_pvdev.c
> > @@ -0,0 +1,481 @@
> > +/*
> > + * Xen para-virtualization device
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> > + */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <inttypes.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/signal.h>
> > +
> > +#include "hw/hw.h"
> > +#include "sysemu/char.h"
> > +#include "qemu/log.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#include <xen/grant_table.h>
> > +
> > +static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> > +           QTAILQ_HEAD_INITIALIZER(xendevs);
> > +static int debug;
> > +
> > +/* public */
> > +XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> > +struct xs_handle *xenstore;
> > +
> > +/*
> > + * find Xen device
> > + */
> > +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    QTAILQ_FOREACH(xendev, &xendevs, next) {
> > +        if (xendev->dom != dom) {
> > +            continue;
> > +        }
> > +        if (xendev->dev != dev) {
> > +            continue;
> > +        }
> > +        if (strcmp(xendev->type, type) != 0) {
> > +            continue;
> > +        }
> > +        return xendev;
> > +    }
> > +    return NULL;
> > +}
> > +
> > +/*
> > + * get xen backend device, allocate a new one if it doesn't exist.
> > + */
> > +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> > +                                    struct XenDevOps *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    xendev = xen_find_xendev(type, dom, dev);
> > +    if (xendev) {
> > +        return xendev;
> > +    }
> > +
> > +    /* init new xendev */
> > +    xendev = g_malloc0(ops->size);
> > +    xendev->type  = type;
> > +    xendev->dom   = dom;
> > +    xendev->dev   = dev;
> > +    xendev->ops   = ops;
> > +
> > +    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> > +             xendev->type, xendev->dom, xendev->dev);
> > +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > +             xendev->type, xendev->dev);
> > +
> > +    xendev->debug      = debug;
> > +    xendev->local_port = -1;
> > +
> > +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > +        g_free(xendev);
> > +        return NULL;
> > +    }
> > +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > +
> > +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > +            xc_evtchn_close(xendev->evtchndev);
> > +            g_free(xendev);
> > +            return NULL;
> > +        }
> > +    } else {
> > +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > +    }
> > +
> > +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > +
> > +    if (xendev->ops->alloc) {
> > +        xendev->ops->alloc(xendev);
> > +    }
> > +
> > +    return xendev;
> > +}
> 
> Only functions that are shared between frontends and backends should be
> here, like xen_find_xendev. Otherwise there is no benefit in moving them
> to a separete, shared, source file.
> 
> 
> > +/*
> > + * get xen fe device, allocate a new one if it doesn't exist.
> > + */
> > +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> > +                                    char *backend, struct XenDevOps
> *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    xendev = xen_find_xendev(type, dom, dev);
> > +    if (xendev) {
> > +        return xendev;
> > +    }
> > +
> > +    /* init new xendev */
> > +    xendev = g_malloc0(ops->size);
> > +    xendev->type  = type;
> > +    xendev->dom   = dom;
> > +    xendev->dev   = dev;
> > +    xendev->ops   = ops;
> > +
> > +    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
> > +    if (!(ops->flags & DEVOPS_FLAG_FE)) {
> > +        return NULL;
> > +    }
> > +
> > +    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
> > +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > +             xendev->type, xendev->dev);
> > +
> > +    xendev->debug = debug;
> > +    xendev->local_port = -1;
> > +
> > +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > +        g_free(xendev);
> > +        return NULL;
> > +    }
> > +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > +
> > +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > +            xc_evtchn_close(xendev->evtchndev);
> > +            g_free(xendev);
> > +            return NULL;
> > +        }
> > +    } else {
> > +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > +    }
> > +
> > +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > +
> > +    if (xendev->ops->alloc) {
> > +        xendev->ops->alloc(xendev);
> > +    }
> > +
> > +    return xendev;
> > +}
> 
> same here
> 
> 
> > +/*
> > + * release xen device
> > + */
> > +
> > +struct XenDevice *xen_del_xendev(int dom, int dev)
> > +{
> > +    struct XenDevice *xendev, *xnext;
> > +
> > +    /*
> > +     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next)
> but
> > +     * we save the next pointer in xnext because we might free xendev.
> > +     */
> > +    xnext = xendevs.tqh_first;
> > +    while (xnext) {
> > +        xendev = xnext;
> > +        xnext = xendev->next.tqe_next;
> > +
> > +        if (xendev->dom != dom) {
> > +            continue;
> > +        }
> > +        if (xendev->dev != dev && dev != -1) {
> > +            continue;
> > +        }
> > +
> > +        if (xendev->ops->free) {
> > +            xendev->ops->free(xendev);
> > +        }
> > +
> > +        if (xendev->fe) {
> > +            char token[XEN_BUFSIZE];
> > +            snprintf(token, sizeof(token), "fe:%p", xendev);
> > +            xs_unwatch(xenstore, xendev->fe, token);
> > +            g_free(xendev->fe);
> > +        }
> > +
> > +        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> > +            xc_evtchn_close(xendev->evtchndev);
> > +        }
> > +        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> > +            xc_gnttab_close(xendev->gnttabdev);
> > +        }
> > +
> > +        QTAILQ_REMOVE(&xendevs, xendev, next);
> > +        g_free(xendev);
> > +    }
> > +    return NULL;
> > +}
> > +
> > +/* ------------------------------------------------------------- */
> > +
> > +int xenstore_write_str(const char *base, const char *node, const char *val)
> > +{
> > +    char abspath[XEN_BUFSIZE];
> > +
> > +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > +    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> > +        return -1;
> > +    }
> > +    return 0;
> > +}
> > +
> > +char *xenstore_read_str(const char *base, const char *node)
> > +{
> > +    char abspath[XEN_BUFSIZE];
> > +    unsigned int len;
> > +    char *str, *ret = NULL;
> > +
> > +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > +    str = xs_read(xenstore, 0, abspath, &len);
> > +    if (str != NULL) {
> > +        /* move to qemu-allocated memory to make sure
> > +         * callers can savely g_free() stuff. */
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +    return ret;
> > +}
> > +
> > +int xenstore_write_int(const char *base, const char *node, int ival)
> > +{
> > +    char val[12];
> > +
> > +    snprintf(val, sizeof(val), "%d", ival);
> > +    return xenstore_write_str(base, node, val);
> > +}
> > +
> > +int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> > +{
> > +    char val[21];
> > +
> > +    snprintf(val, sizeof(val), "%"PRId64, ival);
> > +    return xenstore_write_str(base, node, val);
> > +}
> > +
> > +int xenstore_read_int(const char *base, const char *node, int *ival)
> > +{
> > +    char *val;
> > +    int rc = -1;
> > +
> > +    val = xenstore_read_str(base, node);
> > +    if (val && 1 == sscanf(val, "%d", ival)) {
> > +        rc = 0;
> > +    }
> > +    g_free(val);
> > +    return rc;
> > +}
> > +
> > +int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> > +{
> > +    char *val;
> > +    int rc = -1;
> > +
> > +    val = xenstore_read_str(base, node);
> > +    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> > +        rc = 0;
> > +    }
> > +    g_free(val);
> > +    return rc;
> > +}
> > +
> > +char *xenstore_get_domain_name(uint32_t domid)
> > +{
> > +    char *dom_path, *str, *ret = NULL;;
> > +
> > +    dom_path = xs_get_domain_path(xenstore, domid);
> > +    str = xenstore_read_str(dom_path, "name");
> > +    free(dom_path);
> > +    if (str != NULL) {
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> > +/*
> > + * Sync internal data structures on xenstore updates.
> > + * Node specifies the changed field.  node = NULL means
> > + * update all fields (used for initialization).
> > + */
> > +void xen_be_backend_changed(struct XenDevice *xendev, const char
> *node)
> > +{
> > +    if (node == NULL  ||  strcmp(node, "online") == 0) {
> > +        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
> {
> > +            xendev->online = 0;
> > +        }
> > +    }
> > +
> > +    if (node) {
> > +        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> > +        if (xendev->ops->backend_changed) {
> > +            xendev->ops->backend_changed(xendev, node);
> > +        }
> > +    }
> > +}
> > +
> > +void xen_be_frontend_changed(struct XenDevice *xendev, const char
> *node)
> > +{
> > +    int fe_state;
> > +
> > +    if (node == NULL  ||  strcmp(node, "state") == 0) {
> > +        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > +            fe_state = XenbusStateUnknown;
> > +        }
> > +        if (xendev->fe_state != fe_state) {
> > +            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> > +                          xenbus_strstate(xendev->fe_state),
> > +                          xenbus_strstate(fe_state));
> > +        }
> > +        xendev->fe_state = fe_state;
> > +    }
> > +    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> > +        g_free(xendev->protocol);
> > +        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> > +        if (xendev->protocol) {
> > +            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> > +                          xendev->protocol);
> > +        }
> > +    }
> > +
> > +    if (node) {
> > +        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> > +        if (xendev->ops->frontend_changed) {
> > +            xendev->ops->frontend_changed(xendev, node);
> > +        }
> > +    }
> > +}
> 
> Anything backend or frontend specific, like these two functions, should either:
> 
> 1) be made generic, shared between frontends and backends, moved to this file
> 2) left in the corresponding xen_backend.c or xen_frontend.c source file
> 
> The first option is better, when possible.
> 
> 
> > +static void xenstore_update_be(char *watch, char *type, int dom,
> > +                        struct XenDevOps *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +    char path[XEN_BUFSIZE], *bepath;
> > +    unsigned int len, dev;
> > +
> > +    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> > +
> > +    if (strstr(watch, path) == NULL) {
> > +        return;
> > +    }
> > +    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> > +        strcpy(path, "");
> > +        if (sscanf(watch+len, "/%u", &dev) != 1) {
> > +            dev = -1;
> > +        }
> > +    }
> > +    if (dev == -1) {
> > +        return;
> > +    }
> > +
> > +    xendev = xen_be_get_xendev(type, dom, dev, ops);
> > +    if (xendev != NULL) {
> > +        bepath = xs_read(xenstore, 0, xendev->be, &len);
> > +        if (bepath == NULL) {
> > +            xen_del_xendev(dom, dev);
> > +        } else {
> > +            free(bepath);
> > +            xen_be_backend_changed(xendev, path);
> > +            if (!(ops->flags & DEVOPS_FLAG_FE)) {
> > +                xen_be_check_state(xendev);
> > +            }
> > +        }
> > +    }
> > +}
> > +
> > +static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> > +{
> > +    char *node;
> > +    unsigned int len;
> > +
> > +    len = strlen(xendev->fe);
> > +    if (strncmp(xendev->fe, watch, len) != 0) {
> > +        return;
> > +    }
> > +    if (watch[len] != '/') {
> > +        return;
> > +    }
> > +    node = watch + len + 1;
> > +
> > +    xen_be_frontend_changed(xendev, node);
> > +    xen_be_check_state(xendev);
> > +}
> > +
> > +static void xenstore_update(void *unused)
> > +{
> > +    char **vec = NULL;
> > +    intptr_t type, ops, ptr;
> > +    unsigned int dom, count;
> > +
> > +    vec = xs_read_watch(xenstore, &count);
> > +    if (vec == NULL) {
> > +        goto cleanup;
> > +    }
> > +
> > +    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> > +               &type, &dom, &ops) == 3) {
> > +        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom,
> (void *)ops);
> > +    }
> > +    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> > +        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
> > +    }
> > +
> > +cleanup:
> > +    free(vec);
> > +}
> > +
> > +int xen_be_init(void)
> > +{
> > +    xenstore = xs_daemon_open();
> > +    if (!xenstore) {
> > +        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> > +        return -1;
> > +    }
> > +
> > +    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
> > +        NULL, NULL) < 0) {
> > +        goto err;
> > +    }
> > +
> > +    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> > +
> > +        /* Check if xen_init() have been called */
> > +        goto err;
> > +    }
> > +    return 0;
> > +
> > +err:
> > +    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> > +    xs_daemon_close(xenstore);
> > +    xenstore = NULL;
> > +
> > +    return -1;
> > +}
> > diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> > index 3b4125e..bb0b303 100644
> > --- a/include/hw/xen/xen_backend.h
> > +++ b/include/hw/xen/xen_backend.h
> > @@ -15,6 +15,8 @@ struct XenDevice;
> >  #define DEVOPS_FLAG_NEED_GNTDEV   1
> >  /* don't expect frontend doing correct state transitions (aka console quirk) */
> >  #define DEVOPS_FLAG_IGNORE_STATE  2
> > +/*dev is frontend device*/
> > +#define DEVOPS_FLAG_FE            4
> >
> >  struct XenDevOps {
> >      size_t    size;
> > @@ -59,6 +61,7 @@ struct XenDevice {
> >  extern XenXC xen_xc;
> >  extern struct xs_handle *xenstore;
> >  extern const char *xen_protocol;
> > +extern int xenstore_dev;
> >
> >  /* xenstore helper functions */
> >  int xenstore_write_str(const char *base, const char *node, const char *val);
> > @@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev,
> const char *node, int *ival);
> >  int xenstore_read_uint64(const char *base, const char *node, uint64_t
> *uval);
> >  int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
> uint64_t *uval);
> >
> > +char *xenstore_get_domain_name(uint32_t domid);
> > +
> >  const char *xenbus_strstate(enum xenbus_state state);
> > -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
> > +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
> > +struct XenDevice *xen_del_xendev(int dom, int dev);
> > +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> > +                                    struct XenDevOps *ops);
> > +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> > +                                    char *backend, struct XenDevOps
> *ops);
> >  void xen_be_check_state(struct XenDevice *xendev);
> > +void xen_be_backend_changed(struct XenDevice *xendev, const char
> *node);
> > +void xen_be_frontend_changed(struct XenDevice *xendev, const char
> *node);
> >
> >  /* xen backend driver bits */
> >  int xen_be_init(void);
> > @@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice
> *xendev);
> >  int xen_be_send_notify(struct XenDevice *xendev);
> >  void xen_be_printf(struct XenDevice *xendev, int msg_level, const char
> *fmt, ...)
> >      GCC_FMT_ATTR(3, 4);
> > +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> > +                   const char *fmt, ...)
> > +    GCC_FMT_ATTR(3, 4);
> > +/* Xen frontend driver */
> > +int xen_fe_register(const char *type, struct XenDevOps *ops);
> > +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> remote_dom);
> > +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state
> xbus);
> >
> >  /* actual backend drivers */
> >  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
> > @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /*
> xen_framebuffer.c */
> >  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
> >  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
> >  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> > +extern struct XenDevOps xen_vtpmdev_ops;      /*
> xen_vtpm_frontend.c*/
> >
> >  void xen_init_display(int domid);
> >
> > --
> > 1.8.3.2
> >
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

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

* Re: [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-07 17:25   ` [Qemu-devel] " Stefano Stabellini
@ 2015-05-12  1:28     ` Xu, Quan
  2015-05-12  1:28     ` [Qemu-devel] [Xen-devel] " Xu, Quan
  1 sibling, 0 replies; 48+ messages in thread
From: Xu, Quan @ 2015-05-12  1:28 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: wei.liu2, stefanb, qemu-devel, xen-devel, dgdegra, eblake



> -----Original Message-----
> From: xen-devel-bounces@lists.xen.org
> [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of Stefano Stabellini
> Sent: Friday, May 08, 2015 1:26 AM
> To: Xu, Quan
> Cc: wei.liu2@citrix.com; stefanb@linux.vnet.ibm.com;
> stefano.stabellini@eu.citrix.com; qemu-devel@nongnu.org;
> xen-devel@lists.xen.org; dgdegra@tycho.nsa.gov; eblake@redhat.com
> Subject: Re: [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver
> infrastructure
> 
> On Mon, 4 May 2015, Quan Xu wrote:
> > This patch adds infrastructure for xen front drivers living in qemu,
> > so drivers don't need to implement common stuff on their own.  It's
> > mostly xenbus management stuff: some functions to access XenStore,
> > setting up XenStore watches, callbacks on device discovery and state
> > changes, and handle event channel between the virtual machines.
> >
> > Call xen_fe_register() function to register XenDevOps, and make sure,
> > XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> > the XenDevOps is Xen frontend.
> >
> > Create a new file xen_pvdev.c for some common part of xen frontend and
> > backend, such as xendevs queue and xenstore update functions.
> >
> > Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> Better than the early versions, thanks.
> 
> However the patch is too big and it is too difficult to read as is.
> Could you please split it in two: a patch that creates xen_pvdev.c and moves a
> few functions from xen_backend.c to it and a second patch that introduces
> xen_frontend.c.
> 

Stefano,
       I missed this comment. Sorry for that.
       Agreed, also I think it is too big. I will do it in v8. 
Quan



> 
> >  hw/display/xenfb.c           |   4 +-
> >  hw/xen/Makefile.objs         |   2 +-
> >  hw/xen/xen_backend.c         | 353 -------------------------------
> >  hw/xen/xen_frontend.c        | 345
> +++++++++++++++++++++++++++++++
> >  hw/xen/xen_pvdev.c           | 481
> +++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/xen/xen_backend.h |  22 +-
> >  6 files changed, 850 insertions(+), 357 deletions(-)  create mode
> > 100644 hw/xen/xen_frontend.c  create mode 100644 hw/xen/xen_pvdev.c
> >
> > diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index
> > 5e324ef..10751df 100644
> > --- a/hw/display/xenfb.c
> > +++ b/hw/display/xenfb.c
> > @@ -988,8 +988,8 @@ void xen_init_display(int domid)
> >  wait_more:
> >      i++;
> >      main_loop_wait(true);
> > -    xfb = xen_be_find_xendev("vfb", domid, 0);
> > -    xin = xen_be_find_xendev("vkbd", domid, 0);
> > +    xfb = xen_find_xendev("vfb", domid, 0);
> > +    xin = xen_find_xendev("vkbd", domid, 0);
> >      if (!xfb || !xin) {
> >          if (i < 256) {
> >              usleep(10000);
> > diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs index
> > a0ca0aa..95eb9d0 100644
> > --- a/hw/xen/Makefile.objs
> > +++ b/hw/xen/Makefile.objs
> > @@ -1,5 +1,5 @@
> >  # xen backend driver support
> > -common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> > +common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
> > +xen_frontend.o xen_pvdev.o
> >
> >  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
> >  obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o
> > xen_pt_msi.o diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
> > index b2cb22b..844f918 100644
> > --- a/hw/xen/xen_backend.c
> > +++ b/hw/xen/xen_backend.c
> > @@ -44,86 +44,11 @@
> >  /* ------------------------------------------------------------- */
> >
> >  /* public */
> > -XenXC xen_xc = XC_HANDLER_INITIAL_VALUE; -struct xs_handle *xenstore
> > = NULL;  const char *xen_protocol;
> >
> >  /* private */
> > -static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> > QTAILQ_HEAD_INITIALIZER(xendevs);  static int debug = 0;
> >
> > -/* ------------------------------------------------------------- */
> > -
> > -int xenstore_write_str(const char *base, const char *node, const char
> > *val) -{
> > -    char abspath[XEN_BUFSIZE];
> > -
> > -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > -    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> > -        return -1;
> > -    }
> > -    return 0;
> > -}
> > -
> > -char *xenstore_read_str(const char *base, const char *node) -{
> > -    char abspath[XEN_BUFSIZE];
> > -    unsigned int len;
> > -    char *str, *ret = NULL;
> > -
> > -    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > -    str = xs_read(xenstore, 0, abspath, &len);
> > -    if (str != NULL) {
> > -        /* move to qemu-allocated memory to make sure
> > -         * callers can savely g_free() stuff. */
> > -        ret = g_strdup(str);
> > -        free(str);
> > -    }
> > -    return ret;
> > -}
> > -
> > -int xenstore_write_int(const char *base, const char *node, int ival)
> > -{
> > -    char val[12];
> > -
> > -    snprintf(val, sizeof(val), "%d", ival);
> > -    return xenstore_write_str(base, node, val);
> > -}
> > -
> > -int xenstore_write_int64(const char *base, const char *node, int64_t
> > ival) -{
> > -    char val[21];
> > -
> > -    snprintf(val, sizeof(val), "%"PRId64, ival);
> > -    return xenstore_write_str(base, node, val);
> > -}
> > -
> > -int xenstore_read_int(const char *base, const char *node, int *ival)
> > -{
> > -    char *val;
> > -    int rc = -1;
> > -
> > -    val = xenstore_read_str(base, node);
> > -    if (val && 1 == sscanf(val, "%d", ival)) {
> > -        rc = 0;
> > -    }
> > -    g_free(val);
> > -    return rc;
> > -}
> > -
> > -int xenstore_read_uint64(const char *base, const char *node, uint64_t
> > *uval) -{
> > -    char *val;
> > -    int rc = -1;
> > -
> > -    val = xenstore_read_str(base, node);
> > -    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> > -        rc = 0;
> > -    }
> > -    g_free(val);
> > -    return rc;
> > -}
> > -
> >  int xenstore_write_be_str(struct XenDevice *xendev, const char *node,
> > const char *val)  {
> >      return xenstore_write_str(xendev->be, node, val); @@ -195,183
> > +120,6 @@ int xen_be_set_state(struct XenDevice *xendev, enum
> > xenbus_state state)  }
> >
> >  /* ------------------------------------------------------------- */
> > -
> > -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int
> > dev) -{
> > -    struct XenDevice *xendev;
> > -
> > -    QTAILQ_FOREACH(xendev, &xendevs, next) {
> > -        if (xendev->dom != dom) {
> > -            continue;
> > -        }
> > -        if (xendev->dev != dev) {
> > -            continue;
> > -        }
> > -        if (strcmp(xendev->type, type) != 0) {
> > -            continue;
> > -        }
> > -        return xendev;
> > -    }
> > -    return NULL;
> > -}
> > -
> > -/*
> > - * get xen backend device, allocate a new one if it doesn't exist.
> > - */
> > -static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int
> dev,
> > -                                           struct XenDevOps *ops)
> > -{
> > -    struct XenDevice *xendev;
> > -
> > -    xendev = xen_be_find_xendev(type, dom, dev);
> > -    if (xendev) {
> > -        return xendev;
> > -    }
> > -
> > -    /* init new xendev */
> > -    xendev = g_malloc0(ops->size);
> > -    xendev->type  = type;
> > -    xendev->dom   = dom;
> > -    xendev->dev   = dev;
> > -    xendev->ops   = ops;
> > -
> > -    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> > -             xendev->type, xendev->dom, xendev->dev);
> > -    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > -             xendev->type, xendev->dev);
> > -
> > -    xendev->debug      = debug;
> > -    xendev->local_port = -1;
> > -
> > -    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > -    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > -        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > -        g_free(xendev);
> > -        return NULL;
> > -    }
> > -    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > -
> > -    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > -        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > -        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > -            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > -            xc_evtchn_close(xendev->evtchndev);
> > -            g_free(xendev);
> > -            return NULL;
> > -        }
> > -    } else {
> > -        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > -    }
> > -
> > -    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > -
> > -    if (xendev->ops->alloc) {
> > -        xendev->ops->alloc(xendev);
> > -    }
> > -
> > -    return xendev;
> > -}
> > -
> > -/*
> > - * release xen backend device.
> > - */
> > -static struct XenDevice *xen_be_del_xendev(int dom, int dev) -{
> > -    struct XenDevice *xendev, *xnext;
> > -
> > -    /*
> > -     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next)
> but
> > -     * we save the next pointer in xnext because we might free xendev.
> > -     */
> > -    xnext = xendevs.tqh_first;
> > -    while (xnext) {
> > -        xendev = xnext;
> > -        xnext = xendev->next.tqe_next;
> > -
> > -        if (xendev->dom != dom) {
> > -            continue;
> > -        }
> > -        if (xendev->dev != dev && dev != -1) {
> > -            continue;
> > -        }
> > -
> > -        if (xendev->ops->free) {
> > -            xendev->ops->free(xendev);
> > -        }
> > -
> > -        if (xendev->fe) {
> > -            char token[XEN_BUFSIZE];
> > -            snprintf(token, sizeof(token), "fe:%p", xendev);
> > -            xs_unwatch(xenstore, xendev->fe, token);
> > -            g_free(xendev->fe);
> > -        }
> > -
> > -        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> > -            xc_evtchn_close(xendev->evtchndev);
> > -        }
> > -        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> > -            xc_gnttab_close(xendev->gnttabdev);
> > -        }
> > -
> > -        QTAILQ_REMOVE(&xendevs, xendev, next);
> > -        g_free(xendev);
> > -    }
> > -    return NULL;
> > -}
> > -
> > -/*
> > - * Sync internal data structures on xenstore updates.
> > - * Node specifies the changed field.  node = NULL means
> > - * update all fields (used for initialization).
> > - */
> > -static void xen_be_backend_changed(struct XenDevice *xendev, const
> > char *node) -{
> > -    if (node == NULL  ||  strcmp(node, "online") == 0) {
> > -        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
> {
> > -            xendev->online = 0;
> > -        }
> > -    }
> > -
> > -    if (node) {
> > -        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> > -        if (xendev->ops->backend_changed) {
> > -            xendev->ops->backend_changed(xendev, node);
> > -        }
> > -    }
> > -}
> > -
> > -static void xen_be_frontend_changed(struct XenDevice *xendev, const
> > char *node) -{
> > -    int fe_state;
> > -
> > -    if (node == NULL  ||  strcmp(node, "state") == 0) {
> > -        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > -            fe_state = XenbusStateUnknown;
> > -        }
> > -        if (xendev->fe_state != fe_state) {
> > -            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> > -                          xenbus_strstate(xendev->fe_state),
> > -                          xenbus_strstate(fe_state));
> > -        }
> > -        xendev->fe_state = fe_state;
> > -    }
> > -    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> > -        g_free(xendev->protocol);
> > -        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> > -        if (xendev->protocol) {
> > -            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> xendev->protocol);
> > -        }
> > -    }
> > -
> > -    if (node) {
> > -        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> > -        if (xendev->ops->frontend_changed) {
> > -            xendev->ops->frontend_changed(xendev, node);
> > -        }
> > -    }
> > -}
> > -
> > -/* ------------------------------------------------------------- */
> >  /* Check for possible state transitions and perform them.        */
> >
> >  /*
> > @@ -611,81 +359,6 @@ static int xenstore_scan(const char *type, int dom,
> struct XenDevOps *ops)
> >      return 0;
> >  }
> >
> > -static void xenstore_update_be(char *watch, char *type, int dom,
> > -                               struct XenDevOps *ops)
> > -{
> > -    struct XenDevice *xendev;
> > -    char path[XEN_BUFSIZE], *bepath;
> > -    unsigned int len, dev;
> > -
> > -    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> > -    if (strncmp(path, watch, len) != 0) {
> > -        return;
> > -    }
> > -    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> > -        strcpy(path, "");
> > -        if (sscanf(watch+len, "/%u", &dev) != 1) {
> > -            dev = -1;
> > -        }
> > -    }
> > -    if (dev == -1) {
> > -        return;
> > -    }
> > -
> > -    xendev = xen_be_get_xendev(type, dom, dev, ops);
> > -    if (xendev != NULL) {
> > -        bepath = xs_read(xenstore, 0, xendev->be, &len);
> > -        if (bepath == NULL) {
> > -            xen_be_del_xendev(dom, dev);
> > -        } else {
> > -            free(bepath);
> > -            xen_be_backend_changed(xendev, path);
> > -            xen_be_check_state(xendev);
> > -        }
> > -    }
> > -}
> > -
> > -static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> > -{
> > -    char *node;
> > -    unsigned int len;
> > -
> > -    len = strlen(xendev->fe);
> > -    if (strncmp(xendev->fe, watch, len) != 0) {
> > -        return;
> > -    }
> > -    if (watch[len] != '/') {
> > -        return;
> > -    }
> > -    node = watch + len + 1;
> > -
> > -    xen_be_frontend_changed(xendev, node);
> > -    xen_be_check_state(xendev);
> > -}
> > -
> > -static void xenstore_update(void *unused) -{
> > -    char **vec = NULL;
> > -    intptr_t type, ops, ptr;
> > -    unsigned int dom, count;
> > -
> > -    vec = xs_read_watch(xenstore, &count);
> > -    if (vec == NULL) {
> > -        goto cleanup;
> > -    }
> > -
> > -    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> > -               &type, &dom, &ops) == 3) {
> > -        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom,
> (void*)ops);
> > -    }
> > -    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> > -        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
> > -    }
> > -
> > -cleanup:
> > -    free(vec);
> > -}
> > -
> >  static void xen_be_evtchn_event(void *opaque)  {
> >      struct XenDevice *xendev = opaque; @@ -706,32 +379,6 @@ static
> > void xen_be_evtchn_event(void *opaque)
> >
> >  /*
> > --------------------------------------------------------------------
> > */
> >
> > -int xen_be_init(void)
> > -{
> > -    xenstore = xs_daemon_open();
> > -    if (!xenstore) {
> > -        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> > -        return -1;
> > -    }
> > -
> > -    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL,
> NULL) < 0) {
> > -        goto err;
> > -    }
> > -
> > -    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> > -        /* Check if xen_init() have been called */
> > -        goto err;
> > -    }
> > -    return 0;
> > -
> > -err:
> > -    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> > -    xs_daemon_close(xenstore);
> > -    xenstore = NULL;
> > -
> > -    return -1;
> > -}
> > -
> >  int xen_be_register(const char *type, struct XenDevOps *ops)  {
> >      return xenstore_scan(type, xen_domid, ops); diff --git
> > a/hw/xen/xen_frontend.c b/hw/xen/xen_frontend.c new file mode 100644
> > index 0000000..55af45a
> > --- /dev/null
> > +++ b/hw/xen/xen_frontend.c
> > @@ -0,0 +1,345 @@
> > +/*
> > + * Xen frontend driver infrastructure
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see
> > +<http://www.gnu.org/licenses/>  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <inttypes.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/signal.h>
> > +
> > +#include "hw/hw.h"
> > +#include "sysemu/char.h"
> > +#include "qemu/log.h"
> > +#include "hw/xen/xen_backend.h"
> > +#include <xen/grant_table.h>
> > +
> > +int xenstore_dev;
> > +
> > +/* private */
> > +static int debug;
> > +
> > +static void xen_fe_evtchn_event(void *opaque) {
> > +    struct XenDevice *xendev = opaque;
> > +    evtchn_port_t port;
> > +
> > +    port = xc_evtchn_pending(xendev->evtchndev);
> > +    if (port != xendev->local_port) {
> > +        return;
> > +    }
> > +    xc_evtchn_unmask(xendev->evtchndev, port);
> > +
> > +    if (xendev->ops->event) {
> > +        xendev->ops->event(xendev);
> > +    }
> > +}
> 
> This function is basically identical to xen_be_evtchn_event: could we find a way
> to generalize it and have only one?
> 
> 
> > +/* ------------------------------------------------------------- */
> > +
> > +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> > +remote_dom) {
> > +    xendev->local_port =
> xc_evtchn_bind_unbound_port(xendev->evtchndev,
> > +                                                     remote_dom);
> > +    if (xendev->local_port == -1) {
> > +        xen_fe_printf(xendev, 0, "xc_evtchn_alloc_unbound failed\n");
> > +        return -1;
> > +    }
> > +    xen_fe_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
> > +    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
> > +                        xen_fe_evtchn_event, NULL, xendev);
> > +    return 0;
> > +}
> > +
> > +/*
> > + * Make sure, initialize the 'xendev->fe' in xendev->ops->init() or
> > + * xendev->ops->initialize()
> > + */
> > +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state
> > +xbus) {
> > +    xs_transaction_t xbt = XBT_NULL;
> > +
> > +    if (xendev->fe_state == xbus) {
> > +        return 0;
> > +    }
> > +
> > +    xendev->fe_state = xbus;
> > +    if (xendev->fe == NULL) {
> > +        xen_fe_printf(NULL, 0, "xendev->fe is NULL\n");
> > +        return -1;
> > +    }
> > +
> > +retry_transaction:
> > +    xbt = xs_transaction_start(xenstore);
> > +    if (xbt == XBT_NULL) {
> > +        goto abort_transaction;
> > +    }
> > +
> > +    if (xenstore_write_int(xendev->fe, "state", xbus)) {
> > +        goto abort_transaction;
> > +    }
> > +
> > +    if (!xs_transaction_end(xenstore, xbt, 0)) {
> > +        if (errno == EAGAIN) {
> > +            goto retry_transaction;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +
> > +abort_transaction:
> > +    xs_transaction_end(xenstore, xbt, 1);
> > +    return -1;
> > +}
> 
> This function could probably be unified with xen_be_set_state.
> 
> 
> > +/*
> > + * Simplify QEMU side, a thread is running in Xen backend, which will
> > + * connect frontend when the frontend is initialised. Call these
> > +initialised
> > + * functions.
> > + */
> > +static int xen_fe_try_init(void *opaque) {
> > +    struct XenDevOps *ops = opaque;
> > +    int rc = -1;
> > +
> > +    if (ops->init) {
> > +        rc = ops->init(NULL);
> > +    }
> > +
> > +    return rc;
> > +}
> > +
> > +static int xen_fe_try_initialise(struct XenDevice *xendev) {
> > +    int rc = 0, fe_state;
> > +
> > +    if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > +        fe_state = XenbusStateUnknown;
> > +    }
> > +    xendev->fe_state = fe_state;
> > +
> > +    if (xendev->ops->initialise) {
> > +        rc = xendev->ops->initialise(xendev);
> > +    }
> > +    if (rc != 0) {
> > +        xen_fe_printf(xendev, 0, "initialise() failed\n");
> > +        return rc;
> > +    }
> > +
> > +    xenbus_switch_state(xendev, XenbusStateInitialised);
> > +    return 0;
> > +}
> > +
> > +static void xen_fe_try_connected(struct XenDevice *xendev) {
> > +    if (!xendev->ops->connected) {
> > +        return;
> > +    }
> > +
> > +    if (xendev->fe_state != XenbusStateConnected) {
> > +        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
> > +            xen_fe_printf(xendev, 2, "frontend not ready, ignoring\n");
> > +        } else {
> > +            xen_fe_printf(xendev, 2, "frontend not ready (yet)\n");
> > +            return;
> > +        }
> > +    }
> > +
> > +    xendev->ops->connected(xendev);
> > +}
> > +
> > +static int xen_fe_check(struct XenDevice *xendev, uint32_t domid,
> > +                        int handle)
> > +{
> > +    int rc = 0;
> > +
> > +    rc = xen_fe_try_initialise(xendev);
> > +    if (rc != 0) {
> > +        xen_fe_printf(xendev, 0, "xendev %s initialise error\n",
> > +                      xendev->name);
> > +        goto err;
> > +    }
> > +    xen_fe_try_connected(xendev);
> > +
> > +    return rc;
> > +
> > +err:
> > +    xen_del_xendev(domid, handle);
> > +    return -1;
> > +}
> > +
> > +static char *xenstore_fe_get_backend(const char *type, int be_domid,
> > +                                     uint32_t domid, int *hdl) {
> > +    char *name, *str, *ret = NULL;
> > +    uint32_t i, cdev;
> > +    int handle = 0;
> > +    char path[XEN_BUFSIZE];
> > +    char **dev = NULL;
> > +
> > +    name = xenstore_get_domain_name(domid);
> > +    snprintf(path, sizeof(path), "frontend/%s/%d", type, be_domid);
> > +    dev = xs_directory(xenstore, 0, path, &cdev);
> > +    for (i = 0; i < cdev; i++) {
> > +        handle = i;
> > +        snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> > +        type, be_domid, handle);
> > +        str = xenstore_read_str(path, "domain");
> > +        if (!strcmp(name, str)) {
> > +            break;
> > +        }
> > +
> > +        free(str);
> > +
> > +        /* Not the backend domain */
> > +        if (handle == (cdev - 1)) {
> > +            goto err;
> > +        }
> > +    }
> > +
> > +    snprintf(path, sizeof(path), "frontend/%s/%d/%d",
> > +    type, be_domid, handle);
> > +    str = xenstore_read_str(path, "backend");
> > +    if (str != NULL) {
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +
> > +    *hdl = handle;
> > +    free(dev);
> > +
> > +    return ret;
> > +err:
> > +    *hdl = -1;
> > +    free(dev);
> > +    return NULL;
> > +}
> > +
> > +static int xenstore_fe_scan(const char *type, uint32_t domid,
> > +                            struct XenDevOps *ops) {
> > +    struct XenDevice *xendev;
> > +    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
> > +    unsigned int cdev, j;
> > +    char *backend;
> > +    char **dev = NULL;
> > +    int rc;
> > +
> > +    /* ops .init check, xendev is NOT initialized */
> > +    rc = xen_fe_try_init(ops);
> > +    if (rc != 0) {
> > +        return -1;
> > +    }
> > +
> > +    /* Get /local/domain/0/${type}/{} directory */
> > +    snprintf(path, sizeof(path), "frontend/%s", type);
> > +    dev = xs_directory(xenstore, 0, path, &cdev);
> > +    if (dev == NULL) {
> > +        return 0;
> > +    }
> > +
> > +    for (j = 0; j < cdev; j++) {
> > +
> > +        /* Get backend via domain name */
> > +        backend = xenstore_fe_get_backend(type, atoi(dev[j]),
> > +                                          domid, &xenstore_dev);
> > +        if (backend == NULL) {
> > +            continue;
> > +        }
> > +
> > +        xendev = xen_fe_get_xendev(type, domid, xenstore_dev, backend,
> ops);
> > +        free(backend);
> > +        if (xendev == NULL) {
> > +            xen_fe_printf(xendev, 0, "xendev is NULL.\n");
> > +            continue;
> > +        }
> > +
> > +        /*
> > +         * Simplify QEMU side, a thread is running in Xen backend, which will
> > +         * connect frontend when the frontend is initialised.
> > +         */
> > +        if (xen_fe_check(xendev, domid, xenstore_dev) < 0) {
> > +            xen_fe_printf(xendev, 0, "xendev fe_check error.\n");
> > +            continue;
> > +        }
> > +
> > +        /* Setup watch */
> > +        snprintf(token, sizeof(token), "be:%p:%d:%p",
> > +                 type, domid, xendev->ops);
> > +        if (!xs_watch(xenstore, xendev->be, token)) {
> > +            xen_fe_printf(xendev, 0, "xs_watch failed.\n");
> > +            continue;
> > +        }
> > +    }
> > +
> > +    free(dev);
> > +    return 0;
> > +}
> > +
> > +int xen_fe_register(const char *type, struct XenDevOps *ops) {
> > +    return xenstore_fe_scan(type, xen_domid, ops); }
> > +
> > +/*
> > + * msg_level:
> > + *  0 == errors (stderr + logfile).
> > + *  1 == informative debug messages (logfile only).
> > + *  2 == noisy debug messages (logfile only).
> > + *  3 == will flood your log (logfile only).
> > + */
> > +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> > +                   const char *fmt, ...)
> > +{
> > +    va_list args;
> > +
> > +    if (xendev) {
> > +        if (msg_level > xendev->debug) {
> > +            return;
> > +        }
> > +        qemu_log("xen fe: %s: ", xendev->name);
> > +        if (msg_level == 0) {
> > +            fprintf(stderr, "xen fe: %s: ", xendev->name);
> > +        }
> > +    } else {
> > +        if (msg_level > debug) {
> > +            return;
> > +        }
> > +        qemu_log("xen fe core: ");
> > +        if (msg_level == 0) {
> > +            fprintf(stderr, "xen fe core: ");
> > +        }
> > +    }
> > +    va_start(args, fmt);
> > +    qemu_log_vprintf(fmt, args);
> > +    va_end(args);
> > +    if (msg_level == 0) {
> > +        va_start(args, fmt);
> > +        vfprintf(stderr, fmt, args);
> > +        va_end(args);
> > +    }
> > +    qemu_log_flush();
> 
> There is no need to introduce another one of these. Just rename
> xen_be_printf to xen_pv_printf and move it it xen_pvdev.c.
> 
> In general we should try to share as many functions as possible between
> the frontend and the backend code. To do that we need to modify the
> existing backend functions, such as xen_be_printf, generalize them so
> that they can also be used by frontends (in this case renaming
> xen_be_printf to xen_pv_printf should be enough), and move them to
> xen_pvdev.c.
> 
> 
> > diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
> > new file mode 100644
> > index 0000000..dac8639
> > --- /dev/null
> > +++ b/hw/xen/xen_pvdev.c
> > @@ -0,0 +1,481 @@
> > +/*
> > + * Xen para-virtualization device
> > + *
> > + *  Copyright (c) 2015 Intel Corporation
> > + *  Authors:
> > + *    Quan Xu <quan.xu@intel.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see <http://www.gnu.org/licenses/>
> > + */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdarg.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <inttypes.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <sys/mman.h>
> > +#include <sys/signal.h>
> > +
> > +#include "hw/hw.h"
> > +#include "sysemu/char.h"
> > +#include "qemu/log.h"
> > +#include "hw/xen/xen_backend.h"
> > +
> > +#include <xen/grant_table.h>
> > +
> > +static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
> > +           QTAILQ_HEAD_INITIALIZER(xendevs);
> > +static int debug;
> > +
> > +/* public */
> > +XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
> > +struct xs_handle *xenstore;
> > +
> > +/*
> > + * find Xen device
> > + */
> > +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    QTAILQ_FOREACH(xendev, &xendevs, next) {
> > +        if (xendev->dom != dom) {
> > +            continue;
> > +        }
> > +        if (xendev->dev != dev) {
> > +            continue;
> > +        }
> > +        if (strcmp(xendev->type, type) != 0) {
> > +            continue;
> > +        }
> > +        return xendev;
> > +    }
> > +    return NULL;
> > +}
> > +
> > +/*
> > + * get xen backend device, allocate a new one if it doesn't exist.
> > + */
> > +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> > +                                    struct XenDevOps *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    xendev = xen_find_xendev(type, dom, dev);
> > +    if (xendev) {
> > +        return xendev;
> > +    }
> > +
> > +    /* init new xendev */
> > +    xendev = g_malloc0(ops->size);
> > +    xendev->type  = type;
> > +    xendev->dom   = dom;
> > +    xendev->dev   = dev;
> > +    xendev->ops   = ops;
> > +
> > +    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
> > +             xendev->type, xendev->dom, xendev->dev);
> > +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > +             xendev->type, xendev->dev);
> > +
> > +    xendev->debug      = debug;
> > +    xendev->local_port = -1;
> > +
> > +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > +        g_free(xendev);
> > +        return NULL;
> > +    }
> > +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > +
> > +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > +            xc_evtchn_close(xendev->evtchndev);
> > +            g_free(xendev);
> > +            return NULL;
> > +        }
> > +    } else {
> > +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > +    }
> > +
> > +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > +
> > +    if (xendev->ops->alloc) {
> > +        xendev->ops->alloc(xendev);
> > +    }
> > +
> > +    return xendev;
> > +}
> 
> Only functions that are shared between frontends and backends should be
> here, like xen_find_xendev. Otherwise there is no benefit in moving them
> to a separete, shared, source file.
> 
> 
> > +/*
> > + * get xen fe device, allocate a new one if it doesn't exist.
> > + */
> > +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> > +                                    char *backend, struct XenDevOps
> *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +
> > +    xendev = xen_find_xendev(type, dom, dev);
> > +    if (xendev) {
> > +        return xendev;
> > +    }
> > +
> > +    /* init new xendev */
> > +    xendev = g_malloc0(ops->size);
> > +    xendev->type  = type;
> > +    xendev->dom   = dom;
> > +    xendev->dev   = dev;
> > +    xendev->ops   = ops;
> > +
> > +    /*return if the ops->flags is not DEVOPS_FLAG_FE*/
> > +    if (!(ops->flags & DEVOPS_FLAG_FE)) {
> > +        return NULL;
> > +    }
> > +
> > +    snprintf(xendev->be, sizeof(xendev->be), "%s", backend);
> > +    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
> > +             xendev->type, xendev->dev);
> > +
> > +    xendev->debug = debug;
> > +    xendev->local_port = -1;
> > +
> > +    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
> > +    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
> > +        xen_be_printf(NULL, 0, "can't open evtchn device\n");
> > +        g_free(xendev);
> > +        return NULL;
> > +    }
> > +    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
> > +
> > +    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
> > +        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
> > +        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
> > +            xen_be_printf(NULL, 0, "can't open gnttab device\n");
> > +            xc_evtchn_close(xendev->evtchndev);
> > +            g_free(xendev);
> > +            return NULL;
> > +        }
> > +    } else {
> > +        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
> > +    }
> > +
> > +    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
> > +
> > +    if (xendev->ops->alloc) {
> > +        xendev->ops->alloc(xendev);
> > +    }
> > +
> > +    return xendev;
> > +}
> 
> same here
> 
> 
> > +/*
> > + * release xen device
> > + */
> > +
> > +struct XenDevice *xen_del_xendev(int dom, int dev)
> > +{
> > +    struct XenDevice *xendev, *xnext;
> > +
> > +    /*
> > +     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next)
> but
> > +     * we save the next pointer in xnext because we might free xendev.
> > +     */
> > +    xnext = xendevs.tqh_first;
> > +    while (xnext) {
> > +        xendev = xnext;
> > +        xnext = xendev->next.tqe_next;
> > +
> > +        if (xendev->dom != dom) {
> > +            continue;
> > +        }
> > +        if (xendev->dev != dev && dev != -1) {
> > +            continue;
> > +        }
> > +
> > +        if (xendev->ops->free) {
> > +            xendev->ops->free(xendev);
> > +        }
> > +
> > +        if (xendev->fe) {
> > +            char token[XEN_BUFSIZE];
> > +            snprintf(token, sizeof(token), "fe:%p", xendev);
> > +            xs_unwatch(xenstore, xendev->fe, token);
> > +            g_free(xendev->fe);
> > +        }
> > +
> > +        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
> > +            xc_evtchn_close(xendev->evtchndev);
> > +        }
> > +        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
> > +            xc_gnttab_close(xendev->gnttabdev);
> > +        }
> > +
> > +        QTAILQ_REMOVE(&xendevs, xendev, next);
> > +        g_free(xendev);
> > +    }
> > +    return NULL;
> > +}
> > +
> > +/* ------------------------------------------------------------- */
> > +
> > +int xenstore_write_str(const char *base, const char *node, const char *val)
> > +{
> > +    char abspath[XEN_BUFSIZE];
> > +
> > +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > +    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
> > +        return -1;
> > +    }
> > +    return 0;
> > +}
> > +
> > +char *xenstore_read_str(const char *base, const char *node)
> > +{
> > +    char abspath[XEN_BUFSIZE];
> > +    unsigned int len;
> > +    char *str, *ret = NULL;
> > +
> > +    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
> > +    str = xs_read(xenstore, 0, abspath, &len);
> > +    if (str != NULL) {
> > +        /* move to qemu-allocated memory to make sure
> > +         * callers can savely g_free() stuff. */
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +    return ret;
> > +}
> > +
> > +int xenstore_write_int(const char *base, const char *node, int ival)
> > +{
> > +    char val[12];
> > +
> > +    snprintf(val, sizeof(val), "%d", ival);
> > +    return xenstore_write_str(base, node, val);
> > +}
> > +
> > +int xenstore_write_int64(const char *base, const char *node, int64_t ival)
> > +{
> > +    char val[21];
> > +
> > +    snprintf(val, sizeof(val), "%"PRId64, ival);
> > +    return xenstore_write_str(base, node, val);
> > +}
> > +
> > +int xenstore_read_int(const char *base, const char *node, int *ival)
> > +{
> > +    char *val;
> > +    int rc = -1;
> > +
> > +    val = xenstore_read_str(base, node);
> > +    if (val && 1 == sscanf(val, "%d", ival)) {
> > +        rc = 0;
> > +    }
> > +    g_free(val);
> > +    return rc;
> > +}
> > +
> > +int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
> > +{
> > +    char *val;
> > +    int rc = -1;
> > +
> > +    val = xenstore_read_str(base, node);
> > +    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
> > +        rc = 0;
> > +    }
> > +    g_free(val);
> > +    return rc;
> > +}
> > +
> > +char *xenstore_get_domain_name(uint32_t domid)
> > +{
> > +    char *dom_path, *str, *ret = NULL;;
> > +
> > +    dom_path = xs_get_domain_path(xenstore, domid);
> > +    str = xenstore_read_str(dom_path, "name");
> > +    free(dom_path);
> > +    if (str != NULL) {
> > +        ret = g_strdup(str);
> > +        free(str);
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> > +/*
> > + * Sync internal data structures on xenstore updates.
> > + * Node specifies the changed field.  node = NULL means
> > + * update all fields (used for initialization).
> > + */
> > +void xen_be_backend_changed(struct XenDevice *xendev, const char
> *node)
> > +{
> > +    if (node == NULL  ||  strcmp(node, "online") == 0) {
> > +        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
> {
> > +            xendev->online = 0;
> > +        }
> > +    }
> > +
> > +    if (node) {
> > +        xen_be_printf(xendev, 2, "backend update: %s\n", node);
> > +        if (xendev->ops->backend_changed) {
> > +            xendev->ops->backend_changed(xendev, node);
> > +        }
> > +    }
> > +}
> > +
> > +void xen_be_frontend_changed(struct XenDevice *xendev, const char
> *node)
> > +{
> > +    int fe_state;
> > +
> > +    if (node == NULL  ||  strcmp(node, "state") == 0) {
> > +        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
> > +            fe_state = XenbusStateUnknown;
> > +        }
> > +        if (xendev->fe_state != fe_state) {
> > +            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
> > +                          xenbus_strstate(xendev->fe_state),
> > +                          xenbus_strstate(fe_state));
> > +        }
> > +        xendev->fe_state = fe_state;
> > +    }
> > +    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
> > +        g_free(xendev->protocol);
> > +        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
> > +        if (xendev->protocol) {
> > +            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
> > +                          xendev->protocol);
> > +        }
> > +    }
> > +
> > +    if (node) {
> > +        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
> > +        if (xendev->ops->frontend_changed) {
> > +            xendev->ops->frontend_changed(xendev, node);
> > +        }
> > +    }
> > +}
> 
> Anything backend or frontend specific, like these two functions, should either:
> 
> 1) be made generic, shared between frontends and backends, moved to this file
> 2) left in the corresponding xen_backend.c or xen_frontend.c source file
> 
> The first option is better, when possible.
> 
> 
> > +static void xenstore_update_be(char *watch, char *type, int dom,
> > +                        struct XenDevOps *ops)
> > +{
> > +    struct XenDevice *xendev;
> > +    char path[XEN_BUFSIZE], *bepath;
> > +    unsigned int len, dev;
> > +
> > +    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
> > +
> > +    if (strstr(watch, path) == NULL) {
> > +        return;
> > +    }
> > +    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
> > +        strcpy(path, "");
> > +        if (sscanf(watch+len, "/%u", &dev) != 1) {
> > +            dev = -1;
> > +        }
> > +    }
> > +    if (dev == -1) {
> > +        return;
> > +    }
> > +
> > +    xendev = xen_be_get_xendev(type, dom, dev, ops);
> > +    if (xendev != NULL) {
> > +        bepath = xs_read(xenstore, 0, xendev->be, &len);
> > +        if (bepath == NULL) {
> > +            xen_del_xendev(dom, dev);
> > +        } else {
> > +            free(bepath);
> > +            xen_be_backend_changed(xendev, path);
> > +            if (!(ops->flags & DEVOPS_FLAG_FE)) {
> > +                xen_be_check_state(xendev);
> > +            }
> > +        }
> > +    }
> > +}
> > +
> > +static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
> > +{
> > +    char *node;
> > +    unsigned int len;
> > +
> > +    len = strlen(xendev->fe);
> > +    if (strncmp(xendev->fe, watch, len) != 0) {
> > +        return;
> > +    }
> > +    if (watch[len] != '/') {
> > +        return;
> > +    }
> > +    node = watch + len + 1;
> > +
> > +    xen_be_frontend_changed(xendev, node);
> > +    xen_be_check_state(xendev);
> > +}
> > +
> > +static void xenstore_update(void *unused)
> > +{
> > +    char **vec = NULL;
> > +    intptr_t type, ops, ptr;
> > +    unsigned int dom, count;
> > +
> > +    vec = xs_read_watch(xenstore, &count);
> > +    if (vec == NULL) {
> > +        goto cleanup;
> > +    }
> > +
> > +    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
> > +               &type, &dom, &ops) == 3) {
> > +        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom,
> (void *)ops);
> > +    }
> > +    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
> > +        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
> > +    }
> > +
> > +cleanup:
> > +    free(vec);
> > +}
> > +
> > +int xen_be_init(void)
> > +{
> > +    xenstore = xs_daemon_open();
> > +    if (!xenstore) {
> > +        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
> > +        return -1;
> > +    }
> > +
> > +    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update,
> > +        NULL, NULL) < 0) {
> > +        goto err;
> > +    }
> > +
> > +    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
> > +
> > +        /* Check if xen_init() have been called */
> > +        goto err;
> > +    }
> > +    return 0;
> > +
> > +err:
> > +    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
> > +    xs_daemon_close(xenstore);
> > +    xenstore = NULL;
> > +
> > +    return -1;
> > +}
> > diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
> > index 3b4125e..bb0b303 100644
> > --- a/include/hw/xen/xen_backend.h
> > +++ b/include/hw/xen/xen_backend.h
> > @@ -15,6 +15,8 @@ struct XenDevice;
> >  #define DEVOPS_FLAG_NEED_GNTDEV   1
> >  /* don't expect frontend doing correct state transitions (aka console quirk) */
> >  #define DEVOPS_FLAG_IGNORE_STATE  2
> > +/*dev is frontend device*/
> > +#define DEVOPS_FLAG_FE            4
> >
> >  struct XenDevOps {
> >      size_t    size;
> > @@ -59,6 +61,7 @@ struct XenDevice {
> >  extern XenXC xen_xc;
> >  extern struct xs_handle *xenstore;
> >  extern const char *xen_protocol;
> > +extern int xenstore_dev;
> >
> >  /* xenstore helper functions */
> >  int xenstore_write_str(const char *base, const char *node, const char *val);
> > @@ -77,9 +80,18 @@ int xenstore_read_fe_int(struct XenDevice *xendev,
> const char *node, int *ival);
> >  int xenstore_read_uint64(const char *base, const char *node, uint64_t
> *uval);
> >  int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
> uint64_t *uval);
> >
> > +char *xenstore_get_domain_name(uint32_t domid);
> > +
> >  const char *xenbus_strstate(enum xenbus_state state);
> > -struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
> > +struct XenDevice *xen_find_xendev(const char *type, int dom, int dev);
> > +struct XenDevice *xen_del_xendev(int dom, int dev);
> > +struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
> > +                                    struct XenDevOps *ops);
> > +struct XenDevice *xen_fe_get_xendev(const char *type, int dom, int dev,
> > +                                    char *backend, struct XenDevOps
> *ops);
> >  void xen_be_check_state(struct XenDevice *xendev);
> > +void xen_be_backend_changed(struct XenDevice *xendev, const char
> *node);
> > +void xen_be_frontend_changed(struct XenDevice *xendev, const char
> *node);
> >
> >  /* xen backend driver bits */
> >  int xen_be_init(void);
> > @@ -90,6 +102,13 @@ void xen_be_unbind_evtchn(struct XenDevice
> *xendev);
> >  int xen_be_send_notify(struct XenDevice *xendev);
> >  void xen_be_printf(struct XenDevice *xendev, int msg_level, const char
> *fmt, ...)
> >      GCC_FMT_ATTR(3, 4);
> > +void xen_fe_printf(struct XenDevice *xendev, int msg_level,
> > +                   const char *fmt, ...)
> > +    GCC_FMT_ATTR(3, 4);
> > +/* Xen frontend driver */
> > +int xen_fe_register(const char *type, struct XenDevOps *ops);
> > +int xen_fe_alloc_unbound(struct XenDevice *xendev, int dom, int
> remote_dom);
> > +int xenbus_switch_state(struct XenDevice *xendev, enum xenbus_state
> xbus);
> >
> >  /* actual backend drivers */
> >  extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
> > @@ -97,6 +116,7 @@ extern struct XenDevOps xen_kbdmouse_ops;     /*
> xen_framebuffer.c */
> >  extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
> >  extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
> >  extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
> > +extern struct XenDevOps xen_vtpmdev_ops;      /*
> xen_vtpm_frontend.c*/
> >
> >  void xen_init_display(int domid);
> >
> > --
> > 1.8.3.2
> >
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

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

* Re: [Qemu-devel] [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-12  1:28     ` [Qemu-devel] [Xen-devel] " Xu, Quan
@ 2015-05-12 14:12       ` Stefano Stabellini
  2015-05-12 14:12       ` Stefano Stabellini
  1 sibling, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-12 14:12 UTC (permalink / raw)
  To: Xu, Quan
  Cc: wei.liu2, stefanb, Stefano Stabellini, qemu-devel, xen-devel, dgdegra

On Tue, 12 May 2015, Xu, Quan wrote:
> > -----Original Message-----
> > From: xen-devel-bounces@lists.xen.org
> > [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of Stefano Stabellini
> > Sent: Friday, May 08, 2015 1:26 AM
> > To: Xu, Quan
> > Cc: wei.liu2@citrix.com; stefanb@linux.vnet.ibm.com;
> > stefano.stabellini@eu.citrix.com; qemu-devel@nongnu.org;
> > xen-devel@lists.xen.org; dgdegra@tycho.nsa.gov; eblake@redhat.com
> > Subject: Re: [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver
> > infrastructure
> > 
> > On Mon, 4 May 2015, Quan Xu wrote:
> > > This patch adds infrastructure for xen front drivers living in qemu,
> > > so drivers don't need to implement common stuff on their own.  It's
> > > mostly xenbus management stuff: some functions to access XenStore,
> > > setting up XenStore watches, callbacks on device discovery and state
> > > changes, and handle event channel between the virtual machines.
> > >
> > > Call xen_fe_register() function to register XenDevOps, and make sure,
> > > XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> > > the XenDevOps is Xen frontend.
> > >
> > > Create a new file xen_pvdev.c for some common part of xen frontend and
> > > backend, such as xendevs queue and xenstore update functions.
> > >
> > > Signed-off-by: Quan Xu <quan.xu@intel.com>
> > 
> > Better than the early versions, thanks.
> > 
> > However the patch is too big and it is too difficult to read as is.
> > Could you please split it in two: a patch that creates xen_pvdev.c and moves a
> > few functions from xen_backend.c to it and a second patch that introduces
> > xen_frontend.c.
> > 
> 
> Stefano,
>        I missed this comment. Sorry for that.
>        Agreed, also I think it is too big. I will do it in v8. 

Thanks! If you could also try to address the other comments on this
patch in v8, that would be great.

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

* Re: [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure
  2015-05-12  1:28     ` [Qemu-devel] [Xen-devel] " Xu, Quan
  2015-05-12 14:12       ` Stefano Stabellini
@ 2015-05-12 14:12       ` Stefano Stabellini
  1 sibling, 0 replies; 48+ messages in thread
From: Stefano Stabellini @ 2015-05-12 14:12 UTC (permalink / raw)
  To: Xu, Quan
  Cc: wei.liu2, stefanb, Stefano Stabellini, qemu-devel, xen-devel,
	dgdegra, eblake

On Tue, 12 May 2015, Xu, Quan wrote:
> > -----Original Message-----
> > From: xen-devel-bounces@lists.xen.org
> > [mailto:xen-devel-bounces@lists.xen.org] On Behalf Of Stefano Stabellini
> > Sent: Friday, May 08, 2015 1:26 AM
> > To: Xu, Quan
> > Cc: wei.liu2@citrix.com; stefanb@linux.vnet.ibm.com;
> > stefano.stabellini@eu.citrix.com; qemu-devel@nongnu.org;
> > xen-devel@lists.xen.org; dgdegra@tycho.nsa.gov; eblake@redhat.com
> > Subject: Re: [Xen-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver
> > infrastructure
> > 
> > On Mon, 4 May 2015, Quan Xu wrote:
> > > This patch adds infrastructure for xen front drivers living in qemu,
> > > so drivers don't need to implement common stuff on their own.  It's
> > > mostly xenbus management stuff: some functions to access XenStore,
> > > setting up XenStore watches, callbacks on device discovery and state
> > > changes, and handle event channel between the virtual machines.
> > >
> > > Call xen_fe_register() function to register XenDevOps, and make sure,
> > > XenDevOps's flags is DEVOPS_FLAG_FE, which is flag bit to point out
> > > the XenDevOps is Xen frontend.
> > >
> > > Create a new file xen_pvdev.c for some common part of xen frontend and
> > > backend, such as xendevs queue and xenstore update functions.
> > >
> > > Signed-off-by: Quan Xu <quan.xu@intel.com>
> > 
> > Better than the early versions, thanks.
> > 
> > However the patch is too big and it is too difficult to read as is.
> > Could you please split it in two: a patch that creates xen_pvdev.c and moves a
> > few functions from xen_backend.c to it and a second patch that introduces
> > xen_frontend.c.
> > 
> 
> Stefano,
>        I missed this comment. Sorry for that.
>        Agreed, also I think it is too big. I will do it in v8. 

Thanks! If you could also try to address the other comments on this
patch in v8, that would be great.

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

end of thread, other threads:[~2015-05-12 14:14 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-04  7:22 [Qemu-devel] [PATCH v6 0/6] QEMU:Xen stubdom vTPM for HVM virtual machine(QEMU Part) Quan Xu
2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 1/6] Qemu-Xen-vTPM: Support for Xen stubdom vTPM command line options Quan Xu
2015-05-05 14:28   ` Eric Blake
2015-05-05 14:28   ` [Qemu-devel] " Eric Blake
2015-05-06  2:02     ` Xu, Quan
2015-05-06  2:02     ` Xu, Quan
2015-05-04  7:22 ` Quan Xu
2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 2/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure Quan Xu
2015-05-04  7:22   ` Quan Xu
2015-05-07 17:25   ` Stefano Stabellini
2015-05-07 17:25   ` [Qemu-devel] " Stefano Stabellini
2015-05-12  1:28     ` Xu, Quan
2015-05-12  1:28     ` [Qemu-devel] [Xen-devel] " Xu, Quan
2015-05-12 14:12       ` Stefano Stabellini
2015-05-12 14:12       ` Stefano Stabellini
2015-05-08  9:52   ` [Qemu-devel] " Stefano Stabellini
2015-05-08  9:52     ` Stefano Stabellini
2015-05-04  7:22 ` [Qemu-devel] [PATCH v6 3/6] " Quan Xu
2015-05-04  7:22   ` Quan Xu
2015-05-04 12:57   ` [Qemu-devel] " Xu, Quan
2015-05-04 12:57   ` Xu, Quan
2015-05-04 15:36   ` Stefan Berger
2015-05-04 15:36   ` [Qemu-devel] " Stefan Berger
2015-05-05  2:41     ` Xu, Quan
2015-05-05  2:41     ` [Qemu-devel] " Xu, Quan
2015-05-05 10:23       ` Stefan Berger
2015-05-11 12:56     ` Xu, Quan
2015-05-11 12:56       ` Xu, Quan
2015-05-11 14:49       ` [Qemu-devel] " Stefan Berger
2015-05-11 14:51         ` Xu, Quan
2015-05-11 14:51         ` [Qemu-devel] " Xu, Quan
2015-05-11 14:49       ` Stefan Berger
2015-05-08  9:52   ` [Qemu-devel] " Stefano Stabellini
2015-05-08  9:52     ` Stefano Stabellini
2015-05-04  7:22 ` [PATCH v6 4/6] Qemu-Xen-vTPM: Move tpm_passthrough_is_selftest() into tpm_util.c Quan Xu
2015-05-04  7:22 ` [Qemu-devel] " Quan Xu
2015-05-04 15:25   ` Stefan Berger
2015-05-04 15:25   ` [Qemu-devel] " Stefan Berger
2015-05-05  2:33     ` Xu, Quan
2015-05-05  2:33     ` Xu, Quan
2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 5/6] Qemu-Xen-vTPM: Qemu vTPM xenstubdoms backen Quan Xu
2015-05-04 15:30   ` Stefan Berger
2015-05-05  2:34     ` Xu, Quan
2015-05-05  2:34     ` Xu, Quan
2015-05-04 15:30   ` Stefan Berger
2015-05-04  7:23 ` Quan Xu
2015-05-04  7:23 ` [Qemu-devel] [PATCH v6 6/6] Qemu-Xen-vTPM: QEMU machine class is initialized before tpm_init() Quan Xu
2015-05-04  7:23   ` Quan Xu

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.