173 lines
4.7 KiB
C
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
|