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
virtio_config_readb(struct virtio_device * vdev,unsigned offset)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
virtio_config_readw(struct virtio_device * vdev,unsigned offset)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
virtio_config_readl(struct virtio_device * vdev,unsigned offset)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
virtio_config_writeb(struct virtio_device * vdev,unsigned offset,u8 val)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
virtio_config_writew(struct virtio_device * vdev,unsigned offset,u16 val)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
virtio_config_writel(struct virtio_device * vdev,unsigned offset,u32 val)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