xref: /kvm-unit-tests/lib/virtio.h (revision 49f758b8a983e49b4537ea2726e8a83a0d5632ad)
143402ba5SAndrew Jones #ifndef _VIRTIO_H_
243402ba5SAndrew Jones #define _VIRTIO_H_
343402ba5SAndrew Jones /*
443402ba5SAndrew Jones  * A minimal implementation of virtio.
543402ba5SAndrew Jones  * Structures adapted from the Linux Kernel.
643402ba5SAndrew Jones  *
7*49f758b8SAndrew Jones  * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
843402ba5SAndrew Jones  *
9*49f758b8SAndrew Jones  * This work is licensed under the terms of the GNU GPL, version 2.
1043402ba5SAndrew Jones  */
1143402ba5SAndrew Jones #include "libcflat.h"
1243402ba5SAndrew Jones 
13b412ad0dSAndrew Jones #define VIRTIO_ID_CONSOLE 3
14b412ad0dSAndrew Jones 
1543402ba5SAndrew Jones struct virtio_device_id {
1643402ba5SAndrew Jones 	u32 device;
1743402ba5SAndrew Jones 	u32 vendor;
1843402ba5SAndrew Jones };
1943402ba5SAndrew Jones 
2043402ba5SAndrew Jones struct virtio_device {
2143402ba5SAndrew Jones 	struct virtio_device_id id;
2243402ba5SAndrew Jones 	const struct virtio_config_ops *config;
2343402ba5SAndrew Jones };
2443402ba5SAndrew Jones 
25d73e4521SAndrew Jones struct virtqueue {
26d73e4521SAndrew Jones 	void (*callback)(struct virtqueue *vq);
27d73e4521SAndrew Jones 	const char *name;
28d73e4521SAndrew Jones 	struct virtio_device *vdev;
29d73e4521SAndrew Jones 	unsigned int index;
30d73e4521SAndrew Jones 	unsigned int num_free;
31d73e4521SAndrew Jones 	void *priv;
32d73e4521SAndrew Jones };
33d73e4521SAndrew Jones 
34d73e4521SAndrew Jones typedef void vq_callback_t(struct virtqueue *);
3543402ba5SAndrew Jones struct virtio_config_ops {
3643402ba5SAndrew Jones 	void (*get)(struct virtio_device *vdev, unsigned offset,
3743402ba5SAndrew Jones 		    void *buf, unsigned len);
3843402ba5SAndrew Jones 	void (*set)(struct virtio_device *vdev, unsigned offset,
3943402ba5SAndrew Jones 		    const void *buf, unsigned len);
40d73e4521SAndrew Jones 	int (*find_vqs)(struct virtio_device *vdev, unsigned nvqs,
41d73e4521SAndrew Jones 			struct virtqueue *vqs[],
42d73e4521SAndrew Jones 			vq_callback_t *callbacks[],
43d73e4521SAndrew Jones 			const char *names[]);
4443402ba5SAndrew Jones };
4543402ba5SAndrew Jones 
4643402ba5SAndrew Jones static inline u8
virtio_config_readb(struct virtio_device * vdev,unsigned offset)4743402ba5SAndrew Jones virtio_config_readb(struct virtio_device *vdev, unsigned offset)
4843402ba5SAndrew Jones {
4943402ba5SAndrew Jones 	u8 val;
5043402ba5SAndrew Jones 	vdev->config->get(vdev, offset, &val, 1);
5143402ba5SAndrew Jones 	return val;
5243402ba5SAndrew Jones }
5343402ba5SAndrew Jones 
5443402ba5SAndrew Jones static inline u16
virtio_config_readw(struct virtio_device * vdev,unsigned offset)5543402ba5SAndrew Jones virtio_config_readw(struct virtio_device *vdev, unsigned offset)
5643402ba5SAndrew Jones {
5743402ba5SAndrew Jones 	u16 val;
5843402ba5SAndrew Jones 	vdev->config->get(vdev, offset, &val, 2);
5943402ba5SAndrew Jones 	return val;
6043402ba5SAndrew Jones }
6143402ba5SAndrew Jones 
6243402ba5SAndrew Jones static inline u32
virtio_config_readl(struct virtio_device * vdev,unsigned offset)6343402ba5SAndrew Jones virtio_config_readl(struct virtio_device *vdev, unsigned offset)
6443402ba5SAndrew Jones {
6543402ba5SAndrew Jones 	u32 val;
6643402ba5SAndrew Jones 	vdev->config->get(vdev, offset, &val, 4);
6743402ba5SAndrew Jones 	return val;
6843402ba5SAndrew Jones }
6943402ba5SAndrew Jones 
7043402ba5SAndrew Jones static inline void
virtio_config_writeb(struct virtio_device * vdev,unsigned offset,u8 val)7143402ba5SAndrew Jones virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val)
7243402ba5SAndrew Jones {
7343402ba5SAndrew Jones 	vdev->config->set(vdev, offset, &val, 1);
7443402ba5SAndrew Jones }
7543402ba5SAndrew Jones 
7643402ba5SAndrew Jones static inline void
virtio_config_writew(struct virtio_device * vdev,unsigned offset,u16 val)7743402ba5SAndrew Jones virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val)
7843402ba5SAndrew Jones {
7943402ba5SAndrew Jones 	vdev->config->set(vdev, offset, &val, 2);
8043402ba5SAndrew Jones }
8143402ba5SAndrew Jones 
8243402ba5SAndrew Jones static inline void
virtio_config_writel(struct virtio_device * vdev,unsigned offset,u32 val)8343402ba5SAndrew Jones virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val)
8443402ba5SAndrew Jones {
8543402ba5SAndrew Jones 	vdev->config->set(vdev, offset, &val, 4);
8643402ba5SAndrew Jones }
8743402ba5SAndrew Jones 
88d73e4521SAndrew Jones #define VRING_DESC_F_NEXT	1
89d73e4521SAndrew Jones #define VRING_DESC_F_WRITE	2
90d73e4521SAndrew Jones 
91d73e4521SAndrew Jones struct vring_desc {
92d73e4521SAndrew Jones 	u64 addr;
93d73e4521SAndrew Jones 	u32 len;
94d73e4521SAndrew Jones 	u16 flags;
95d73e4521SAndrew Jones 	u16 next;
96d73e4521SAndrew Jones };
97d73e4521SAndrew Jones 
98d73e4521SAndrew Jones struct vring_avail {
99d73e4521SAndrew Jones 	u16 flags;
100d73e4521SAndrew Jones 	u16 idx;
101d73e4521SAndrew Jones 	u16 ring[];
102d73e4521SAndrew Jones };
103d73e4521SAndrew Jones 
104d73e4521SAndrew Jones struct vring_used_elem {
105d73e4521SAndrew Jones 	u32 id;
106d73e4521SAndrew Jones 	u32 len;
107d73e4521SAndrew Jones };
108d73e4521SAndrew Jones 
109d73e4521SAndrew Jones struct vring_used {
110d73e4521SAndrew Jones 	u16 flags;
111d73e4521SAndrew Jones 	u16 idx;
112d73e4521SAndrew Jones 	struct vring_used_elem ring[];
113d73e4521SAndrew Jones };
114d73e4521SAndrew Jones 
115d73e4521SAndrew Jones struct vring {
116d73e4521SAndrew Jones 	unsigned int num;
117d73e4521SAndrew Jones 	struct vring_desc *desc;
118d73e4521SAndrew Jones 	struct vring_avail *avail;
119d73e4521SAndrew Jones 	struct vring_used *used;
120d73e4521SAndrew Jones };
121d73e4521SAndrew Jones 
122d73e4521SAndrew Jones struct vring_virtqueue {
123d73e4521SAndrew Jones 	struct virtqueue vq;
124d73e4521SAndrew Jones 	struct vring vring;
125d73e4521SAndrew Jones 	unsigned int free_head;
126d73e4521SAndrew Jones 	unsigned int num_added;
127d73e4521SAndrew Jones 	u16 last_used_idx;
128d73e4521SAndrew Jones 	bool (*notify)(struct virtqueue *vq);
129d73e4521SAndrew Jones 	void *data[];
130d73e4521SAndrew Jones };
131d73e4521SAndrew Jones 
132d73e4521SAndrew Jones #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
133d73e4521SAndrew Jones 
134d73e4521SAndrew Jones extern void vring_init(struct vring *vr, unsigned int num, void *p,
135d73e4521SAndrew Jones 		       unsigned long align);
136d73e4521SAndrew Jones extern void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index,
137d73e4521SAndrew Jones 				 unsigned num, unsigned vring_align,
138d73e4521SAndrew Jones 				 struct virtio_device *vdev, void *pages,
139d73e4521SAndrew Jones 				 bool (*notify)(struct virtqueue *),
140d73e4521SAndrew Jones 				 void (*callback)(struct virtqueue *),
141d73e4521SAndrew Jones 				 const char *name);
142368819a9SAndrew Jones extern int virtqueue_add_outbuf(struct virtqueue *vq, char *buf,
143368819a9SAndrew Jones 				unsigned int len);
144d73e4521SAndrew Jones extern bool virtqueue_kick(struct virtqueue *vq);
145d73e4521SAndrew Jones extern void detach_buf(struct vring_virtqueue *vq, unsigned head);
146d73e4521SAndrew Jones extern void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len);
147d73e4521SAndrew Jones 
14843402ba5SAndrew Jones extern struct virtio_device *virtio_bind(u32 devid);
14943402ba5SAndrew Jones 
15043402ba5SAndrew Jones #endif /* _VIRTIO_H_ */
151