#include <sys/types.h>
#include <dev/pv/virtioreg.h>
#include <dev/pci/virtio_pcireg.h>
#include <net/if_tun.h>
#include <event.h>
#include "vmd.h"
#include "pci.h"
#ifndef _VIRTIO_H_
#define _VIRTIO_H_
#define VIRTQUEUE_ALIGN(n) (((n)+(VIRTIO_PAGE_SIZE-1))& \
~(VIRTIO_PAGE_SIZE-1))
#define ALIGNSZ(sz, align) ((sz + align - 1) & ~(align - 1))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define VIO1_PCI_DEVICE_FEATURE_SELECT \
(offsetof(struct virtio_pci_common_cfg, device_feature_select))
#define VIO1_PCI_DEVICE_FEATURE \
(offsetof(struct virtio_pci_common_cfg, device_feature))
#define VIO1_PCI_DRIVER_FEATURE_SELECT \
(offsetof(struct virtio_pci_common_cfg, driver_feature_select))
#define VIO1_PCI_DRIVER_FEATURE \
(offsetof(struct virtio_pci_common_cfg, driver_feature))
#define VIO1_PCI_CONFIG_MSIX_VECTOR \
(offsetof(struct virtio_pci_common_cfg, config_msix_vector))
#define VIO1_PCI_NUM_QUEUES \
(offsetof(struct virtio_pci_common_cfg, num_queues))
#define VIO1_PCI_DEVICE_STATUS \
(offsetof(struct virtio_pci_common_cfg, device_status))
#define VIO1_PCI_CONFIG_GENERATION \
(offsetof(struct virtio_pci_common_cfg, config_generation))
#define VIO1_PCI_QUEUE_SELECT \
(offsetof(struct virtio_pci_common_cfg, queue_select))
#define VIO1_PCI_QUEUE_SIZE \
(offsetof(struct virtio_pci_common_cfg, queue_size))
#define VIO1_PCI_QUEUE_MSIX_VECTOR \
(offsetof(struct virtio_pci_common_cfg, queue_msix_vector))
#define VIO1_PCI_QUEUE_ENABLE \
(offsetof(struct virtio_pci_common_cfg, queue_enable))
#define VIO1_PCI_QUEUE_NOTIFY_OFF \
(offsetof(struct virtio_pci_common_cfg, queue_notify_off))
#define VIO1_PCI_QUEUE_DESC \
(offsetof(struct virtio_pci_common_cfg, queue_desc))
#define VIO1_PCI_QUEUE_AVAIL \
(offsetof(struct virtio_pci_common_cfg, queue_avail))
#define VIO1_PCI_QUEUE_USED \
(offsetof(struct virtio_pci_common_cfg, queue_used))
#define VIO1_CFG_BAR_OFFSET 0x000
#define VIO1_NOTIFY_BAR_OFFSET 0x100
#define VIO1_ISR_BAR_OFFSET 0x200
#define VIO1_DEV_BAR_OFFSET 0x300
#define VIRTIO_QUEUE_SIZE_MAX IOV_MAX
#define VIORND_QUEUE_SIZE_DEFAULT 64
#define VIOBLK_QUEUE_SIZE_DEFAULT 128
#define VIOSCSI_QUEUE_SIZE_DEFAULT 128
#define VIONET_QUEUE_SIZE_DEFAULT 256
#define VIOBLK_SEG_MAX_DEFAULT (VIOBLK_QUEUE_SIZE_DEFAULT - 2)
#define VIONET_HARD_MTU TUNMRU
#define VIONET_MIN_TXLEN ETHER_HDR_LEN
#define VIONET_MAX_TXLEN VIONET_HARD_MTU + ETHER_HDR_LEN
#define VMMCI_TIMEOUT_SHORT 3
#define VMMCI_TIMEOUT_LONG 120
#define VIRTIO_RND_QUEUES 1
#define VIRTIO_BLK_QUEUES 1
#define VIRTIO_NET_QUEUES 2
#define VIRTIO_SCSI_QUEUES 3
#define VIRTIO_VMMCI_QUEUES 0
#define VIRTIO_MAX_QUEUES 3
#define MAXPHYS (64 * 1024)
#define VIRTIO_CONFIG_QUEUE_PFN VIRTIO_CONFIG_QUEUE_ADDRESS
#define DEVICE_NEEDS_RESET VIRTIO_CONFIG_DEVICE_STATUS_DEVICE_NEEDS_RESET
#define DESC_WRITABLE( x) \
(((x)->flags & VRING_DESC_F_WRITE) ? 1 : 0)
struct virtio_pci_common_cap {
union {
struct pci_cap pci;
struct virtio_pci_cap virtio;
struct virtio_pci_notify_cap notify;
struct virtio_pci_cfg_cap cfg;
};
} __packed;
struct viodev_msg {
uint8_t type;
#define VIODEV_MSG_INVALID 0
#define VIODEV_MSG_READY 1
#define VIODEV_MSG_ERROR 2
#define VIODEV_MSG_KICK 3
#define VIODEV_MSG_IO_READ 4
#define VIODEV_MSG_IO_WRITE 5
#define VIODEV_MSG_DUMP 6
#define VIODEV_MSG_SHUTDOWN 7
uint16_t reg;
uint8_t io_sz;
uint8_t vcpu;
uint8_t irq;
int8_t state;
#define INTR_STATE_ASSERT 1
#define INTR_STATE_NOOP 0
#define INTR_STATE_DEASSERT -1
uint32_t data;
uint8_t data_valid;
} __packed;
struct virtio_io_cfg {
uint32_t device_feature;
uint32_t guest_feature;
uint32_t queue_pfn;
uint16_t queue_select;
uint16_t queue_size;
uint16_t queue_notify;
};
struct virtio_backing {
void *p;
ssize_t (*pread)(void *, char *, size_t, off_t);
ssize_t (*preadv)(void *, struct iovec *, int, off_t);
ssize_t (*pwrite)(void *, char *, size_t, off_t);
ssize_t (*pwritev)(void *, struct iovec *, int, off_t);
void (*close)(void *, int);
};
struct virtio_vq_info {
uint64_t q_gpa;
void *q_hva;
uint32_t qs;
uint32_t mask;
uint32_t vq_availoffset;
uint32_t vq_usedoffset;
uint16_t last_avail;
uint16_t notified_avail;
uint8_t vq_enabled;
};
struct virtio_vq_acct {
uint16_t idx;
uint16_t req_idx;
uint16_t resp_idx;
struct vring_desc *desc;
struct vring_desc *req_desc;
struct vring_desc *resp_desc;
struct vring_avail *avail;
struct vring_used *used;
};
struct vioblk_dev {
struct virtio_backing file;
int disk_fd[VM_MAX_BASE_PER_DISK];
uint8_t ndisk_fd;
uint64_t capacity;
uint32_t seg_max;
unsigned int idx;
};
struct vioscsi_dev {
struct virtio_backing file;
int cdrom_fd;
int locked;
uint64_t sz;
uint64_t lba;
uint64_t n_blocks;
uint32_t max_xfer;
};
struct vionet_dev {
int data_fd;
uint8_t mac[6];
uint8_t hostmac[6];
int lockedmac;
int local;
int pxeboot;
struct local_prefix local_prefix;
unsigned int idx;
};
struct virtio_net_hdr {
uint8_t flags;
uint8_t gso_type;
uint16_t hdr_len;
uint16_t gso_size;
uint16_t csum_start;
uint16_t csum_offset;
uint16_t num_buffers;
};
enum vmmci_cmd {
VMMCI_NONE = 0,
VMMCI_SHUTDOWN,
VMMCI_REBOOT,
VMMCI_SYNCRTC,
};
struct vmmci_dev {
struct event timeout;
struct timeval time;
enum vmmci_cmd cmd;
pthread_mutex_t mutex;
struct vm_dev_pipe dev_pipe;
};
struct ioinfo {
uint8_t *buf;
ssize_t len;
off_t offset;
};
struct virtio_dev {
uint16_t device_id;
union {
struct vioblk_dev vioblk;
struct vionet_dev vionet;
struct vmmci_dev vmmci;
struct vioscsi_dev vioscsi;
};
struct virtio_io_cfg cfg;
struct virtio_pci_common_cfg pci_cfg;
struct virtio_vq_info vq[VIRTIO_MAX_QUEUES];
uint16_t num_queues;
uint16_t queue_size;
uint8_t isr;
uint8_t status;
uint64_t device_feature;
uint64_t driver_feature;
uint8_t pci_id;
int irq;
struct imsgev async_iev;
struct imsgev sync_iev;
int sync_fd;
int async_fd;
uint32_t vm_id;
uint32_t vmm_id;
pid_t dev_pid;
char dev_type;
SLIST_ENTRY(virtio_dev) dev_next;
};
extern struct virtio_dev vmmci;
int virtio_init(struct vmd_vm *, int, int[][VM_MAX_BASE_PER_DISK], int *);
void virtio_vq_init(struct virtio_dev *, size_t);
void virtio_broadcast_imsg(struct vmd_vm *, uint16_t, void *, uint16_t);
void virtio_stop(struct vmd_vm *);
void virtio_start(struct vmd_vm *);
void virtio_shutdown(struct vmd_vm *);
const char *virtio_reg_name(uint8_t);
uint32_t vring_size(uint32_t);
int vm_device_pipe(struct virtio_dev *, void (*)(int, short, void *),
struct event_base *);
int virtio_pci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
void virtio_assert_irq(struct virtio_dev *, int);
void virtio_deassert_irq(struct virtio_dev *, int);
uint32_t virtio_io_cfg(struct virtio_dev *, int, uint8_t, uint32_t, uint8_t);
void virtio_update_qs(struct virtio_dev *);
void virtio_update_qa(struct virtio_dev *);
ssize_t virtio_qcow2_get_base(int, char *, size_t, const char *);
int virtio_qcow2_create(const char *, const char *, uint64_t);
int virtio_qcow2_init(struct virtio_backing *, off_t *, int*, size_t);
int virtio_raw_create(const char *, uint64_t);
int virtio_raw_init(struct virtio_backing *, off_t *, int*, size_t);
void vionet_set_hostmac(struct vmd_vm *, unsigned int, uint8_t *);
int vmmci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
int vmmci_ctl(struct virtio_dev *, unsigned int);
void vmmci_timeout(int, short, void *);
const char *vioblk_cmd_name(uint32_t);
ssize_t dhcp_request(struct virtio_dev *, char *, size_t, char **);
void viodev_msg_read(struct imsg *, struct viodev_msg *);
void vionet_hostmac_read(struct imsg *, struct vionet_dev *);
#endif