karlos/include/virtio-common.h

173 lines
4.7 KiB
C

#ifndef KARLOS_VIRTIO_COMMON_H
#define KARLOS_VIRTIO_COMMON_H
#include <stdint.h>
#include <stdbool.h>
#include "pci.h"
// struct so you don't accidentally access the value; use following macros to read/write
// TODO these are aligned, we have no way to specify unaligned ints currently
typedef struct le16 {
uint16_t value;
} le16;
typedef struct le32 {
uint32_t value;
} le32;
typedef struct le64 {
uint64_t value;
} le64;
#if !defined(__BYTE_ORDER__) || (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define LE16_READ(v) TODO()
#define LE16_WRITE(v, new_value) TODO()
#define LE32_READ(v) TODO()
#define LE32_WRITE(v, new_value) TODO()
#define LE64_READ(v) TODO()
#define LE64_WRITE(v, new_value) TODO()
#else
#define LE16_READ(v) ((v).value)
#define LE16_WRITE(v, new_value) do { (v).value = (new_value); } while (0)
#define LE32_READ(v) ((v).value)
#define LE32_WRITE(v, new_value) do { (v).value = (new_value); } while (0)
#define LE64_READ(v) ((v).value)
#define LE64_WRITE(v, new_value) do { (v).value = (new_value); } while (0)
#endif
// TODO be consistent and define here the bit shift, not the bit value.
// then when using, use BIT_GET and BIT_SET macros
// OS acknowledged the device
#define VIRTIO_DEV_STATUS_ACKNOWLEDGE 1
// OS knows how to drive the device
#define VIRTIO_DEV_STATUS_DRIVER 2
// guest has given up on the device
#define VIRTIO_DEV_STATUS_FAILED 128
// feature negotiation complete
#define VIRTIO_DEV_STATUS_FEATURES_OK 8
// driver is set up
#define VIRTIO_DEV_STATUS_DRIVER_OK 4
// unrecoverable error
#define VIRTIO_DEV_STATUS_DEVICE_NEEDS_RESET 64
// reserved feature bits
#define VIRTIO_F_INDIRECT_DESC 28
#define VIRTIO_F_EVENT_IDX 29
#define VIRTIO_F_VERSION_1 32
// TODO others
// buffer continues via `next` field
#define VIRTQ_DESC_F_NEXT 1
// buffer is device write-only (not set: device read-only)
#define VIRTQ_DESC_F_WRITE 2
// buffer contains list of buffer descriptors (ONLY AVAILABLE BY VIRTIO_F_INDIRECT_DESC; DO NOT SET THIS AND F_NEXT)
#define VIRTQ_DESC_F_INDIRECT 4
struct virtq_desc {
le64 addr;
le32 len;
le16 flags; // see macros above
le16 next;
};
#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
struct virtq_avail {
le16 flags;
// where driver would put next descriptor entry, modulo queue size
le16 idx;
le16 ring[ /* queue size */ ];
// le16 used_event; // only when VIRTIO_F_EVENT_IDX
};
struct virtq_used_elem {
// index of start of used descriptor chain
le32 id;
// number of bytes written into device writable portion
// useful to avoid data leaks (e.g. passing buffer directly to userspace)
le32 len;
};
#define VIRTQ_USED_F_NO_NOTIFY 1
struct virtq_used {
le16 flags;
le16 idx;
struct virtq_used_elem ring[ /* queue size */ ];
// le16 avail_event; // only when VIRTIO_F_EVENT_IDX
};
// searching for devices
#define VIRTIO_VENDOR_ID 0x1af4
enum virtio_dev_kind {
VIRTIO_DEV_KIND_BLOCK,
// TODO
};
struct virtio_dev_iter {
struct pci_iter iter;
enum virtio_dev_kind kind;
};
void virtio_dev_iter_init(struct virtio_dev_iter *it, enum virtio_dev_kind kind);
bool virtio_dev_iter_next(struct virtio_dev_iter *it, uint16_t *bdf);
struct virtio_pci_cap {
uint8_t cap_vndr;
uint8_t cap_next;
uint8_t cap_len;
// see below
uint8_t cfg_type;
uint8_t bar;
uint8_t id;
uint8_t padding[2];
le32 offset;
le32 length;
};
/* Common configuration */
#define VIRTIO_PCI_CAP_COMMON_CFG 1
/* Notifications */
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
/* ISR Status */
#define VIRTIO_PCI_CAP_ISR_CFG 3
/* Device specific configuration */
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
/* PCI configuration access */
#define VIRTIO_PCI_CAP_PCI_CFG 5
/* Shared memory region */
#define VIRTIO_PCI_CAP_SHARED_MEMORY_CFG 8
/* Vendor-specific data */
#define VIRTIO_PCI_CAP_VENDOR_CFG 9
struct virtio_cap {
unsigned type;
uint8_t pci_offset;
uint8_t barno;
uint32_t offset;
uint32_t length;
};
bool virtio_find_cap_of_type(uint16_t bdf, unsigned type, struct virtio_cap *cap);
struct virtio_pci_common_cfg {
le32 device_feature_select;
le32 device_feature;
le32 driver_feature_select;
le32 driver_feature;
le16 config_msix_vector;
le16 num_queues;
uint8_t device_status;
uint8_t config_generation;
le16 queue_select;
le16 queue_size;
le16 queue_msix_vector;
le16 queue_enable;
le16 queue_notify_off;
le64 queue_desc;
le64 queue_driver;
le64 queue_device;
le16 queue_notify_data; // only for VIRTIO_F_NOTIF_CONFIG_DATA
le16 queue_reset; // only for VIRTIO_F_RING_-RESET
};
struct virtio_pci_notify_cap {
struct virtio_pci_cap cap;
le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
};
#endif