All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org, maxim.uvarov@linaro.org,
	joakim.bech@linaro.org, ilias.apalodimas@linaro.org,
	tomas.winkler@intel.com, yang.huang@intel.com,
	bing.zhu@intel.com, Matti.Moell@opensynergy.com,
	hmo@opensynergy.com
Cc: "Kevin Wolf" <kwolf@redhat.com>,
	jean-philippe@linaro.org,
	"open list:Block layer core" <qemu-block@nongnu.org>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Max Reitz" <mreitz@redhat.com>,
	takahiro.akashi@linaro.org,
	virtualization@lists.linuxfoundation.org,
	"Alex Bennée" <alex.bennee@linaro.org>,
	arnd@linaro.org, stratos-dev@op-lists.linaro.org
Subject: [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device
Date: Fri, 25 Sep 2020 13:51:30 +0100	[thread overview]
Message-ID: <20200925125147.26943-3-alex.bennee@linaro.org> (raw)
In-Reply-To: <20200925125147.26943-1-alex.bennee@linaro.org>

This creates the QEMU side of the vhost-user-rpmb device which
connects to the remote daemon. It is based of the reasonably modern
vhost-user-fs code with bits from vhost-user-blk as we want the
virtio-config itself to be sourced from the daemon.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/hw/virtio/vhost-user-rpmb.h |  46 ++++
 hw/block/vhost-user-rpmb.c          | 333 ++++++++++++++++++++++++++++
 hw/block/Kconfig                    |   5 +
 hw/block/meson.build                |   1 +
 4 files changed, 385 insertions(+)
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 create mode 100644 hw/block/vhost-user-rpmb.c

diff --git a/include/hw/virtio/vhost-user-rpmb.h b/include/hw/virtio/vhost-user-rpmb.h
new file mode 100644
index 000000000000..7e5988127dc2
--- /dev/null
+++ b/include/hw/virtio/vhost-user-rpmb.h
@@ -0,0 +1,46 @@
+/*
+ * vhost-user-rpmb virtio device
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _VHOST_USER_RPMB_H_
+#define _VHOST_USER_RPMB_H_
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_VHOST_USER_RPMB "vhost-user-rpmb-device"
+#define VHOST_USER_RPMB(obj) \
+        OBJECT_CHECK(VHostUserRPMB, (obj), TYPE_VHOST_USER_RPMB)
+
+/* This is defined in the VIRTIO spec */
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+typedef struct {
+    CharBackend chardev;
+    struct virtio_rpmb_config config;
+} VHostUserRPMBConf;
+
+typedef struct {
+    /*< private >*/
+    VirtIODevice parent;
+    VHostUserRPMBConf conf;
+    struct vhost_virtqueue *vhost_vq;
+    struct vhost_dev vhost_dev;
+    VhostUserState vhost_user;
+    VirtQueue *req_vq;
+    bool connected;
+    /*< public >*/
+} VHostUserRPMB;
+
+
+#endif /* _VHOST_USER_RPMB_H_ */
diff --git a/hw/block/vhost-user-rpmb.c b/hw/block/vhost-user-rpmb.c
new file mode 100644
index 000000000000..de243e7a53a0
--- /dev/null
+++ b/hw/block/vhost-user-rpmb.c
@@ -0,0 +1,333 @@
+/*
+ * Vhost-user RPMB virtio device
+ *
+ * This is the boilerplate for instantiating a vhost-user device
+ * implementing a Replay Protected Memory Block (RPMB) device. This is
+ * a type of flash chip that is protected from replay attacks and used
+ * for tamper resistant storage. The actual back-end for this driver
+ * is the vhost-user-rpmb daemon. The code here just connects up the
+ * device in QEMU and allows it to be instantiated.
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "qemu/error-report.h"
+
+/* currently there is no RPMB driver in Linux */
+#define VIRTIO_ID_RPMB         28 /* virtio RPMB */
+
+static void vurpmb_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    /* this somehow needs to come from the vhost-user daemon */
+}
+
+static void vurpmb_start(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+    int i;
+
+    if (!k->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        return;
+    }
+
+    ret = vhost_dev_enable_notifiers(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error enabling host notifiers: %d", -ret);
+        return;
+    }
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Error binding guest notifier: %d", -ret);
+        goto err_host_notifiers;
+    }
+
+    rpmb->vhost_dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error starting vhost-user-rpmb: %d", -ret);
+        goto err_guest_notifiers;
+    }
+
+    /*
+     * guest_notifier_mask/pending not used yet, so just unmask
+     * everything here.  virtio-pci will do the right thing by
+     * enabling/disabling irqfd.
+     */
+    for (i = 0; i < rpmb->vhost_dev.nvqs; i++) {
+        vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, i, false);
+    }
+
+    return;
+
+err_guest_notifiers:
+    k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+err_host_notifiers:
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_stop(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+
+    if (!k->set_guest_notifiers) {
+        return;
+    }
+
+    vhost_dev_stop(&rpmb->vhost_dev, vdev);
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+    if (ret < 0) {
+        error_report("vhost guest notifier cleanup failed: %d", ret);
+        return;
+    }
+
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+
+    if (!vdev->vm_running) {
+        should_start = false;
+    }
+
+    if (rpmb->vhost_dev.started == should_start) {
+        return;
+    }
+
+    if (should_start) {
+        vurpmb_start(vdev);
+    } else {
+        vurpmb_stop(vdev);
+    }
+}
+
+static uint64_t vurpmb_get_features(VirtIODevice *vdev,
+                                      uint64_t requested_features,
+                                      Error **errp)
+{
+    /* No feature bits used yet */
+    return requested_features;
+}
+
+static void vurpmb_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /*
+     * Not normally called; it's the daemon that handles the queue;
+     * however virtio's cleanup path can call this.
+     */
+}
+
+static void vurpmb_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                            bool mask)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, idx, mask);
+}
+
+static bool vurpmb_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    return vhost_virtqueue_pending(&rpmb->vhost_dev, idx);
+}
+
+/*
+ * Chardev connect/disconnect events
+ */
+
+static int vurpmb_handle_config_change(struct vhost_dev *dev)
+{
+    int ret;
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev->vdev);
+
+    ret = vhost_dev_get_config(dev, (uint8_t *)&rpmb->conf.config,
+                               sizeof(struct virtio_rpmb_config));
+    if (ret < 0) {
+        error_report("get config space failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+const VhostDevConfigOps rpmb_ops = {
+    .vhost_dev_config_notifier = vurpmb_handle_config_change,
+};
+
+static int vurpmb_connect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (rpmb->connected) {
+        return 0;
+    }
+    rpmb->connected = true;
+
+    /* restore vhost state */
+    if (virtio_device_started(vdev, vdev->status)) {
+        vurpmb_start(vdev);
+    }
+
+    return 0;
+}
+
+static void vurpmb_disconnect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (!rpmb->connected) {
+        return;
+    }
+    rpmb->connected = false;
+
+    if (rpmb->vhost_dev.started) {
+        vurpmb_stop(vdev);
+    }
+
+    vhost_dev_cleanup(&rpmb->vhost_dev);
+}
+
+static void vurpmb_event(void *opaque, QEMUChrEvent event)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (vurpmb_connect(dev) < 0) {
+            qemu_chr_fe_disconnect(&rpmb->conf.chardev);
+            return;
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        vurpmb_disconnect(dev);
+        break;
+    case CHR_EVENT_BREAK:
+    case CHR_EVENT_MUX_IN:
+    case CHR_EVENT_MUX_OUT:
+        /* Ignore */
+        break;
+    }
+}
+
+static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserRPMB *rpmb)
+{
+    vhost_user_cleanup(&rpmb->vhost_user);
+    virtio_delete_queue(rpmb->req_vq);
+    virtio_cleanup(vdev);
+    g_free(rpmb->vhost_dev.vqs);
+    rpmb->vhost_dev.vqs = NULL;
+}
+
+
+static void vurpmb_device_realize(DeviceState *dev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+    int ret;
+
+    if (!rpmb->conf.chardev.chr) {
+        error_setg(errp, "missing chardev");
+        return;
+    }
+
+    if (!vhost_user_init(&rpmb->vhost_user, &rpmb->conf.chardev, errp)) {
+        return;
+    }
+
+    virtio_init(vdev, "vhost-user-rpmb", VIRTIO_ID_RPMB,
+                sizeof(struct virtio_rpmb_config));
+
+    /* One request queue, 4 elements in case we don't do indirect */
+    rpmb->req_vq = virtio_add_queue(vdev, 4, vurpmb_handle_output);
+    rpmb->vhost_dev.nvqs = 1;
+    rpmb->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rpmb->vhost_dev.nvqs);
+    ret = vhost_dev_init(&rpmb->vhost_dev, &rpmb->vhost_user,
+                         VHOST_BACKEND_TYPE_USER, 0);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost_dev_init failed");
+        do_vhost_user_cleanup(vdev, rpmb);
+    }
+
+    /*
+     * At this point the next event we will get is a connection from
+     * the daemon on the control socket.
+     */
+
+    qemu_chr_fe_set_handlers(&rpmb->conf.chardev,  NULL, NULL, vurpmb_event,
+                             NULL, (void *)dev, NULL, true);
+
+    return;
+}
+
+static void vurpmb_device_unrealize(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+
+    /* This will stop vhost backend if appropriate. */
+    vurpmb_set_status(vdev, 0);
+
+    do_vhost_user_cleanup(vdev, rpmb);
+}
+
+static const VMStateDescription vurpmb_vmstate = {
+    .name = "vhost-user-rpmb",
+    .unmigratable = 1,
+};
+
+static Property vurpmb_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserRPMB, conf.chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, vurpmb_properties);
+    dc->vmsd = &vurpmb_vmstate;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    vdc->realize = vurpmb_device_realize;
+    vdc->unrealize = vurpmb_device_unrealize;
+    vdc->get_features = vurpmb_get_features;
+    vdc->get_config = vurpmb_get_config;
+    vdc->set_status = vurpmb_set_status;
+    vdc->guest_notifier_mask = vurpmb_guest_notifier_mask;
+    vdc->guest_notifier_pending = vurpmb_guest_notifier_pending;
+}
+
+static const TypeInfo vurpmb_info = {
+    .name = TYPE_VHOST_USER_RPMB,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VHostUserRPMB),
+    .class_init = vurpmb_class_init,
+};
+
+static void vurpmb_register_types(void)
+{
+    type_register_static(&vurpmb_info);
+}
+
+type_init(vurpmb_register_types)
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 2d17f481adc6..12e21870847a 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -38,5 +38,10 @@ config VHOST_USER_BLK
     default y if VIRTIO_PCI
     depends on VIRTIO && VHOST_USER && LINUX
 
