11cf4323eSThomas Huth /*
21cf4323eSThomas Huth * libqos virtio definitions
31cf4323eSThomas Huth *
41cf4323eSThomas Huth * Copyright (c) 2014 Marc Marí
51cf4323eSThomas Huth *
61cf4323eSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later.
71cf4323eSThomas Huth * See the COPYING file in the top-level directory.
81cf4323eSThomas Huth */
91cf4323eSThomas Huth
101cf4323eSThomas Huth #ifndef LIBQOS_VIRTIO_H
111cf4323eSThomas Huth #define LIBQOS_VIRTIO_H
121cf4323eSThomas Huth
13b243c73cSXuzhou Cheng #include "libqos-malloc.h"
141cf4323eSThomas Huth #include "standard-headers/linux/virtio_ring.h"
151cf4323eSThomas Huth
161cf4323eSThomas Huth #define QVIRTIO_F_BAD_FEATURE 0x40000000ull
171cf4323eSThomas Huth
181cf4323eSThomas Huth typedef struct QVirtioBus QVirtioBus;
191cf4323eSThomas Huth
201cf4323eSThomas Huth typedef struct QVirtioDevice {
211cf4323eSThomas Huth const QVirtioBus *bus;
221cf4323eSThomas Huth /* Device type */
231cf4323eSThomas Huth uint16_t device_type;
241cf4323eSThomas Huth uint64_t features;
251cf4323eSThomas Huth bool big_endian;
261cf4323eSThomas Huth bool features_negotiated;
271cf4323eSThomas Huth } QVirtioDevice;
281cf4323eSThomas Huth
291cf4323eSThomas Huth typedef struct QVirtQueue {
301cf4323eSThomas Huth QVirtioDevice *vdev;
311cf4323eSThomas Huth uint64_t desc; /* This points to an array of struct vring_desc */
321cf4323eSThomas Huth uint64_t avail; /* This points to a struct vring_avail */
331cf4323eSThomas Huth uint64_t used; /* This points to a struct vring_used */
341cf4323eSThomas Huth uint16_t index;
351cf4323eSThomas Huth uint32_t size;
361cf4323eSThomas Huth uint32_t free_head;
371cf4323eSThomas Huth uint32_t num_free;
381cf4323eSThomas Huth uint32_t align;
391cf4323eSThomas Huth uint16_t last_used_idx;
401cf4323eSThomas Huth bool indirect;
411cf4323eSThomas Huth bool event;
421cf4323eSThomas Huth } QVirtQueue;
431cf4323eSThomas Huth
441cf4323eSThomas Huth typedef struct QVRingIndirectDesc {
451cf4323eSThomas Huth uint64_t desc; /* This points to an array fo struct vring_desc */
461cf4323eSThomas Huth uint16_t index;
471cf4323eSThomas Huth uint16_t elem;
481cf4323eSThomas Huth } QVRingIndirectDesc;
491cf4323eSThomas Huth
501cf4323eSThomas Huth struct QVirtioBus {
511cf4323eSThomas Huth uint8_t (*config_readb)(QVirtioDevice *d, uint64_t addr);
521cf4323eSThomas Huth uint16_t (*config_readw)(QVirtioDevice *d, uint64_t addr);
531cf4323eSThomas Huth uint32_t (*config_readl)(QVirtioDevice *d, uint64_t addr);
541cf4323eSThomas Huth uint64_t (*config_readq)(QVirtioDevice *d, uint64_t addr);
551cf4323eSThomas Huth
561cf4323eSThomas Huth /* Get features of the device */
571cf4323eSThomas Huth uint64_t (*get_features)(QVirtioDevice *d);
581cf4323eSThomas Huth
591cf4323eSThomas Huth /* Set features of the device */
601cf4323eSThomas Huth void (*set_features)(QVirtioDevice *d, uint64_t features);
611cf4323eSThomas Huth
621cf4323eSThomas Huth /* Get features of the guest */
631cf4323eSThomas Huth uint64_t (*get_guest_features)(QVirtioDevice *d);
641cf4323eSThomas Huth
651cf4323eSThomas Huth /* Get status of the device */
661cf4323eSThomas Huth uint8_t (*get_status)(QVirtioDevice *d);
671cf4323eSThomas Huth
681cf4323eSThomas Huth /* Set status of the device */
691cf4323eSThomas Huth void (*set_status)(QVirtioDevice *d, uint8_t status);
701cf4323eSThomas Huth
711cf4323eSThomas Huth /* Get the queue ISR status of the device */
721cf4323eSThomas Huth bool (*get_queue_isr_status)(QVirtioDevice *d, QVirtQueue *vq);
731cf4323eSThomas Huth
741cf4323eSThomas Huth /* Wait for the configuration ISR status of the device */
751cf4323eSThomas Huth void (*wait_config_isr_status)(QVirtioDevice *d, gint64 timeout_us);
761cf4323eSThomas Huth
771cf4323eSThomas Huth /* Select a queue to work on */
781cf4323eSThomas Huth void (*queue_select)(QVirtioDevice *d, uint16_t index);
791cf4323eSThomas Huth
801cf4323eSThomas Huth /* Get the size of the selected queue */
811cf4323eSThomas Huth uint16_t (*get_queue_size)(QVirtioDevice *d);
821cf4323eSThomas Huth
831cf4323eSThomas Huth /* Set the address of the selected queue */
841cf4323eSThomas Huth void (*set_queue_address)(QVirtioDevice *d, QVirtQueue *vq);
851cf4323eSThomas Huth
861cf4323eSThomas Huth /* Setup the virtqueue specified by index */
871cf4323eSThomas Huth QVirtQueue *(*virtqueue_setup)(QVirtioDevice *d, QGuestAllocator *alloc,
881cf4323eSThomas Huth uint16_t index);
891cf4323eSThomas Huth
901cf4323eSThomas Huth /* Free virtqueue resources */
911cf4323eSThomas Huth void (*virtqueue_cleanup)(QVirtQueue *vq, QGuestAllocator *alloc);
921cf4323eSThomas Huth
931cf4323eSThomas Huth /* Notify changes in virtqueue */
941cf4323eSThomas Huth void (*virtqueue_kick)(QVirtioDevice *d, QVirtQueue *vq);
951cf4323eSThomas Huth };
961cf4323eSThomas Huth
qvring_size(uint32_t num,uint32_t align)971cf4323eSThomas Huth static inline uint32_t qvring_size(uint32_t num, uint32_t align)
981cf4323eSThomas Huth {
991cf4323eSThomas Huth return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (3 + num)
1001cf4323eSThomas Huth + align - 1) & ~(align - 1))
1011cf4323eSThomas Huth + sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num;
1021cf4323eSThomas Huth }
1031cf4323eSThomas Huth
1041cf4323eSThomas Huth uint8_t qvirtio_config_readb(QVirtioDevice *d, uint64_t addr);
1051cf4323eSThomas Huth uint16_t qvirtio_config_readw(QVirtioDevice *d, uint64_t addr);
1061cf4323eSThomas Huth uint32_t qvirtio_config_readl(QVirtioDevice *d, uint64_t addr);
1071cf4323eSThomas Huth uint64_t qvirtio_config_readq(QVirtioDevice *d, uint64_t addr);
1081cf4323eSThomas Huth uint64_t qvirtio_get_features(QVirtioDevice *d);
1091cf4323eSThomas Huth void qvirtio_set_features(QVirtioDevice *d, uint64_t features);
1101cf4323eSThomas Huth bool qvirtio_is_big_endian(QVirtioDevice *d);
1111cf4323eSThomas Huth
1121cf4323eSThomas Huth void qvirtio_reset(QVirtioDevice *d);
1131cf4323eSThomas Huth void qvirtio_set_acknowledge(QVirtioDevice *d);
1141cf4323eSThomas Huth void qvirtio_set_driver(QVirtioDevice *d);
1151cf4323eSThomas Huth void qvirtio_set_driver_ok(QVirtioDevice *d);
1161cf4323eSThomas Huth
1171cf4323eSThomas Huth void qvirtio_wait_queue_isr(QTestState *qts, QVirtioDevice *d,
1181cf4323eSThomas Huth QVirtQueue *vq, gint64 timeout_us);
1191cf4323eSThomas Huth uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d,
1201cf4323eSThomas Huth QVirtQueue *vq,
1211cf4323eSThomas Huth uint64_t addr,
1221cf4323eSThomas Huth gint64 timeout_us);
1231cf4323eSThomas Huth void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d,
1241cf4323eSThomas Huth QVirtQueue *vq,
1251cf4323eSThomas Huth uint32_t desc_idx,
1261cf4323eSThomas Huth uint32_t *len,
1271cf4323eSThomas Huth gint64 timeout_us);
1281cf4323eSThomas Huth void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us);
1291cf4323eSThomas Huth QVirtQueue *qvirtqueue_setup(QVirtioDevice *d,
1301cf4323eSThomas Huth QGuestAllocator *alloc, uint16_t index);
1311cf4323eSThomas Huth void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq,
1321cf4323eSThomas Huth QGuestAllocator *alloc);
1331cf4323eSThomas Huth
1341cf4323eSThomas Huth void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq,
1351cf4323eSThomas Huth uint64_t addr);
1361cf4323eSThomas Huth QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d,
1371cf4323eSThomas Huth QGuestAllocator *alloc,
1381cf4323eSThomas Huth uint16_t elem);
1391cf4323eSThomas Huth void qvring_indirect_desc_add(QVirtioDevice *d, QTestState *qts,
1401cf4323eSThomas Huth QVRingIndirectDesc *indirect,
1411cf4323eSThomas Huth uint64_t data, uint32_t len, bool write);
1421cf4323eSThomas Huth uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data,
1431cf4323eSThomas Huth uint32_t len, bool write, bool next);
1441cf4323eSThomas Huth uint32_t qvirtqueue_add_indirect(QTestState *qts, QVirtQueue *vq,
1451cf4323eSThomas Huth QVRingIndirectDesc *indirect);
1461cf4323eSThomas Huth void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq,
1471cf4323eSThomas Huth uint32_t free_head);
1481cf4323eSThomas Huth bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx,
1491cf4323eSThomas Huth uint32_t *len);
1501cf4323eSThomas Huth
1511cf4323eSThomas Huth void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx);
1521cf4323eSThomas Huth
1531cf4323eSThomas Huth void qvirtio_start_device(QVirtioDevice *vdev);
1541cf4323eSThomas Huth
1551cf4323eSThomas Huth #endif
156