151 lines
3.3 KiB
C
151 lines
3.3 KiB
C
#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 <drjones@redhat.com>
|
|
*
|
|
* 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_ */
|