diff mbox

[v6,3/6] Qemu-Xen-vTPM: Xen frontend driver infrastructure

Message ID 1430724181-476-4-git-send-email-quan.xu@intel.com
State New
Headers show

Commit Message

Xu, Quan May 4, 2015, 7:22 a.m. UTC
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

Comments

Xu, Quan May 4, 2015, 12:57 p.m. UTC | #1
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
Stefan Berger May 4, 2015, 3:36 p.m. UTC | #2
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
Xu, Quan May 5, 2015, 2:41 a.m. UTC | #3
> -----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
Stefan Berger May 5, 2015, 10:23 a.m. UTC | #4
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
Stefano Stabellini May 8, 2015, 9:52 a.m. UTC | #5
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
>
Xu, Quan May 11, 2015, 12:56 p.m. UTC | #6
> -----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
Stefan Berger May 11, 2015, 2:49 p.m. UTC | #7
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
Xu, Quan May 11, 2015, 2:51 p.m. UTC | #8
> -----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
diff mbox

Patch

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);