diff options
Diffstat (limited to 'qemu/include/hw/virtio')
-rw-r--r-- | qemu/include/hw/virtio/dataplane/vring-accessors.h | 75 | ||||
-rw-r--r-- | qemu/include/hw/virtio/dataplane/vring.h | 49 | ||||
-rw-r--r-- | qemu/include/hw/virtio/vhost-backend.h | 40 | ||||
-rw-r--r-- | qemu/include/hw/virtio/vhost-scsi.h | 69 | ||||
-rw-r--r-- | qemu/include/hw/virtio/vhost.h | 84 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-9p.h | 24 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-access.h | 196 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-balloon.h | 48 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-blk.h | 92 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-bus.h | 106 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-gpu.h | 142 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-input.h | 119 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-net.h | 103 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-rng.h | 50 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-scsi.h | 166 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio-serial.h | 224 | ||||
-rw-r--r-- | qemu/include/hw/virtio/virtio.h | 290 |
17 files changed, 1877 insertions, 0 deletions
diff --git a/qemu/include/hw/virtio/dataplane/vring-accessors.h b/qemu/include/hw/virtio/dataplane/vring-accessors.h new file mode 100644 index 000000000..815c19b6e --- /dev/null +++ b/qemu/include/hw/virtio/dataplane/vring-accessors.h @@ -0,0 +1,75 @@ +#ifndef VRING_ACCESSORS_H +#define VRING_ACCESSORS_H + +#include "standard-headers/linux/virtio_ring.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-access.h" + +static inline uint16_t vring_get_used_idx(VirtIODevice *vdev, Vring *vring) +{ + return virtio_tswap16(vdev, vring->vr.used->idx); +} + +static inline void vring_set_used_idx(VirtIODevice *vdev, Vring *vring, + uint16_t idx) +{ + vring->vr.used->idx = virtio_tswap16(vdev, idx); +} + +static inline uint16_t vring_get_avail_idx(VirtIODevice *vdev, Vring *vring) +{ + return virtio_tswap16(vdev, vring->vr.avail->idx); +} + +static inline uint16_t vring_get_avail_ring(VirtIODevice *vdev, Vring *vring, + int i) +{ + return virtio_tswap16(vdev, vring->vr.avail->ring[i]); +} + +static inline void vring_set_used_ring_id(VirtIODevice *vdev, Vring *vring, + int i, uint32_t id) +{ + vring->vr.used->ring[i].id = virtio_tswap32(vdev, id); +} + +static inline void vring_set_used_ring_len(VirtIODevice *vdev, Vring *vring, + int i, uint32_t len) +{ + vring->vr.used->ring[i].len = virtio_tswap32(vdev, len); +} + +static inline uint16_t vring_get_used_flags(VirtIODevice *vdev, Vring *vring) +{ + return virtio_tswap16(vdev, vring->vr.used->flags); +} + +static inline uint16_t vring_get_avail_flags(VirtIODevice *vdev, Vring *vring) +{ + return virtio_tswap16(vdev, vring->vr.avail->flags); +} + +static inline void vring_set_used_flags(VirtIODevice *vdev, Vring *vring, + uint16_t flags) +{ + vring->vr.used->flags |= virtio_tswap16(vdev, flags); +} + +static inline void vring_clear_used_flags(VirtIODevice *vdev, Vring *vring, + uint16_t flags) +{ + vring->vr.used->flags &= virtio_tswap16(vdev, ~flags); +} + +static inline unsigned int vring_get_num(Vring *vring) +{ + return vring->vr.num; +} + +/* Are there more descriptors available? */ +static inline bool vring_more_avail(VirtIODevice *vdev, Vring *vring) +{ + return vring_get_avail_idx(vdev, vring) != vring->last_avail_idx; +} + +#endif diff --git a/qemu/include/hw/virtio/dataplane/vring.h b/qemu/include/hw/virtio/dataplane/vring.h new file mode 100644 index 000000000..8d97db9e2 --- /dev/null +++ b/qemu/include/hw/virtio/dataplane/vring.h @@ -0,0 +1,49 @@ +/* Copyright 2012 Red Hat, Inc. and/or its affiliates + * Copyright IBM, Corp. 2012 + * + * Based on Linux 2.6.39 vhost code: + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin <mst@redhat.com> + * Stefan Hajnoczi <stefanha@redhat.com> + * + * Inspiration, some code, and most witty comments come from + * Documentation/virtual/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#ifndef VRING_H +#define VRING_H + +#include "qemu-common.h" +#include "standard-headers/linux/virtio_ring.h" +#include "hw/virtio/virtio.h" + +typedef struct { + MemoryRegion *mr; /* memory region containing the vring */ + struct vring vr; /* virtqueue vring mapped to host memory */ + uint16_t last_avail_idx; /* last processed avail ring index */ + uint16_t last_used_idx; /* last processed used ring index */ + uint16_t signalled_used; /* EVENT_IDX state */ + bool signalled_used_valid; + bool broken; /* was there a fatal error? */ +} Vring; + +/* Fail future vring_pop() and vring_push() calls until reset */ +static inline void vring_set_broken(Vring *vring) +{ + vring->broken = true; +} + +bool vring_setup(Vring *vring, VirtIODevice *vdev, int n); +void vring_teardown(Vring *vring, VirtIODevice *vdev, int n); +void vring_disable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_should_notify(VirtIODevice *vdev, Vring *vring); +int vring_pop(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem); +void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, + int len); + +#endif /* VRING_H */ diff --git a/qemu/include/hw/virtio/vhost-backend.h b/qemu/include/hw/virtio/vhost-backend.h new file mode 100644 index 000000000..e472f2971 --- /dev/null +++ b/qemu/include/hw/virtio/vhost-backend.h @@ -0,0 +1,40 @@ +/* + * vhost-backend + * + * Copyright (c) 2013 Virtual Open Systems Sarl. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef VHOST_BACKEND_H_ +#define VHOST_BACKEND_H_ + +typedef enum VhostBackendType { + VHOST_BACKEND_TYPE_NONE = 0, + VHOST_BACKEND_TYPE_KERNEL = 1, + VHOST_BACKEND_TYPE_USER = 2, + VHOST_BACKEND_TYPE_MAX = 3, +} VhostBackendType; + +struct vhost_dev; + +typedef int (*vhost_call)(struct vhost_dev *dev, unsigned long int request, + void *arg); +typedef int (*vhost_backend_init)(struct vhost_dev *dev, void *opaque); +typedef int (*vhost_backend_cleanup)(struct vhost_dev *dev); + +typedef struct VhostOps { + VhostBackendType backend_type; + vhost_call vhost_call; + vhost_backend_init vhost_backend_init; + vhost_backend_cleanup vhost_backend_cleanup; +} VhostOps; + +extern const VhostOps user_ops; + +int vhost_set_backend_type(struct vhost_dev *dev, + VhostBackendType backend_type); + +#endif /* VHOST_BACKEND_H_ */ diff --git a/qemu/include/hw/virtio/vhost-scsi.h b/qemu/include/hw/virtio/vhost-scsi.h new file mode 100644 index 000000000..701bfee61 --- /dev/null +++ b/qemu/include/hw/virtio/vhost-scsi.h @@ -0,0 +1,69 @@ +/* + * vhost_scsi host device + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef VHOST_SCSI_H +#define VHOST_SCSI_H + +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/virtio/vhost.h" + +/* + * Used by QEMU userspace to ensure a consistent vhost-scsi ABI. + * + * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + + * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage + * ABI Rev 1: January 2013. Ignore vhost_tpgt filed in struct vhost_scsi_target. + * All the targets under vhost_wwpn can be seen and used by guest. + */ + +#define VHOST_SCSI_ABI_VERSION 1 + +/* TODO #include <linux/vhost.h> properly */ +/* For VHOST_SCSI_SET_ENDPOINT/VHOST_SCSI_CLEAR_ENDPOINT ioctl */ +struct vhost_scsi_target { + int abi_version; + char vhost_wwpn[224]; + unsigned short vhost_tpgt; + unsigned short reserved; +}; + +enum vhost_scsi_vq_list { + VHOST_SCSI_VQ_CONTROL = 0, + VHOST_SCSI_VQ_EVENT = 1, + VHOST_SCSI_VQ_NUM_FIXED = 2, +}; + +#define VHOST_VIRTIO 0xAF +#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) +#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) +#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) + +#define TYPE_VHOST_SCSI "vhost-scsi" +#define VHOST_SCSI(obj) \ + OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI) + +typedef struct VHostSCSI { + VirtIOSCSICommon parent_obj; + + Error *migration_blocker; + + struct vhost_dev dev; + int32_t bootindex; + int channel; + int target; + int lun; +} VHostSCSI; + +#endif diff --git a/qemu/include/hw/virtio/vhost.h b/qemu/include/hw/virtio/vhost.h new file mode 100644 index 000000000..dd510509e --- /dev/null +++ b/qemu/include/hw/virtio/vhost.h @@ -0,0 +1,84 @@ +#ifndef VHOST_H +#define VHOST_H + +#include "hw/hw.h" +#include "hw/virtio/vhost-backend.h" +#include "hw/virtio/virtio.h" +#include "exec/memory.h" + +/* Generic structures common for any vhost based device. */ +struct vhost_virtqueue { + int kick; + int call; + void *desc; + void *avail; + void *used; + int num; + unsigned long long used_phys; + unsigned used_size; + void *ring; + unsigned long long ring_phys; + unsigned ring_size; + EventNotifier masked_notifier; +}; + +typedef unsigned long vhost_log_chunk_t; +#define VHOST_LOG_PAGE 0x1000 +#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) +#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) +#define VHOST_INVALID_FEATURE_BIT (0xff) + +struct vhost_log { + unsigned long long size; + int refcnt; + vhost_log_chunk_t log[0]; +}; + +struct vhost_memory; +struct vhost_dev { + MemoryListener memory_listener; + struct vhost_memory *mem; + int n_mem_sections; + MemoryRegionSection *mem_sections; + struct vhost_virtqueue *vqs; + int nvqs; + /* the first virtqueue which would be used by this vhost dev */ + int vq_index; + unsigned long long features; + unsigned long long acked_features; + unsigned long long backend_features; + bool started; + bool log_enabled; + unsigned long long log_size; + Error *migration_blocker; + bool memory_changed; + hwaddr mem_changed_start_addr; + hwaddr mem_changed_end_addr; + const VhostOps *vhost_ops; + void *opaque; + struct vhost_log *log; +}; + +int vhost_dev_init(struct vhost_dev *hdev, void *opaque, + VhostBackendType backend_type); +void vhost_dev_cleanup(struct vhost_dev *hdev); +bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev); +int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); +void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); +int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); + +/* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. + */ +bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n); + +/* Mask/unmask events from this vq. + */ +void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + bool mask); +uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features); +void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features); +#endif diff --git a/qemu/include/hw/virtio/virtio-9p.h b/qemu/include/hw/virtio/virtio-9p.h new file mode 100644 index 000000000..65789db13 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-9p.h @@ -0,0 +1,24 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_VIRTIO_9P_DEVICE_H +#define QEMU_VIRTIO_9P_DEVICE_H + +typedef struct V9fsConf +{ + /* tag name for the device */ + char *tag; + char *fsdev_id; +} V9fsConf; + +#endif diff --git a/qemu/include/hw/virtio/virtio-access.h b/qemu/include/hw/virtio/virtio-access.h new file mode 100644 index 000000000..1ec1dfdb6 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-access.h @@ -0,0 +1,196 @@ +/* + * Virtio Accessor Support: In case your target can change endian. + * + * Copyright IBM, Corp. 2013 + * + * Authors: + * Rusty Russell <rusty@au.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + */ +#ifndef _QEMU_VIRTIO_ACCESS_H +#define _QEMU_VIRTIO_ACCESS_H +#include "hw/virtio/virtio.h" +#include "exec/address-spaces.h" + +static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) +{ + if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + /* Devices conforming to VIRTIO 1.0 or later are always LE. */ + return false; + } +#if defined(TARGET_IS_BIENDIAN) + return virtio_is_big_endian(vdev); +#elif defined(TARGET_WORDS_BIGENDIAN) + return true; +#else + return false; +#endif +} + +static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev) +{ +#ifdef TARGET_IS_BIENDIAN +#ifdef HOST_WORDS_BIGENDIAN + return !virtio_is_big_endian(vdev); +#else + return virtio_is_big_endian(vdev); +#endif +#else + return false; +#endif +} + +static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return lduw_be_phys(&address_space_memory, pa); + } + return lduw_le_phys(&address_space_memory, pa); +} + +static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldl_be_phys(&address_space_memory, pa); + } + return ldl_le_phys(&address_space_memory, pa); +} + +static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldq_be_phys(&address_space_memory, pa); + } + return ldq_le_phys(&address_space_memory, pa); +} + +static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa, + uint16_t value) +{ + if (virtio_access_is_big_endian(vdev)) { + stw_be_phys(&address_space_memory, pa, value); + } else { + stw_le_phys(&address_space_memory, pa, value); + } +} + +static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa, + uint32_t value) +{ + if (virtio_access_is_big_endian(vdev)) { + stl_be_phys(&address_space_memory, pa, value); + } else { + stl_le_phys(&address_space_memory, pa, value); + } +} + +static inline void virtio_stw_p(VirtIODevice *vdev, void *ptr, uint16_t v) +{ + if (virtio_access_is_big_endian(vdev)) { + stw_be_p(ptr, v); + } else { + stw_le_p(ptr, v); + } +} + +static inline void virtio_stl_p(VirtIODevice *vdev, void *ptr, uint32_t v) +{ + if (virtio_access_is_big_endian(vdev)) { + stl_be_p(ptr, v); + } else { + stl_le_p(ptr, v); + } +} + +static inline void virtio_stq_p(VirtIODevice *vdev, void *ptr, uint64_t v) +{ + if (virtio_access_is_big_endian(vdev)) { + stq_be_p(ptr, v); + } else { + stq_le_p(ptr, v); + } +} + +static inline int virtio_lduw_p(VirtIODevice *vdev, const void *ptr) +{ + if (virtio_access_is_big_endian(vdev)) { + return lduw_be_p(ptr); + } else { + return lduw_le_p(ptr); + } +} + +static inline int virtio_ldl_p(VirtIODevice *vdev, const void *ptr) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldl_be_p(ptr); + } else { + return ldl_le_p(ptr); + } +} + +static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldq_be_p(ptr); + } else { + return ldq_le_p(ptr); + } +} + +static inline bool virtio_needs_swap(VirtIODevice *vdev) +{ +#ifdef HOST_WORDS_BIGENDIAN + return virtio_access_is_big_endian(vdev) ? false : true; +#else + return virtio_access_is_big_endian(vdev) ? true : false; +#endif +} + +static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s) +{ +#ifdef HOST_WORDS_BIGENDIAN + return virtio_access_is_big_endian(vdev) ? s : bswap16(s); +#else + return virtio_access_is_big_endian(vdev) ? bswap16(s) : s; +#endif +} + +static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s) +{ + *s = virtio_tswap16(vdev, *s); +} + +static inline uint32_t virtio_tswap32(VirtIODevice *vdev, uint32_t s) +{ +#ifdef HOST_WORDS_BIGENDIAN + return virtio_access_is_big_endian(vdev) ? s : bswap32(s); +#else + return virtio_access_is_big_endian(vdev) ? bswap32(s) : s; +#endif +} + +static inline void virtio_tswap32s(VirtIODevice *vdev, uint32_t *s) +{ + *s = virtio_tswap32(vdev, *s); +} + +static inline uint64_t virtio_tswap64(VirtIODevice *vdev, uint64_t s) +{ +#ifdef HOST_WORDS_BIGENDIAN + return virtio_access_is_big_endian(vdev) ? s : bswap64(s); +#else + return virtio_access_is_big_endian(vdev) ? bswap64(s) : s; +#endif +} + +static inline void virtio_tswap64s(VirtIODevice *vdev, uint64_t *s) +{ + *s = virtio_tswap64(vdev, *s); +} +#endif /* _QEMU_VIRTIO_ACCESS_H */ diff --git a/qemu/include/hw/virtio/virtio-balloon.h b/qemu/include/hw/virtio/virtio-balloon.h new file mode 100644 index 000000000..09c2ce4dc --- /dev/null +++ b/qemu/include/hw/virtio/virtio-balloon.h @@ -0,0 +1,48 @@ +/* + * Virtio Support + * + * Copyright IBM, Corp. 2007-2008 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * Rusty Russell <rusty@rustcorp.com.au> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_BALLOON_H +#define _QEMU_VIRTIO_BALLOON_H + +#include "standard-headers/linux/virtio_balloon.h" +#include "hw/virtio/virtio.h" +#include "hw/pci/pci.h" + +#define TYPE_VIRTIO_BALLOON "virtio-balloon-device" +#define VIRTIO_BALLOON(obj) \ + OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON) + +typedef struct virtio_balloon_stat VirtIOBalloonStat; + +typedef struct virtio_balloon_stat_modern { + uint16_t tag; + uint8_t reserved[6]; + uint64_t val; +} VirtIOBalloonStatModern; + +typedef struct VirtIOBalloon { + VirtIODevice parent_obj; + VirtQueue *ivq, *dvq, *svq; + uint32_t num_pages; + uint32_t actual; + uint64_t stats[VIRTIO_BALLOON_S_NR]; + VirtQueueElement stats_vq_elem; + size_t stats_vq_offset; + QEMUTimer *stats_timer; + int64_t stats_last_update; + int64_t stats_poll_interval; + uint32_t host_features; +} VirtIOBalloon; + +#endif diff --git a/qemu/include/hw/virtio/virtio-blk.h b/qemu/include/hw/virtio/virtio-blk.h new file mode 100644 index 000000000..6bf5905c5 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-blk.h @@ -0,0 +1,92 @@ +/* + * Virtio Block Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_BLK_H +#define _QEMU_VIRTIO_BLK_H + +#include "standard-headers/linux/virtio_blk.h" +#include "hw/virtio/virtio.h" +#include "hw/block/block.h" +#include "sysemu/iothread.h" +#include "sysemu/block-backend.h" + +#define TYPE_VIRTIO_BLK "virtio-blk-device" +#define VIRTIO_BLK(obj) \ + OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK) + +/* This is the last element of the write scatter-gather list */ +struct virtio_blk_inhdr +{ + unsigned char status; +}; + +struct VirtIOBlkConf +{ + BlockConf conf; + IOThread *iothread; + char *serial; + uint32_t scsi; + uint32_t config_wce; + uint32_t data_plane; + uint32_t request_merging; +}; + +struct VirtIOBlockDataPlane; + +struct VirtIOBlockReq; +typedef struct VirtIOBlock { + VirtIODevice parent_obj; + BlockBackend *blk; + VirtQueue *vq; + void *rq; + QEMUBH *bh; + VirtIOBlkConf conf; + unsigned short sector_mask; + bool original_wce; + VMChangeStateEntry *change; + /* Function to push to vq and notify guest */ + void (*complete_request)(struct VirtIOBlockReq *req, unsigned char status); + Notifier migration_state_notifier; + struct VirtIOBlockDataPlane *dataplane; +} VirtIOBlock; + +typedef struct VirtIOBlockReq { + int64_t sector_num; + VirtIOBlock *dev; + VirtQueueElement elem; + struct virtio_blk_inhdr *in; + struct virtio_blk_outhdr out; + QEMUIOVector qiov; + size_t in_len; + struct VirtIOBlockReq *next; + struct VirtIOBlockReq *mr_next; + BlockAcctCookie acct; +} VirtIOBlockReq; + +#define VIRTIO_BLK_MAX_MERGE_REQS 32 + +typedef struct MultiReqBuffer { + VirtIOBlockReq *reqs[VIRTIO_BLK_MAX_MERGE_REQS]; + unsigned int num_reqs; + bool is_write; +} MultiReqBuffer; + +VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s); + +void virtio_blk_free_request(VirtIOBlockReq *req); + +void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); + +void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb); + +#endif diff --git a/qemu/include/hw/virtio/virtio-bus.h b/qemu/include/hw/virtio/virtio-bus.h new file mode 100644 index 000000000..8811415fa --- /dev/null +++ b/qemu/include/hw/virtio/virtio-bus.h @@ -0,0 +1,106 @@ +/* + * VirtioBus + * + * Copyright (C) 2012 : GreenSocs Ltd + * http://www.greensocs.com/ , email: info@greensocs.com + * + * Developed by : + * Frederic Konrad <fred.konrad@greensocs.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef VIRTIO_BUS_H +#define VIRTIO_BUS_H + +#include "hw/qdev.h" +#include "sysemu/sysemu.h" +#include "hw/virtio/virtio.h" + +#define TYPE_VIRTIO_BUS "virtio-bus" +#define VIRTIO_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioBusClass, obj, TYPE_VIRTIO_BUS) +#define VIRTIO_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioBusClass, klass, TYPE_VIRTIO_BUS) +#define VIRTIO_BUS(obj) OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_BUS) + +typedef struct VirtioBusState VirtioBusState; + +typedef struct VirtioBusClass { + /* This is what a VirtioBus must implement */ + BusClass parent; + void (*notify)(DeviceState *d, uint16_t vector); + void (*save_config)(DeviceState *d, QEMUFile *f); + void (*save_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_config)(DeviceState *d, QEMUFile *f); + int (*load_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_done)(DeviceState *d, QEMUFile *f); + bool (*query_guest_notifiers)(DeviceState *d); + int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign); + int (*set_host_notifier)(DeviceState *d, int n, bool assigned); + void (*vmstate_change)(DeviceState *d, bool running); + /* + * transport independent init function. + * This is called by virtio-bus just after the device is plugged. + */ + void (*device_plugged)(DeviceState *d, Error **errp); + /* + * transport independent exit function. + * This is called by virtio-bus just before the device is unplugged. + */ + void (*device_unplugged)(DeviceState *d); + int (*query_nvectors)(DeviceState *d); + /* + * Does the transport have variable vring alignment? + * (ie can it ever call virtio_queue_set_align()?) + * Note that changing this will break migration for this transport. + */ + bool has_variable_vring_alignment; +} VirtioBusClass; + +struct VirtioBusState { + BusState parent_obj; +}; + +void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp); +void virtio_bus_reset(VirtioBusState *bus); +void virtio_bus_device_unplugged(VirtIODevice *bus); +/* Get the device id of the plugged device. */ +uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus); +/* Get the config_len field of the plugged device. */ +size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus); +/* Get the features of the plugged device. */ +uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus, + uint32_t requested_features); +/* Get bad features of the plugged device. */ +uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus); +/* Get config of the plugged device. */ +void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config); +/* Set config of the plugged device. */ +void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config); + +static inline VirtIODevice *virtio_bus_get_device(VirtioBusState *bus) +{ + BusState *qbus = &bus->parent_obj; + BusChild *kid = QTAILQ_FIRST(&qbus->children); + DeviceState *qdev = kid ? kid->child : NULL; + + /* This is used on the data path, the cast is guaranteed + * to succeed by the qdev machinery. + */ + return (VirtIODevice *)qdev; +} + +#endif /* VIRTIO_BUS_H */ diff --git a/qemu/include/hw/virtio/virtio-gpu.h b/qemu/include/hw/virtio/virtio-gpu.h new file mode 100644 index 000000000..889676147 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-gpu.h @@ -0,0 +1,142 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef _QEMU_VIRTIO_VGA_H +#define _QEMU_VIRTIO_VGA_H + +#include "qemu/queue.h" +#include "ui/qemu-pixman.h" +#include "ui/console.h" +#include "hw/virtio/virtio.h" +#include "hw/pci/pci.h" + +#include "standard-headers/linux/virtio_gpu.h" +#define TYPE_VIRTIO_GPU "virtio-gpu-device" +#define VIRTIO_GPU(obj) \ + OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) + +#define VIRTIO_ID_GPU 16 + +#define VIRTIO_GPU_MAX_SCANOUT 4 + +struct virtio_gpu_simple_resource { + uint32_t resource_id; + uint32_t width; + uint32_t height; + uint32_t format; + struct iovec *iov; + unsigned int iov_cnt; + uint32_t scanout_bitmask; + pixman_image_t *image; + QTAILQ_ENTRY(virtio_gpu_simple_resource) next; +}; + +struct virtio_gpu_scanout { + QemuConsole *con; + DisplaySurface *ds; + uint32_t width, height; + int x, y; + int invalidate; + uint32_t resource_id; + QEMUCursor *current_cursor; +}; + +struct virtio_gpu_requested_state { + uint32_t width, height; + int x, y; +}; + +struct virtio_gpu_conf { + uint32_t max_outputs; +}; + +struct virtio_gpu_ctrl_command { + VirtQueueElement elem; + VirtQueue *vq; + struct virtio_gpu_ctrl_hdr cmd_hdr; + uint32_t error; + bool finished; + QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; +}; + +typedef struct VirtIOGPU { + VirtIODevice parent_obj; + + QEMUBH *ctrl_bh; + QEMUBH *cursor_bh; + VirtQueue *ctrl_vq; + VirtQueue *cursor_vq; + + int enable; + + int config_size; + DeviceState *qdev; + + QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; + QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; + + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT]; + struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT]; + + struct virtio_gpu_conf conf; + int enabled_output_bitmask; + struct virtio_gpu_config virtio_config; + + QEMUTimer *fence_poll; + QEMUTimer *print_stats; + + struct { + uint32_t inflight; + uint32_t max_inflight; + uint32_t requests; + uint32_t req_3d; + uint32_t bytes_3d; + } stats; +} VirtIOGPU; + +extern const GraphicHwOps virtio_gpu_ops; + +/* to share between PCI and VGA */ +#define DEFINE_VIRTIO_GPU_PCI_PROPERTIES(_state) \ + DEFINE_PROP_BIT("ioeventfd", _state, flags, \ + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), \ + DEFINE_PROP_UINT32("vectors", _state, nvectors, 3) + +#define VIRTIO_GPU_FILL_CMD(out) do { \ + size_t s; \ + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + &out, sizeof(out)); \ + if (s != sizeof(out)) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "%s: command size incorrect %zu vs %zu\n", \ + __func__, s, sizeof(out)); \ + return; \ + } \ + } while (0) + +/* virtio-gpu.c */ +void virtio_gpu_ctrl_response(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + struct virtio_gpu_ctrl_hdr *resp, + size_t resp_len); +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + enum virtio_gpu_ctrl_type type); +void virtio_gpu_get_display_info(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd); +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, + struct virtio_gpu_ctrl_command *cmd, + struct iovec **iov); +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count); + +#endif diff --git a/qemu/include/hw/virtio/virtio-input.h b/qemu/include/hw/virtio/virtio-input.h new file mode 100644 index 000000000..af1c207ab --- /dev/null +++ b/qemu/include/hw/virtio/virtio-input.h @@ -0,0 +1,119 @@ +#ifndef _QEMU_VIRTIO_INPUT_H +#define _QEMU_VIRTIO_INPUT_H + +#include "ui/input.h" + +/* ----------------------------------------------------------------- */ +/* virtio input protocol */ + +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_input.h" + +typedef struct virtio_input_absinfo virtio_input_absinfo; +typedef struct virtio_input_config virtio_input_config; +typedef struct virtio_input_event virtio_input_event; + +#if defined(HOST_WORDS_BIGENDIAN) +# define const_le32(_x) \ + (((_x & 0x000000ffU) << 24) | \ + ((_x & 0x0000ff00U) << 8) | \ + ((_x & 0x00ff0000U) >> 8) | \ + ((_x & 0xff000000U) >> 24)) +# define const_le16(_x) \ + (((_x & 0x00ff) << 8) | \ + ((_x & 0xff00) >> 8)) +#else +# define const_le32(_x) (_x) +# define const_le16(_x) (_x) +#endif + +/* ----------------------------------------------------------------- */ +/* qemu internals */ + +#define TYPE_VIRTIO_INPUT "virtio-input-device" +#define VIRTIO_INPUT(obj) \ + OBJECT_CHECK(VirtIOInput, (obj), TYPE_VIRTIO_INPUT) +#define VIRTIO_INPUT_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT) +#define VIRTIO_INPUT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOInputClass, obj, TYPE_VIRTIO_INPUT) +#define VIRTIO_INPUT_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT) + +#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid-device" +#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device" +#define TYPE_VIRTIO_MOUSE "virtio-mouse-device" +#define TYPE_VIRTIO_TABLET "virtio-tablet-device" + +#define VIRTIO_INPUT_HID(obj) \ + OBJECT_CHECK(VirtIOInputHID, (obj), TYPE_VIRTIO_INPUT_HID) +#define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HID) + +#define TYPE_VIRTIO_INPUT_HOST "virtio-input-host-device" +#define VIRTIO_INPUT_HOST(obj) \ + OBJECT_CHECK(VirtIOInputHost, (obj), TYPE_VIRTIO_INPUT_HOST) +#define VIRTIO_INPUT_HOST_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HOST) + +typedef struct VirtIOInput VirtIOInput; +typedef struct VirtIOInputClass VirtIOInputClass; +typedef struct VirtIOInputConfig VirtIOInputConfig; +typedef struct VirtIOInputHID VirtIOInputHID; +typedef struct VirtIOInputHost VirtIOInputHost; + +struct VirtIOInputConfig { + virtio_input_config config; + QTAILQ_ENTRY(VirtIOInputConfig) node; +}; + +struct VirtIOInput { + VirtIODevice parent_obj; + uint8_t cfg_select; + uint8_t cfg_subsel; + uint32_t cfg_size; + QTAILQ_HEAD(, VirtIOInputConfig) cfg_list; + VirtQueue *evt, *sts; + char *serial; + + virtio_input_event *queue; + uint32_t qindex, qsize; + + bool active; +}; + +struct VirtIOInputClass { + /*< private >*/ + VirtioDeviceClass parent; + /*< public >*/ + + DeviceRealize realize; + DeviceUnrealize unrealize; + void (*change_active)(VirtIOInput *vinput); + void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event); +}; + +struct VirtIOInputHID { + VirtIOInput parent_obj; + char *display; + uint32_t head; + QemuInputHandler *handler; + QemuInputHandlerState *hs; + int ledstate; +}; + +struct VirtIOInputHost { + VirtIOInput parent_obj; + char *evdev; + int fd; +}; + +void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event); +void virtio_input_init_config(VirtIOInput *vinput, + virtio_input_config *config); +void virtio_input_add_config(VirtIOInput *vinput, + virtio_input_config *config); +void virtio_input_idstr_config(VirtIOInput *vinput, + uint8_t select, const char *string); + +#endif /* _QEMU_VIRTIO_INPUT_H */ diff --git a/qemu/include/hw/virtio/virtio-net.h b/qemu/include/hw/virtio/virtio-net.h new file mode 100644 index 000000000..60b11d5c2 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-net.h @@ -0,0 +1,103 @@ +/* + * Virtio Network Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_NET_H +#define _QEMU_VIRTIO_NET_H + +#include "standard-headers/linux/virtio_net.h" +#include "hw/virtio/virtio.h" + +#define TYPE_VIRTIO_NET "virtio-net-device" +#define VIRTIO_NET(obj) \ + OBJECT_CHECK(VirtIONet, (obj), TYPE_VIRTIO_NET) + +#define TX_TIMER_INTERVAL 150000 /* 150 us */ + +/* Limit the number of packets that can be sent via a single flush + * of the TX queue. This gives us a guaranteed exit condition and + * ensures fairness in the io path. 256 conveniently matches the + * length of the TX queue and shows a good balance of performance + * and latency. */ +#define TX_BURST 256 + +typedef struct virtio_net_conf +{ + uint32_t txtimer; + int32_t txburst; + char *tx; +} virtio_net_conf; + +/* Maximum packet size we can receive from tap device: header + 64k */ +#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10)) + +typedef struct VirtIONetQueue { + VirtQueue *rx_vq; + VirtQueue *tx_vq; + QEMUTimer *tx_timer; + QEMUBH *tx_bh; + int tx_waiting; + struct { + VirtQueueElement elem; + ssize_t len; + } async_tx; + struct VirtIONet *n; +} VirtIONetQueue; + +typedef struct VirtIONet { + VirtIODevice parent_obj; + uint8_t mac[ETH_ALEN]; + uint16_t status; + VirtIONetQueue *vqs; + VirtQueue *ctrl_vq; + NICState *nic; + uint32_t tx_timeout; + int32_t tx_burst; + uint32_t has_vnet_hdr; + size_t host_hdr_len; + size_t guest_hdr_len; + uint32_t host_features; + uint8_t has_ufo; + int mergeable_rx_bufs; + uint8_t promisc; + uint8_t allmulti; + uint8_t alluni; + uint8_t nomulti; + uint8_t nouni; + uint8_t nobcast; + uint8_t vhost_started; + struct { + uint32_t in_use; + uint32_t first_multi; + uint8_t multi_overflow; + uint8_t uni_overflow; + uint8_t *macs; + } mac_table; + uint32_t *vlans; + virtio_net_conf net_conf; + NICConf nic_conf; + DeviceState *qdev; + int multiqueue; + uint16_t max_queues; + uint16_t curr_queues; + size_t config_size; + char *netclient_name; + char *netclient_type; + uint64_t curr_guest_offloads; + QEMUTimer *announce_timer; + int announce_counter; +} VirtIONet; + +void virtio_net_set_netclient_name(VirtIONet *n, const char *name, + const char *type); + +#endif diff --git a/qemu/include/hw/virtio/virtio-rng.h b/qemu/include/hw/virtio/virtio-rng.h new file mode 100644 index 000000000..3f07de70c --- /dev/null +++ b/qemu/include/hw/virtio/virtio-rng.h @@ -0,0 +1,50 @@ +/* + * Virtio RNG Support + * + * Copyright Red Hat, Inc. 2012 + * Copyright Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef _QEMU_VIRTIO_RNG_H +#define _QEMU_VIRTIO_RNG_H + +#include "sysemu/rng.h" +#include "sysemu/rng-random.h" +#include "standard-headers/linux/virtio_rng.h" + +#define TYPE_VIRTIO_RNG "virtio-rng-device" +#define VIRTIO_RNG(obj) \ + OBJECT_CHECK(VirtIORNG, (obj), TYPE_VIRTIO_RNG) +#define VIRTIO_RNG_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_RNG) + +struct VirtIORNGConf { + RngBackend *rng; + uint64_t max_bytes; + uint32_t period_ms; + RndRandom *default_backend; +}; + +typedef struct VirtIORNG { + VirtIODevice parent_obj; + + /* Only one vq - guest puts buffer(s) on it when it needs entropy */ + VirtQueue *vq; + + VirtIORNGConf conf; + + RngBackend *rng; + + /* We purposefully don't migrate this state. The quota will reset on the + * destination as a result. Rate limiting is host state, not guest state. + */ + QEMUTimer *rate_limit_timer; + int64_t quota_remaining; + bool activate_timer; +} VirtIORNG; + +#endif diff --git a/qemu/include/hw/virtio/virtio-scsi.h b/qemu/include/hw/virtio/virtio-scsi.h new file mode 100644 index 000000000..088fe9f4b --- /dev/null +++ b/qemu/include/hw/virtio/virtio-scsi.h @@ -0,0 +1,166 @@ +/* + * Virtio SCSI HBA + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_SCSI_H +#define _QEMU_VIRTIO_SCSI_H + +/* Override CDB/sense data size: they are dynamic (guest controlled) in QEMU */ +#define VIRTIO_SCSI_CDB_SIZE 0 +#define VIRTIO_SCSI_SENSE_SIZE 0 +#include "standard-headers/linux/virtio_scsi.h" +#include "hw/virtio/virtio.h" +#include "hw/pci/pci.h" +#include "hw/scsi/scsi.h" +#include "sysemu/iothread.h" +#include "hw/virtio/dataplane/vring.h" + +#define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common" +#define VIRTIO_SCSI_COMMON(obj) \ + OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON) + +#define TYPE_VIRTIO_SCSI "virtio-scsi-device" +#define VIRTIO_SCSI(obj) \ + OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI) + +#define VIRTIO_SCSI_VQ_SIZE 128 +#define VIRTIO_SCSI_MAX_CHANNEL 0 +#define VIRTIO_SCSI_MAX_TARGET 255 +#define VIRTIO_SCSI_MAX_LUN 16383 + +typedef struct virtio_scsi_cmd_req VirtIOSCSICmdReq; +typedef struct virtio_scsi_cmd_resp VirtIOSCSICmdResp; +typedef struct virtio_scsi_ctrl_tmf_req VirtIOSCSICtrlTMFReq; +typedef struct virtio_scsi_ctrl_tmf_resp VirtIOSCSICtrlTMFResp; +typedef struct virtio_scsi_ctrl_an_req VirtIOSCSICtrlANReq; +typedef struct virtio_scsi_ctrl_an_resp VirtIOSCSICtrlANResp; +typedef struct virtio_scsi_event VirtIOSCSIEvent; +typedef struct virtio_scsi_config VirtIOSCSIConfig; + +struct VirtIOSCSIConf { + uint32_t num_queues; + uint32_t max_sectors; + uint32_t cmd_per_lun; + char *vhostfd; + char *wwpn; + uint32_t boot_tpgt; + IOThread *iothread; +}; + +struct VirtIOSCSI; + +typedef struct { + struct VirtIOSCSI *parent; + Vring vring; + EventNotifier host_notifier; + EventNotifier guest_notifier; +} VirtIOSCSIVring; + +typedef struct VirtIOSCSICommon { + VirtIODevice parent_obj; + VirtIOSCSIConf conf; + + uint32_t sense_size; + uint32_t cdb_size; + VirtQueue *ctrl_vq; + VirtQueue *event_vq; + VirtQueue **cmd_vqs; +} VirtIOSCSICommon; + +typedef struct VirtIOSCSI { + VirtIOSCSICommon parent_obj; + + SCSIBus bus; + int resetting; + bool events_dropped; + + /* Fields for dataplane below */ + AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ + + /* Vring is used instead of vq in dataplane code, because of the underlying + * memory layer thread safety */ + VirtIOSCSIVring *ctrl_vring; + VirtIOSCSIVring *event_vring; + VirtIOSCSIVring **cmd_vrings; + bool dataplane_started; + bool dataplane_starting; + bool dataplane_stopping; + bool dataplane_disabled; + bool dataplane_fenced; + Error *blocker; + Notifier migration_state_notifier; + uint32_t host_features; +} VirtIOSCSI; + +typedef struct VirtIOSCSIReq { + VirtIOSCSI *dev; + VirtQueue *vq; + QEMUSGList qsgl; + QEMUIOVector resp_iov; + + /* Note: + * - fields before elem are initialized by virtio_scsi_init_req; + * - elem is uninitialized at the time of allocation. + * - fields after elem are zeroed by virtio_scsi_init_req. + * */ + + VirtQueueElement elem; + /* Set by dataplane code. */ + VirtIOSCSIVring *vring; + + union { + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + + /* Used for cancellation of request during TMFs */ + int remaining; + }; + + SCSIRequest *sreq; + size_t resp_size; + enum SCSIXferMode mode; + union { + VirtIOSCSICmdResp cmd; + VirtIOSCSICtrlTMFResp tmf; + VirtIOSCSICtrlANResp an; + VirtIOSCSIEvent event; + } resp; + union { + VirtIOSCSICmdReq cmd; + VirtIOSCSICtrlTMFReq tmf; + VirtIOSCSICtrlANReq an; + } req; +} VirtIOSCSIReq; + +typedef void (*HandleOutput)(VirtIODevice *, VirtQueue *); + +void virtio_scsi_common_realize(DeviceState *dev, Error **errp, + HandleOutput ctrl, HandleOutput evt, + HandleOutput cmd); + +void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); +void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); +bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req); +void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req); +VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_free_req(VirtIOSCSIReq *req); +void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason); + +void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread); +void virtio_scsi_dataplane_start(VirtIOSCSI *s); +void virtio_scsi_dataplane_stop(VirtIOSCSI *s); +void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req); +VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, + VirtIOSCSIVring *vring); + +#endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/qemu/include/hw/virtio/virtio-serial.h b/qemu/include/hw/virtio/virtio-serial.h new file mode 100644 index 000000000..527d0bf62 --- /dev/null +++ b/qemu/include/hw/virtio/virtio-serial.h @@ -0,0 +1,224 @@ +/* + * Virtio Serial / Console Support + * + * Copyright IBM, Corp. 2008 + * Copyright Red Hat, Inc. 2009, 2010 + * + * Authors: + * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> + * Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#ifndef _QEMU_VIRTIO_SERIAL_H +#define _QEMU_VIRTIO_SERIAL_H + +#include "standard-headers/linux/virtio_console.h" +#include "hw/qdev.h" +#include "hw/virtio/virtio.h" + +struct virtio_serial_conf { + /* Max. number of ports we can have for a virtio-serial device */ + uint32_t max_virtserial_ports; +}; + +#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port" +#define VIRTIO_SERIAL_PORT(obj) \ + OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT) +#define VIRTIO_SERIAL_PORT_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT) +#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT) + +typedef struct VirtIOSerial VirtIOSerial; +typedef struct VirtIOSerialBus VirtIOSerialBus; +typedef struct VirtIOSerialPort VirtIOSerialPort; + +typedef struct VirtIOSerialPortClass { + DeviceClass parent_class; + + /* Is this a device that binds with hvc in the guest? */ + bool is_console; + + /* + * The per-port (or per-app) realize function that's called when a + * new device is found on the bus. + */ + DeviceRealize realize; + /* + * Per-port unrealize function that's called when a port gets + * hot-unplugged or removed. + */ + DeviceUnrealize unrealize; + + /* Callbacks for guest events */ + /* Guest opened/closed device. */ + void (*set_guest_connected)(VirtIOSerialPort *port, int guest_connected); + + /* Guest is now ready to accept data (virtqueues set up). */ + void (*guest_ready)(VirtIOSerialPort *port); + + /* + * Guest has enqueued a buffer for the host to write into. + * Called each time a buffer is enqueued by the guest; + * irrespective of whether there already were free buffers the + * host could have consumed. + * + * This is dependent on both the guest and host end being + * connected. + */ + void (*guest_writable)(VirtIOSerialPort *port); + + /* + * Guest wrote some data to the port. This data is handed over to + * the app via this callback. The app can return a size less than + * 'len'. In this case, throttling will be enabled for this port. + */ + ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, + ssize_t len); +} VirtIOSerialPortClass; + +/* + * This is the state that's shared between all the ports. Some of the + * state is configurable via command-line options. Some of it can be + * set by individual devices in their initfn routines. Some of the + * state is set by the generic qdev device init routine. + */ +struct VirtIOSerialPort { + DeviceState dev; + + QTAILQ_ENTRY(VirtIOSerialPort) next; + + /* + * This field gives us the virtio device as well as the qdev bus + * that we are associated with + */ + VirtIOSerial *vser; + + VirtQueue *ivq, *ovq; + + /* + * This name is sent to the guest and exported via sysfs. + * The guest could create symlinks based on this information. + * The name is in the reverse fqdn format, like org.qemu.console.0 + */ + char *name; + + /* + * This id helps identify ports between the guest and the host. + * The guest sends a "header" with this id with each data packet + * that it sends and the host can then find out which associated + * device to send out this data to + */ + uint32_t id; + + /* + * This is the elem that we pop from the virtqueue. A slow + * backend that consumes guest data (e.g. the file backend for + * qemu chardevs) can cause the guest to block till all the output + * is flushed. This isn't desired, so we keep a note of the last + * element popped and continue consuming it once the backend + * becomes writable again. + */ + VirtQueueElement elem; + + /* + * The index and the offset into the iov buffer that was popped in + * elem above. + */ + uint32_t iov_idx; + uint64_t iov_offset; + + /* + * When unthrottling we use a bottom-half to call flush_queued_data. + */ + QEMUBH *bh; + + /* Is the corresponding guest device open? */ + bool guest_connected; + /* Is this device open for IO on the host? */ + bool host_connected; + /* Do apps not want to receive data? */ + bool throttled; +}; + +/* The virtio-serial bus on top of which the ports will ride as devices */ +struct VirtIOSerialBus { + BusState qbus; + + /* This is the parent device that provides the bus for ports. */ + VirtIOSerial *vser; + + /* The maximum number of ports that can ride on top of this bus */ + uint32_t max_nr_ports; +}; + +typedef struct VirtIOSerialPostLoad { + QEMUTimer *timer; + uint32_t nr_active_ports; + struct { + VirtIOSerialPort *port; + uint8_t host_connected; + } *connected; +} VirtIOSerialPostLoad; + +struct VirtIOSerial { + VirtIODevice parent_obj; + + VirtQueue *c_ivq, *c_ovq; + /* Arrays of ivqs and ovqs: one per port */ + VirtQueue **ivqs, **ovqs; + + VirtIOSerialBus bus; + + QTAILQ_HEAD(, VirtIOSerialPort) ports; + + QLIST_ENTRY(VirtIOSerial) next; + + /* bitmap for identifying active ports */ + uint32_t *ports_map; + + struct VirtIOSerialPostLoad *post_load; + + virtio_serial_conf serial; +}; + +/* Interface to the virtio-serial bus */ + +/* + * Open a connection to the port + * Returns 0 on success (always). + */ +int virtio_serial_open(VirtIOSerialPort *port); + +/* + * Close the connection to the port + * Returns 0 on success (always). + */ +int virtio_serial_close(VirtIOSerialPort *port); + +/* + * Send data to Guest + */ +ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf, + size_t size); + +/* + * Query whether a guest is ready to receive data. + */ +size_t virtio_serial_guest_ready(VirtIOSerialPort *port); + +/* + * Flow control: Ports can signal to the virtio-serial core to stop + * sending data or re-start sending data, depending on the 'throttle' + * value here. + */ +void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle); + +#define TYPE_VIRTIO_SERIAL "virtio-serial-device" +#define VIRTIO_SERIAL(obj) \ + OBJECT_CHECK(VirtIOSerial, (obj), TYPE_VIRTIO_SERIAL) + +#endif diff --git a/qemu/include/hw/virtio/virtio.h b/qemu/include/hw/virtio/virtio.h new file mode 100644 index 000000000..cccae89d8 --- /dev/null +++ b/qemu/include/hw/virtio/virtio.h @@ -0,0 +1,290 @@ +/* + * Virtio Support + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef _QEMU_VIRTIO_H +#define _QEMU_VIRTIO_H + +#include "hw/hw.h" +#include "net/net.h" +#include "hw/qdev.h" +#include "sysemu/sysemu.h" +#include "qemu/event_notifier.h" +#include "standard-headers/linux/virtio_config.h" +#include "standard-headers/linux/virtio_ring.h" + +/* A guest should never accept this. It implies negotiation is broken. */ +#define VIRTIO_F_BAD_FEATURE 30 + +#define VIRTIO_LEGACY_FEATURES ((0x1ULL << VIRTIO_F_BAD_FEATURE) | \ + (0x1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \ + (0x1ULL << VIRTIO_F_ANY_LAYOUT)) + +struct VirtQueue; + +static inline hwaddr vring_align(hwaddr addr, + unsigned long align) +{ + return (addr + align - 1) & ~(align - 1); +} + +typedef struct VirtQueue VirtQueue; + +#define VIRTQUEUE_MAX_SIZE 1024 + +typedef struct VirtQueueElement +{ + unsigned int index; + unsigned int out_num; + unsigned int in_num; + hwaddr in_addr[VIRTQUEUE_MAX_SIZE]; + hwaddr out_addr[VIRTQUEUE_MAX_SIZE]; + struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; + struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; +} VirtQueueElement; + +#define VIRTIO_QUEUE_MAX 1024 + +#define VIRTIO_NO_VECTOR 0xffff + +#define TYPE_VIRTIO_DEVICE "virtio-device" +#define VIRTIO_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioDeviceClass, obj, TYPE_VIRTIO_DEVICE) +#define VIRTIO_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, TYPE_VIRTIO_DEVICE) +#define VIRTIO_DEVICE(obj) \ + OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE) + +enum virtio_device_endian { + VIRTIO_DEVICE_ENDIAN_UNKNOWN, + VIRTIO_DEVICE_ENDIAN_LITTLE, + VIRTIO_DEVICE_ENDIAN_BIG, +}; + +struct VirtIODevice +{ + DeviceState parent_obj; + const char *name; + uint8_t status; + uint8_t isr; + uint16_t queue_sel; + uint64_t guest_features; + uint64_t host_features; + size_t config_len; + void *config; + uint16_t config_vector; + uint32_t generation; + int nvectors; + VirtQueue *vq; + uint16_t device_id; + bool vm_running; + VMChangeStateEntry *vmstate; + char *bus_name; + uint8_t device_endian; + QLIST_HEAD(, VirtQueue) *vector_queues; +}; + +typedef struct VirtioDeviceClass { + /*< private >*/ + DeviceClass parent; + /*< public >*/ + + /* This is what a VirtioDevice must implement */ + DeviceRealize realize; + DeviceUnrealize unrealize; + uint64_t (*get_features)(VirtIODevice *vdev, + uint64_t requested_features, + Error **errp); + uint64_t (*bad_features)(VirtIODevice *vdev); + void (*set_features)(VirtIODevice *vdev, uint64_t val); + int (*validate_features)(VirtIODevice *vdev); + void (*get_config)(VirtIODevice *vdev, uint8_t *config); + void (*set_config)(VirtIODevice *vdev, const uint8_t *config); + void (*reset)(VirtIODevice *vdev); + void (*set_status)(VirtIODevice *vdev, uint8_t val); + /* Test and clear event pending status. + * Should be called after unmask to avoid losing events. + * If backend does not support masking, + * must check in frontend instead. + */ + bool (*guest_notifier_pending)(VirtIODevice *vdev, int n); + /* Mask/unmask events from this vq. Any events reported + * while masked will become pending. + * If backend does not support masking, + * must mask in frontend instead. + */ + void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); + void (*save)(VirtIODevice *vdev, QEMUFile *f); + int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); +} VirtioDeviceClass; + +void virtio_instance_init_common(Object *proxy_obj, void *data, + size_t vdev_size, const char *vdev_name); + +void virtio_init(VirtIODevice *vdev, const char *name, + uint16_t device_id, size_t config_size); +void virtio_cleanup(VirtIODevice *vdev); + +/* Set the child bus name. */ +void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name); + +VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + void (*handle_output)(VirtIODevice *, + VirtQueue *)); + +void virtio_del_queue(VirtIODevice *vdev, int n); + +void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len); +void virtqueue_flush(VirtQueue *vq, unsigned int count); +void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len, unsigned int idx); + +void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, + size_t num_sg, int is_write); +int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); +int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, + unsigned int out_bytes); +void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes); + +void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); + +void virtio_save(VirtIODevice *vdev, QEMUFile *f); + +int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); + +void virtio_notify_config(VirtIODevice *vdev); + +void virtio_queue_set_notification(VirtQueue *vq, int enable); + +int virtio_queue_ready(VirtQueue *vq); + +int virtio_queue_empty(VirtQueue *vq); + +/* Host binding interface. */ + +uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); +uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr); +uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr); +void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data); +void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data); +void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data); +uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr); +uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr); +uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr); +void virtio_config_modern_writeb(VirtIODevice *vdev, + uint32_t addr, uint32_t data); +void virtio_config_modern_writew(VirtIODevice *vdev, + uint32_t addr, uint32_t data); +void virtio_config_modern_writel(VirtIODevice *vdev, + uint32_t addr, uint32_t data); +void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr); +hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n); +void virtio_queue_set_num(VirtIODevice *vdev, int n, int num); +int virtio_queue_get_num(VirtIODevice *vdev, int n); +int virtio_get_num_queues(VirtIODevice *vdev); +void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc, + hwaddr avail, hwaddr used); +void virtio_queue_update_rings(VirtIODevice *vdev, int n); +void virtio_queue_set_align(VirtIODevice *vdev, int n, int align); +void virtio_queue_notify(VirtIODevice *vdev, int n); +uint16_t virtio_queue_vector(VirtIODevice *vdev, int n); +void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector); +int virtio_set_status(VirtIODevice *vdev, uint8_t val); +void virtio_reset(void *opaque); +void virtio_update_irq(VirtIODevice *vdev); +int virtio_set_features(VirtIODevice *vdev, uint64_t val); + +/* Base devices. */ +typedef struct VirtIOBlkConf VirtIOBlkConf; +struct virtio_net_conf; +typedef struct virtio_serial_conf virtio_serial_conf; +typedef struct virtio_input_conf virtio_input_conf; +typedef struct VirtIOSCSIConf VirtIOSCSIConf; +typedef struct VirtIORNGConf VirtIORNGConf; + +#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ + DEFINE_PROP_BIT64("indirect_desc", _state, _field, \ + VIRTIO_RING_F_INDIRECT_DESC, true), \ + DEFINE_PROP_BIT64("event_idx", _state, _field, \ + VIRTIO_RING_F_EVENT_IDX, true), \ + DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \ + VIRTIO_F_NOTIFY_ON_EMPTY, true), \ + DEFINE_PROP_BIT64("any_layout", _state, _field, \ + VIRTIO_F_ANY_LAYOUT, true) + +hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n); +uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); +void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); +void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); +VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); +uint16_t virtio_get_queue_index(VirtQueue *vq); +int virtio_queue_get_id(VirtQueue *vq); +EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); +void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, + bool with_irqfd); +EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); +void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, + bool set_handler); +void virtio_queue_notify_vq(VirtQueue *vq); +void virtio_irq(VirtQueue *vq); +VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); +VirtQueue *virtio_vector_next_queue(VirtQueue *vq); + +static inline void virtio_add_feature(uint64_t *features, unsigned int fbit) +{ + assert(fbit < 64); + *features |= (1ULL << fbit); +} + +static inline void virtio_clear_feature(uint64_t *features, unsigned int fbit) +{ + assert(fbit < 64); + *features &= ~(1ULL << fbit); +} + +static inline bool __virtio_has_feature(uint64_t features, unsigned int fbit) +{ + assert(fbit < 64); + return !!(features & (1ULL << fbit)); +} + +static inline bool virtio_has_feature(VirtIODevice *vdev, unsigned int fbit) +{ + return __virtio_has_feature(vdev->guest_features, fbit); +} + +static inline bool virtio_host_has_feature(VirtIODevice *vdev, + unsigned int fbit) +{ + return __virtio_has_feature(vdev->host_features, fbit); +} + +static inline bool virtio_is_big_endian(VirtIODevice *vdev) +{ + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); + return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; + } + /* Devices conforming to VIRTIO 1.0 or later are always LE. */ + return false; +} +#endif |