+config VHOST_USER_RPMB
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config SWIM
     bool
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 78cad8f7cba1..114222f18424 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -17,5 +17,6 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
+specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
 
 subdir('dataplane')
-- 
2.20.1



WARNING: multiple messages have this Message-ID (diff)
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org, maxim.uvarov@linaro.org,
	joakim.bech@linaro.org, ilias.apalodimas@linaro.org,
	tomas.winkler@intel.com, yang.huang@intel.com,
	bing.zhu@intel.com, Matti.Moell@opensynergy.com,
	hmo@opensynergy.com
Cc: jean-philippe@linaro.org,
	"open list:Block layer core" <qemu-block@nongnu.org>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Max Reitz <mreitz@redhat.com>,
	takahiro.akashi@linaro.org,
	virtualization@lists.linuxfoundation.org, arnd@linaro.org,
	stratos-dev@op-lists.linaro.org
Subject: [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device
Date: Fri, 25 Sep 2020 13:51:30 +0100	[thread overview]
Message-ID: <20200925125147.26943-3-alex.bennee@linaro.org> (raw)
In-Reply-To: <20200925125147.26943-1-alex.bennee@linaro.org>

This creates the QEMU side of the vhost-user-rpmb device which
connects to the remote daemon. It is based of the reasonably modern
vhost-user-fs code with bits from vhost-user-blk as we want the
virtio-config itself to be sourced from the daemon.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/hw/virtio/vhost-user-rpmb.h |  46 ++++
 hw/block/vhost-user-rpmb.c          | 333 ++++++++++++++++++++++++++++
 hw/block/Kconfig                    |   5 +
 hw/block/meson.build                |   1 +
 4 files changed, 385 insertions(+)
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 create mode 100644 hw/block/vhost-user-rpmb.c

diff --git a/include/hw/virtio/vhost-user-rpmb.h b/include/hw/virtio/vhost-user-rpmb.h
new file mode 100644
index 000000000000..7e5988127dc2
--- /dev/null
+++ b/include/hw/virtio/vhost-user-rpmb.h
@@ -0,0 +1,46 @@
+/*
+ * vhost-user-rpmb virtio device
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _VHOST_USER_RPMB_H_
+#define _VHOST_USER_RPMB_H_
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_VHOST_USER_RPMB "vhost-user-rpmb-device"
+#define VHOST_USER_RPMB(obj) \
+        OBJECT_CHECK(VHostUserRPMB, (obj), TYPE_VHOST_USER_RPMB)
+
+/* This is defined in the VIRTIO spec */
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+typedef struct {
+    CharBackend chardev;
+    struct virtio_rpmb_config config;
+} VHostUserRPMBConf;
+
+typedef struct {
+    /*< private >*/
+    VirtIODevice parent;
+    VHostUserRPMBConf conf;
+    struct vhost_virtqueue *vhost_vq;
+    struct vhost_dev vhost_dev;
+    VhostUserState vhost_user;
+    VirtQueue *req_vq;
+    bool connected;
+    /*< public >*/
+} VHostUserRPMB;
+
+
+#endif /* _VHOST_USER_RPMB_H_ */
diff --git a/hw/block/vhost-user-rpmb.c b/hw/block/vhost-user-rpmb.c
new file mode 100644
index 000000000000..de243e7a53a0
--- /dev/null
+++ b/hw/block/vhost-user-rpmb.c
@@ -0,0 +1,333 @@
+/*
+ * Vhost-user RPMB virtio device
+ *
+ * This is the boilerplate for instantiating a vhost-user device
+ * implementing a Replay Protected Memory Block (RPMB) device. This is
+ * a type of flash chip that is protected from replay attacks and used
+ * for tamper resistant storage. The actual back-end for this driver
+ * is the vhost-user-rpmb daemon. The code here just connects up the
+ * device in QEMU and allows it to be instantiated.
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "qemu/error-report.h"
+
+/* currently there is no RPMB driver in Linux */
+#define VIRTIO_ID_RPMB         28 /* virtio RPMB */
+
+static void vurpmb_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    /* this somehow needs to come from the vhost-user daemon */
+}
+
+static void vurpmb_start(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+    int i;
+
+    if (!k->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        return;
+    }
+
+    ret = vhost_dev_enable_notifiers(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error enabling host notifiers: %d", -ret);
+        return;
+    }
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Error binding guest notifier: %d", -ret);
+        goto err_host_notifiers;
+    }
+
+    rpmb->vhost_dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error starting vhost-user-rpmb: %d", -ret);
+        goto err_guest_notifiers;
+    }
+
+    /*
+     * guest_notifier_mask/pending not used yet, so just unmask
+     * everything here.  virtio-pci will do the right thing by
+     * enabling/disabling irqfd.
+     */
+    for (i = 0; i < rpmb->vhost_dev.nvqs; i++) {
+        vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, i, false);
+    }
+
+    return;
+
+err_guest_notifiers:
+    k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+err_host_notifiers:
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_stop(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+
+    if (!k->set_guest_notifiers) {
+        return;
+    }
+
+    vhost_dev_stop(&rpmb->vhost_dev, vdev);
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+    if (ret < 0) {
+        error_report("vhost guest notifier cleanup failed: %d", ret);
+        return;
+    }
+
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+
+    if (!vdev->vm_running) {
+        should_start = false;
+    }
+
+    if (rpmb->vhost_dev.started == should_start) {
+        return;
+    }
+
+    if (should_start) {
+        vurpmb_start(vdev);
+    } else {
+        vurpmb_stop(vdev);
+    }
+}
+
+static uint64_t vurpmb_get_features(VirtIODevice *vdev,
+                                      uint64_t requested_features,
+                                      Error **errp)
+{
+    /* No feature bits used yet */
+    return requested_features;
+}
+
+static void vurpmb_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /*
+     * Not normally called; it's the daemon that handles the queue;
+     * however virtio's cleanup path can call this.
+     */
+}
+
+static void vurpmb_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                            bool mask)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, idx, mask);
+}
+
+static bool vurpmb_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    return vhost_virtqueue_pending(&rpmb->vhost_dev, idx);
+}
+
+/*
+ * Chardev connect/disconnect events
+ */
+
+static int vurpmb_handle_config_change(struct vhost_dev *dev)
+{
+    int ret;
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev->vdev);
+
+    ret = vhost_dev_get_config(dev, (uint8_t *)&rpmb->conf.config,
+                               sizeof(struct virtio_rpmb_config));
+    if (ret < 0) {
+        error_report("get config space failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+const VhostDevConfigOps rpmb_ops = {
+    .vhost_dev_config_notifier = vurpmb_handle_config_change,
+};
+
+static int vurpmb_connect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (rpmb->connected) {
+        return 0;
+    }
+    rpmb->connected = true;
+
+    /* restore vhost state */
+    if (virtio_device_started(vdev, vdev->status)) {
+        vurpmb_start(vdev);
+    }
+
+    return 0;
+}
+
+static void vurpmb_disconnect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (!rpmb->connected) {
+        return;
+    }
+    rpmb->connected = false;
+
+    if (rpmb->vhost_dev.started) {
+        vurpmb_stop(vdev);
+    }
+
+    vhost_dev_cleanup(&rpmb->vhost_dev);
+}
+
+static void vurpmb_event(void *opaque, QEMUChrEvent event)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (vurpmb_connect(dev) < 0) {
+            qemu_chr_fe_disconnect(&rpmb->conf.chardev);
+            return;
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        vurpmb_disconnect(dev);
+        break;
+    case CHR_EVENT_BREAK:
+    case CHR_EVENT_MUX_IN:
+    case CHR_EVENT_MUX_OUT:
+        /* Ignore */
+        break;
+    }
+}
+
+static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserRPMB *rpmb)
+{
+    vhost_user_cleanup(&rpmb->vhost_user);
+    virtio_delete_queue(rpmb->req_vq);
+    virtio_cleanup(vdev);
+    g_free(rpmb->vhost_dev.vqs);
+    rpmb->vhost_dev.vqs = NULL;
+}
+
+
+static void vurpmb_device_realize(DeviceState *dev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+    int ret;
+
+    if (!rpmb->conf.chardev.chr) {
+        error_setg(errp, "missing chardev");
+        return;
+    }
+
+    if (!vhost_user_init(&rpmb->vhost_user, &rpmb->conf.chardev, errp)) {
+        return;
+    }
+
+    virtio_init(vdev, "vhost-user-rpmb", VIRTIO_ID_RPMB,
+                sizeof(struct virtio_rpmb_config));
+
+    /* One request queue, 4 elements in case we don't do indirect */
+    rpmb->req_vq = virtio_add_queue(vdev, 4, vurpmb_handle_output);
+    rpmb->vhost_dev.nvqs = 1;
+    rpmb->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rpmb->vhost_dev.nvqs);
+    ret = vhost_dev_init(&rpmb->vhost_dev, &rpmb->vhost_user,
+                         VHOST_BACKEND_TYPE_USER, 0);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost_dev_init failed");
+        do_vhost_user_cleanup(vdev, rpmb);
+    }
+
+    /*
+     * At this point the next event we will get is a connection from
+     * the daemon on the control socket.
+     */
+
+    qemu_chr_fe_set_handlers(&rpmb->conf.chardev,  NULL, NULL, vurpmb_event,
+                             NULL, (void *)dev, NULL, true);
+
+    return;
+}
+
+static void vurpmb_device_unrealize(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+
+    /* This will stop vhost backend if appropriate. */
+    vurpmb_set_status(vdev, 0);
+
+    do_vhost_user_cleanup(vdev, rpmb);
+}
+
+static const VMStateDescription vurpmb_vmstate = {
+    .name = "vhost-user-rpmb",
+    .unmigratable = 1,
+};
+
+static Property vurpmb_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserRPMB, conf.chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, vurpmb_properties);
+    dc->vmsd = &vurpmb_vmstate;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    vdc->realize = vurpmb_device_realize;
+    vdc->unrealize = vurpmb_device_unrealize;
+    vdc->get_features = vurpmb_get_features;
+    vdc->get_config = vurpmb_get_config;
+    vdc->set_status = vurpmb_set_status;
+    vdc->guest_notifier_mask = vurpmb_guest_notifier_mask;
+    vdc->guest_notifier_pending = vurpmb_guest_notifier_pending;
+}
+
+static const TypeInfo vurpmb_info = {
+    .name = TYPE_VHOST_USER_RPMB,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VHostUserRPMB),
+    .class_init = vurpmb_class_init,
+};
+
+static void vurpmb_register_types(void)
+{
+    type_register_static(&vurpmb_info);
+}
+
+type_init(vurpmb_register_types)
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 2d17f481adc6..12e21870847a 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -38,5 +38,10 @@ config VHOST_USER_BLK
     default y if VIRTIO_PCI
     depends on VIRTIO && VHOST_USER && LINUX
 
