1 #ifndef _VIRTIO_H_ 2 #define _VIRTIO_H_ 3 /* 4 * A minimal implementation of virtio. 5 * Structures adapted from the Linux Kernel. 6 * 7 * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. 10 */ 11 #include "libcflat.h" 12 13 #define VIRTIO_ID_CONSOLE 3 14 15 struct virtio_device_id { 16 u32 device; 17 u32 vendor; 18 }; 19 20 struct virtio_device { 21 struct virtio_device_id id; 22 const struct virtio_config_ops *config; 23 }; 24 25 struct virtqueue { 26 void (*callback)(struct virtqueue *vq); 27 const char *name; 28 struct virtio_device *vdev; 29 unsigned int index; 30 unsigned int num_free; 31 void *priv; 32 }; 33 34 typedef void vq_callback_t(struct virtqueue *); 35 struct virtio_config_ops { 36 void (*get)(struct virtio_device *vdev, unsigned offset, 37 void *buf, unsigned len); 38 void (*set)(struct virtio_device *vdev, unsigned offset, 39 const void *buf, unsigned len); 40 int (*find_vqs)(struct virtio_device *vdev, unsigned nvqs, 41 struct virtqueue *vqs[], 42 vq_callback_t *callbacks[], 43 const char *names[]); 44 }; 45 46 static inline u8 47 virtio_config_readb(struct virtio_device *vdev, unsigned offset) 48 { 49 u8 val; 50 vdev->config->get(vdev, offset, &val, 1); 51 return val; 52 } 53 54 static inline u16 55 virtio_config_readw(struct virtio_device *vdev, unsigned offset) 56 { 57 u16 val; 58 vdev->config->get(vdev, offset, &val, 2); 59 return val; 60 } 61 62 static inline u32 63 virtio_config_readl(struct virtio_device *vdev, unsigned offset) 64 { 65 u32 val; 66 vdev->config->get(vdev, offset, &val, 4); 67 return val; 68 } 69 70 static inline void 71 virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val) 72 { 73 vdev->config->set(vdev, offset, &val, 1); 74 } 75 76 static inline void 77 virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val) 78 { 79 vdev->config->set(vdev, offset, &val, 2); 80 } 81 82 static inline void 83 virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val) 84 { 85 vdev->config->set(vdev, offset, &val, 4); 86 } 87 88 #define VRING_DESC_F_NEXT 1 89 #define VRING_DESC_F_WRITE 2 90 91 struct vring_desc { 92 u64 addr; 93 u32 len; 94 u16 flags; 95 u16 next; 96 }; 97 98 struct vring_avail { 99 u16 flags; 100 u16 idx; 101 u16 ring[]; 102 }; 103 104 struct vring_used_elem { 105 u32 id; 106 u32 len; 107 }; 108 109 struct vring_used { 110 u16 flags; 111 u16 idx; 112 struct vring_used_elem ring[]; 113 }; 114 115 struct vring { 116 unsigned int num; 117 struct vring_desc *desc; 118 struct vring_avail *avail; 119 struct vring_used *used; 120 }; 121 122 struct vring_virtqueue { 123 struct virtqueue vq; 124 struct vring vring; 125 unsigned int free_head; 126 unsigned int num_added; 127 u16 last_used_idx; 128 bool (*notify)(struct virtqueue *vq); 129 void *data[]; 130 }; 131 132 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) 133 134 extern void vring_init(struct vring *vr, unsigned int num, void *p, 135 unsigned long align); 136 extern void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index, 137 unsigned num, unsigned vring_align, 138 struct virtio_device *vdev, void *pages, 139 bool (*notify)(struct virtqueue *), 140 void (*callback)(struct virtqueue *), 141 const char *name); 142 extern int virtqueue_add_outbuf(struct virtqueue *vq, char *buf, 143 unsigned int len); 144 extern bool virtqueue_kick(struct virtqueue *vq); 145 extern void detach_buf(struct vring_virtqueue *vq, unsigned head); 146 extern void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len); 147 148 extern struct virtio_device *virtio_bind(u32 devid); 149 150 #endif /* _VIRTIO_H_ */ 151