#ifndef _VIRTIO_H_ #define _VIRTIO_H_ /* * A minimal implementation of virtio. * Structures adapted from the Linux Kernel. * * Copyright (C) 2017, Red Hat Inc, Andrew Jones * * This work is licensed under the terms of the GNU GPL, version 2. */ #include "libcflat.h" #define VIRTIO_ID_CONSOLE 3 struct virtio_device_id { u32 device; u32 vendor; }; struct virtio_device { struct virtio_device_id id; const struct virtio_config_ops *config; }; struct virtqueue { void (*callback)(struct virtqueue *vq); const char *name; struct virtio_device *vdev; unsigned int index; unsigned int num_free; void *priv; }; typedef void vq_callback_t(struct virtqueue *); struct virtio_config_ops { void (*get)(struct virtio_device *vdev, unsigned offset, void *buf, unsigned len); void (*set)(struct virtio_device *vdev, unsigned offset, const void *buf, unsigned len); int (*find_vqs)(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], const char *names[]); }; static inline u8 virtio_config_readb(struct virtio_device *vdev, unsigned offset) { u8 val; vdev->config->get(vdev, offset, &val, 1); return val; } static inline u16 virtio_config_readw(struct virtio_device *vdev, unsigned offset) { u16 val; vdev->config->get(vdev, offset, &val, 2); return val; } static inline u32 virtio_config_readl(struct virtio_device *vdev, unsigned offset) { u32 val; vdev->config->get(vdev, offset, &val, 4); return val; } static inline void virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val) { vdev->config->set(vdev, offset, &val, 1); } static inline void virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val) { vdev->config->set(vdev, offset, &val, 2); } static inline void virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val) { vdev->config->set(vdev, offset, &val, 4); } #define VRING_DESC_F_NEXT 1 #define VRING_DESC_F_WRITE 2 struct vring_desc { u64 addr; u32 len; u16 flags; u16 next; }; struct vring_avail { u16 flags; u16 idx; u16 ring[]; }; struct vring_used_elem { u32 id; u32 len; }; struct vring_used { u16 flags; u16 idx; struct vring_used_elem ring[]; }; struct vring { unsigned int num; struct vring_desc *desc; struct vring_avail *avail; struct vring_used *used; }; struct vring_virtqueue { struct virtqueue vq; struct vring vring; unsigned int free_head; unsigned int num_added; u16 last_used_idx; bool (*notify)(struct virtqueue *vq); void *data[]; }; #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) extern void vring_init(struct vring *vr, unsigned int num, void *p, unsigned long align); extern void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index, unsigned num, unsigned vring_align, struct virtio_device *vdev, void *pages, bool (*notify)(struct virtqueue *), void (*callback)(struct virtqueue *), const char *name); extern int virtqueue_add_outbuf(struct virtqueue *vq, char *buf, unsigned int len); extern bool virtqueue_kick(struct virtqueue *vq); extern void detach_buf(struct vring_virtqueue *vq, unsigned head); extern void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len); extern struct virtio_device *virtio_bind(u32 devid); #endif /* _VIRTIO_H_ */