Host independent implementation for virtio block devices. The host
dependent part of the host library must provide an implementation for
lkl_dev_block_ops.

Disks can be added to the LKL configuration via lkl_disk_add(), a new
LKL application API.

Signed-off-by: Octavian Purdila <octavian.purd...@intel.com>
---
 tools/lkl/include/lkl.h      |  20 ++++++++
 tools/lkl/include/lkl_host.h |  21 ++++++++
 tools/lkl/lib/virtio_blk.c   | 116 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+)
 create mode 100644 tools/lkl/lib/virtio_blk.c

diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h
index 958614d..0c30b23 100644
--- a/tools/lkl/include/lkl.h
+++ b/tools/lkl/include/lkl.h
@@ -20,4 +20,24 @@ static inline long lkl_sys_lseek(unsigned int fd, 
__lkl__kernel_loff_t off,
  */
 const char *lkl_strerror(int err);
 
+/**
+ * lkl_disk_backstore - host dependend disk backstore
+ *
+ * @fd - an open file descriptor that can be used by preadv/pwritev; used by
+ * POSIX hosts
+ */
+union lkl_disk_backstore {
+       int fd;
+};
+
+/**
+ * lkl_disk_add - add a new disk
+ *
+ * Must be called before calling lkl_start_kernel.
+ *
+ * @backstore - the disk backstore
+ * @returns a disk id (0 is valid) or a strictly negative value in case of 
error
+ */
+int lkl_disk_add(union lkl_disk_backstore backstore);
+
 #endif
diff --git a/tools/lkl/include/lkl_host.h b/tools/lkl/include/lkl_host.h
index 26d3e43..2dafaa8 100644
--- a/tools/lkl/include/lkl_host.h
+++ b/tools/lkl/include/lkl_host.h
@@ -20,4 +20,25 @@ struct lkl_dev_buf {
        unsigned int len;
 };
 
+extern struct lkl_dev_blk_ops lkl_dev_blk_ops;
+
+#define LKL_DEV_BLK_TYPE_READ          0
+#define LKL_DEV_BLK_TYPE_WRITE         1
+#define LKL_DEV_BLK_TYPE_FLUSH         4
+#define LKL_DEV_BLK_TYPE_FLUSH_OUT     5
+
+struct lkl_dev_blk_ops {
+       int (*get_capacity)(union lkl_disk_backstore bs,
+                           unsigned long long *res);
+       void (*request)(union lkl_disk_backstore bs, unsigned int type,
+                       unsigned int prio, unsigned long long sector,
+                       struct lkl_dev_buf *bufs, int count);
+};
+
+#define LKL_DEV_BLK_STATUS_OK          0
+#define LKL_DEV_BLK_STATUS_IOERR       1
+#define LKL_DEV_BLK_STATUS_UNSUP       2
+
+void lkl_dev_blk_complete(struct lkl_dev_buf *bufs, unsigned char status,
+                         int len);
 #endif
diff --git a/tools/lkl/lib/virtio_blk.c b/tools/lkl/lib/virtio_blk.c
new file mode 100644
index 0000000..3262f42
--- /dev/null
+++ b/tools/lkl/lib/virtio_blk.c
@@ -0,0 +1,116 @@
+#include <lkl_host.h>
+#include "virtio.h"
+
+struct virtio_blk_dev {
+       struct virtio_dev dev;
+       struct {
+               uint64_t capacity;
+       } config;
+       struct lkl_dev_blk_ops *ops;
+       union lkl_disk_backstore backstore;
+};
+
+struct virtio_blk_req_header {
+       uint32_t type;
+       uint32_t prio;
+       uint64_t sector;
+};
+
+struct virtio_blk_req_trailer {
+       uint8_t status;
+};
+
+static int blk_check_features(uint32_t features)
+{
+       if (!features)
+               return 0;
+
+       return -LKL_EINVAL;
+}
+
+void lkl_dev_blk_complete(struct lkl_dev_buf *bufs, unsigned char status,
+                         int len)
+{
+       struct virtio_dev_req *req;
+       struct virtio_blk_req_trailer *f;
+
+       req = container_of(bufs - 1, struct virtio_dev_req, buf);
+
+       if (req->buf_count < 2) {
+               lkl_printf("virtio_blk: no status buf\n");
+               return;
+       }
+
+       if (req->buf[req->buf_count - 1].len != sizeof(*f)) {
+               lkl_printf("virtio_blk: bad status buf\n");
+       } else {
+               f = req->buf[req->buf_count - 1].addr;
+               f->status = status;
+       }
+
+       virtio_dev_complete(req, len);
+}
+
+static void blk_queue(struct virtio_dev *dev, struct virtio_dev_req *req)
+{
+       struct virtio_blk_req_header *h;
+       struct virtio_blk_dev *blk_dev;
+
+       if (req->buf[0].len != sizeof(struct virtio_blk_req_header)) {
+               lkl_printf("virtio_blk: bad header buf\n");
+               lkl_dev_blk_complete(&req->buf[1], LKL_DEV_BLK_STATUS_UNSUP, 0);
+               return;
+       }
+
+       h = req->buf[0].addr;
+       blk_dev = container_of(dev, struct virtio_blk_dev, dev);
+
+       blk_dev->ops->request(blk_dev->backstore, le32toh(h->type),
+                             le32toh(h->prio), le32toh(h->sector),
+                             &req->buf[1], req->buf_count - 2);
+}
+
+static struct virtio_dev_ops blk_ops = {
+       .check_features = blk_check_features,
+       .queue = blk_queue,
+};
+
+int lkl_disk_add(union lkl_disk_backstore backstore)
+{
+       struct virtio_blk_dev *dev;
+       unsigned long long capacity;
+       int ret;
+       static int count;
+
+       dev = lkl_host_ops.mem_alloc(sizeof(*dev));
+       if (!dev)
+               return -LKL_ENOMEM;
+
+       dev->dev.device_id = 2;
+       dev->dev.vendor_id = 0;
+       dev->dev.device_features = 0;
+       dev->dev.config_gen = 0;
+       dev->dev.config_data = &dev->config;
+       dev->dev.config_len = sizeof(dev->config);
+       dev->dev.ops = &blk_ops;
+       dev->ops = &lkl_dev_blk_ops;
+       dev->backstore = backstore;
+
+       ret = dev->ops->get_capacity(backstore, &capacity);
+       if (ret) {
+               ret = -LKL_ENOMEM;
+               goto out_free;
+       }
+       dev->config.capacity = capacity;
+
+       ret = virtio_dev_setup(&dev->dev, 1, 65536);
+       if (ret)
+               goto out_free;
+
+       return count++;
+
+out_free:
+       lkl_host_ops.mem_free(dev);
+
+       return ret;
+}
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to