Spaces:
Runtime error
Runtime error
| /* | |
| * A minimal implementation of virtio. | |
| * Structures adapted from the Linux Kernel. | |
| * | |
| * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com> | |
| * | |
| * This work is licensed under the terms of the GNU GPL, version 2. | |
| */ | |
| 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); | |
| } | |
| 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[]; | |
| }; | |
| 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); | |