+config VHOST_USER_RPMB
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config SWIM
     bool
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 78cad8f7cba1..114222f18424 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -17,5 +17,6 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
+specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
 
 subdir('dataplane')
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

  parent reply	other threads:[~2020-09-25 12:53 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-25 12:51 [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) Alex Bennée
2020-09-25 12:51 ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 01/19] tools/virtiofsd: add support for --socket-group Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-10-07 10:48   ` Dr. David Alan Gilbert
2020-10-07 10:48     ` Dr. David Alan Gilbert
2020-09-25 12:51 ` Alex Bennée [this message]
2020-09-25 12:51   ` [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 03/19] hw/virtio: move virtio-pci.h into shared include space Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 04/19] hw/block: add vhost-user-rpmb-pci boilerplate Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 05/19] virtio-pci: add notification trace points Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 13:06   ` Philippe Mathieu-Daudé
2020-09-25 12:51 ` [RFC PATCH 06/19] tools/vhost-user-rpmb: add boilerplate and initial main Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 07/19] tools/vhost-user-rpmb: implement --print-capabilities Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 08/19] tools/vhost-user-rpmb: connect to fd and instantiate basic run loop Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 09/19] tools/vhost-user-rpmb: add a --verbose/debug flags for logging Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 10/19] tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 11/19] tools/vhost-user-rpmb: add --flash-path for backing store Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 12/19] tools/vhost-user-rpmb: import hmac_sha256 functions Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 14/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-28 13:52   ` Joakim Bech
2020-09-28 14:56     ` Alex Bennée
2020-09-28 14:56       ` Alex Bennée
2020-09-28 15:18       ` Joakim Bech
2020-09-25 12:51 ` [RFC PATCH 16/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 17/19] tools/vhost-user-rpmb: add key persistence Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 18/19] tools/vhost-user-rpmb: allow setting of the write_count Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 19/19] docs: add a man page for vhost-user-rpmb Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 14:07 ` [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200925125147.26943-3-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=Matti.Moell@opensynergy.com \
    --cc=arnd@linaro.org \
    --cc=bing.zhu@intel.com \
    --cc=hmo@opensynergy.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=jean-philippe@linaro.org \
    --cc=joakim.bech@linaro.org \
    --cc=kwolf@redhat.com \
    --cc=maxim.uvarov@linaro.org \
    --cc=mreitz@redhat.com \
    --cc=mst@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stratos-dev@op-lists.linaro.org \
    --cc=takahiro.akashi@linaro.org \
    --cc=tomas.winkler@intel.com \
    --cc=virtualization@lists.linuxfoundation.org \
    --cc=yang.huang@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.