#include "kvm/virtio-pci.h" #include "kvm/ioport.h" #include "kvm/virtio.h" #include "kvm/virtio-pci-dev.h" #include #define VPCI_CFG_COMMON_SIZE sizeof(struct virtio_pci_common_cfg) #define VPCI_CFG_COMMON_START 0 #define VPCI_CFG_COMMON_END (VPCI_CFG_COMMON_SIZE - 1) /* * Use a naturally aligned 4-byte doorbell, in case we ever want to * implement VIRTIO_F_NOTIFICATION_DATA */ #define VPCI_CFG_NOTIFY_SIZE 4 #define VPCI_CFG_NOTIFY_START (VPCI_CFG_COMMON_END + 1) #define VPCI_CFG_NOTIFY_END (VPCI_CFG_COMMON_END + VPCI_CFG_NOTIFY_SIZE) #define VPCI_CFG_ISR_SIZE 4 #define VPCI_CFG_ISR_START (VPCI_CFG_NOTIFY_END + 1) #define VPCI_CFG_ISR_END (VPCI_CFG_NOTIFY_END + VPCI_CFG_ISR_SIZE) /* * We're at 64 bytes. Use the remaining 192 bytes in PCI_IO_SIZE for the * device-specific config space. It's sufficient for the devices we * currently implement (virtio_blk_config is 60 bytes) and, I think, all * existing virtio 1.2 devices. */ #define VPCI_CFG_DEV_START (VPCI_CFG_ISR_END + 1) #define VPCI_CFG_DEV_END ((PCI_IO_SIZE) - 1) #define VPCI_CFG_DEV_SIZE (VPCI_CFG_DEV_END - VPCI_CFG_DEV_START + 1) #define vpci_selected_vq(vpci) \ vdev->ops->get_vq((vpci)->kvm, (vpci)->dev, (vpci)->queue_selector) typedef bool (*access_handler_t)(struct virtio_device *, unsigned long, void *, int); static bool virtio_pci__common_write(struct virtio_device *vdev, unsigned long offset, void *data, int size) { u64 features; u32 val, gsi, vec; struct virtio_pci *vpci = vdev->virtio; switch (offset - VPCI_CFG_COMMON_START) { case VIRTIO_PCI_COMMON_DFSELECT: vpci->device_features_sel = ioport__read32(data); break; case VIRTIO_PCI_COMMON_GFSELECT: vpci->driver_features_sel = ioport__read32(data); break; case VIRTIO_PCI_COMMON_GF: val = ioport__read32(data); if (vpci->driver_features_sel > 1) break; features = (u64)val << (32 * vpci->driver_features_sel); virtio_set_guest_features(vpci->kvm, vdev, vpci->dev, features); break; case VIRTIO_PCI_COMMON_MSIX: vec = vpci->config_vector = ioport__read16(data); gsi = virtio_pci__add_msix_route(vpci, vec); if (gsi < 0) break; vpci->config_gsi = gsi; break; case VIRTIO_PCI_COMMON_STATUS: vpci->status = ioport__read8(data); virtio_notify_status(vpci->kvm, vdev, vpci->dev, vpci->status); break; case VIRTIO_PCI_COMMON_Q_SELECT: val = ioport__read16(data); if (val >= (u32)vdev->ops->get_vq_count(vpci->kvm, vpci->dev)) pr_warning("invalid vq number %u", val); else vpci->queue_selector = val; break; case VIRTIO_PCI_COMMON_Q_SIZE: vdev->ops->set_size_vq(vpci->kvm, vpci->dev, vpci->queue_selector, ioport__read16(data)); break; case VIRTIO_PCI_COMMON_Q_MSIX: vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data); gsi = virtio_pci__add_msix_route(vpci, vec); if (gsi < 0) break; vpci->gsis[vpci->queue_selector] = gsi; if (vdev->ops->notify_vq_gsi) vdev->ops->notify_vq_gsi(vpci->kvm, vpci->dev, vpci->queue_selector, gsi); break; case VIRTIO_PCI_COMMON_Q_ENABLE: val = ioport__read16(data); if (val) virtio_pci_init_vq(vpci->kvm, vdev, vpci->queue_selector); else virtio_pci_exit_vq(vpci->kvm, vdev, vpci->queue_selector); break; case VIRTIO_PCI_COMMON_Q_DESCLO: vpci_selected_vq(vpci)->vring_addr.desc_lo = ioport__read32(data); break; case VIRTIO_PCI_COMMON_Q_DESCHI: vpci_selected_vq(vpci)->vring_addr.desc_hi = ioport__read32(data); break; case VIRTIO_PCI_COMMON_Q_AVAILLO: vpci_selected_vq(vpci)->vring_addr.avail_lo = ioport__read32(data); break; case VIRTIO_PCI_COMMON_Q_AVAILHI: vpci_selected_vq(vpci)->vring_addr.avail_hi = ioport__read32(data); break; case VIRTIO_PCI_COMMON_Q_USEDLO: vpci_selected_vq(vpci)->vring_addr.used_lo = ioport__read32(data); break; case VIRTIO_PCI_COMMON_Q_USEDHI: vpci_selected_vq(vpci)->vring_addr.used_hi = ioport__read32(data); break; } return true; } static bool virtio_pci__notify_write(struct virtio_device *vdev, unsigned long offset, void *data, int size) { u16 vq = ioport__read16(data); struct virtio_pci *vpci = vdev->virtio; vdev->ops->notify_vq(vpci->kvm, vpci->dev, vq); return true; } static bool virtio_pci__config_write(struct virtio_device *vdev, unsigned long offset, void *data, int size) { struct virtio_pci *vpci = vdev->virtio; return virtio_access_config(vpci->kvm, vdev, vpci->dev, offset - VPCI_CFG_DEV_START, data, size, true); } static bool virtio_pci__common_read(struct virtio_device *vdev, unsigned long offset, void *data, int size) { u32 val; struct virtio_pci *vpci = vdev->virtio; u64 features = 1ULL << VIRTIO_F_VERSION_1; switch (offset - VPCI_CFG_COMMON_START) { case VIRTIO_PCI_COMMON_DFSELECT: val = vpci->device_features_sel; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_DF: if (vpci->device_features_sel > 1) break; features |= vdev->ops->get_host_features(vpci->kvm, vpci->dev); val = features >> (32 * vpci->device_features_sel); ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_GFSELECT: val = vpci->driver_features_sel; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_MSIX: val = vpci->config_vector; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_NUMQ: val = vdev->ops->get_vq_count(vpci->kvm, vpci->dev); ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_STATUS: ioport__write8(data, vpci->status); break; case VIRTIO_PCI_COMMON_CFGGENERATION: /* * The config generation changes when the device updates a * config field larger than 32 bits, that the driver may read * using multiple accesses. Since kvmtool doesn't use any * mutable config field larger than 32 bits, the generation is * constant. */ ioport__write8(data, 0); break; case VIRTIO_PCI_COMMON_Q_SELECT: ioport__write16(data, vpci->queue_selector); break; case VIRTIO_PCI_COMMON_Q_SIZE: val = vdev->ops->get_size_vq(vpci->kvm, vpci->dev, vpci->queue_selector); ioport__write16(data, val); break; case VIRTIO_PCI_COMMON_Q_MSIX: val = vpci->vq_vector[vpci->queue_selector]; ioport__write16(data, val); break; case VIRTIO_PCI_COMMON_Q_ENABLE: val = vpci_selected_vq(vpci)->enabled; ioport__write16(data, val); break; case VIRTIO_PCI_COMMON_Q_NOFF: val = vpci->queue_selector; ioport__write16(data, val); break; case VIRTIO_PCI_COMMON_Q_DESCLO: val = vpci_selected_vq(vpci)->vring_addr.desc_lo; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_Q_DESCHI: val = vpci_selected_vq(vpci)->vring_addr.desc_hi; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_Q_AVAILLO: val = vpci_selected_vq(vpci)->vring_addr.avail_lo; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_Q_AVAILHI: val = vpci_selected_vq(vpci)->vring_addr.avail_hi; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_Q_USEDLO: val = vpci_selected_vq(vpci)->vring_addr.used_lo; ioport__write32(data, val); break; case VIRTIO_PCI_COMMON_Q_USEDHI: val = vpci_selected_vq(vpci)->vring_addr.used_hi; ioport__write32(data, val); break; }; return true; } static bool virtio_pci__isr_read(struct virtio_device *vdev, unsigned long offset, void *data, int size) { struct virtio_pci *vpci = vdev->virtio; if (WARN_ON(offset - VPCI_CFG_ISR_START != 0)) return false; ioport__write8(data, vpci->isr); kvm__irq_line(vpci->kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW); vpci->isr = 0; return 0; } static bool virtio_pci__config_read(struct virtio_device *vdev, unsigned long offset, void *data, int size) { struct virtio_pci *vpci = vdev->virtio; return virtio_access_config(vpci->kvm, vdev, vpci->dev, offset - VPCI_CFG_DEV_START, data, size, false); } static bool virtio_pci_access(struct kvm_cpu *vcpu, struct virtio_device *vdev, unsigned long offset, void *data, int size, bool write) { access_handler_t handler = NULL; switch (offset) { case VPCI_CFG_COMMON_START...VPCI_CFG_COMMON_END: if (write) handler = virtio_pci__common_write; else handler = virtio_pci__common_read; break; case VPCI_CFG_NOTIFY_START...VPCI_CFG_NOTIFY_END: if (write) handler = virtio_pci__notify_write; break; case VPCI_CFG_ISR_START...VPCI_CFG_ISR_END: if (!write) handler = virtio_pci__isr_read; break; case VPCI_CFG_DEV_START...VPCI_CFG_DEV_END: if (write) handler = virtio_pci__config_write; else handler = virtio_pci__config_read; break; } if (!handler) return false; return handler(vdev, offset, data, size); } void virtio_pci_modern__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr) { struct virtio_device *vdev = ptr; struct virtio_pci *vpci = vdev->virtio; u32 mmio_addr = virtio_pci__mmio_addr(vpci); virtio_pci_access(vcpu, vdev, addr - mmio_addr, data, len, is_write); } int virtio_pci_modern_init(struct virtio_device *vdev) { int subsys_id; struct virtio_pci *vpci = vdev->virtio; struct pci_device_header *hdr = &vpci->pci_hdr; subsys_id = le16_to_cpu(hdr->subsys_id); hdr->device_id = cpu_to_le16(PCI_DEVICE_ID_VIRTIO_BASE + subsys_id); hdr->subsys_id = cpu_to_le16(PCI_SUBSYS_ID_VIRTIO_BASE + subsys_id); vpci->doorbell_offset = VPCI_CFG_NOTIFY_START; vdev->endian = VIRTIO_ENDIAN_LE; hdr->msix.next = PCI_CAP_OFF(hdr, virtio); hdr->virtio.common = (struct virtio_pci_cap) { .cap_vndr = PCI_CAP_ID_VNDR, .cap_next = PCI_CAP_OFF(hdr, virtio.notify), .cap_len = sizeof(hdr->virtio.common), .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, .bar = 1, .offset = cpu_to_le32(VPCI_CFG_COMMON_START), .length = cpu_to_le32(VPCI_CFG_COMMON_SIZE), }; BUILD_BUG_ON(VPCI_CFG_COMMON_START & 0x3); hdr->virtio.notify = (struct virtio_pci_notify_cap) { .cap.cap_vndr = PCI_CAP_ID_VNDR, .cap.cap_next = PCI_CAP_OFF(hdr, virtio.isr), .cap.cap_len = sizeof(hdr->virtio.notify), .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG, .cap.bar = 1, .cap.offset = cpu_to_le32(VPCI_CFG_NOTIFY_START), .cap.length = cpu_to_le32(VPCI_CFG_NOTIFY_SIZE), /* * Notify multiplier is 0, meaning that notifications are all on * the same register */ }; BUILD_BUG_ON(VPCI_CFG_NOTIFY_START & 0x3); hdr->virtio.isr = (struct virtio_pci_cap) { .cap_vndr = PCI_CAP_ID_VNDR, .cap_next = PCI_CAP_OFF(hdr, virtio.device), .cap_len = sizeof(hdr->virtio.isr), .cfg_type = VIRTIO_PCI_CAP_ISR_CFG, .bar = 1, .offset = cpu_to_le32(VPCI_CFG_ISR_START), .length = cpu_to_le32(VPCI_CFG_ISR_SIZE), }; hdr->virtio.device = (struct virtio_pci_cap) { .cap_vndr = PCI_CAP_ID_VNDR, .cap_next = PCI_CAP_OFF(hdr, virtio.pci), .cap_len = sizeof(hdr->virtio.device), .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG, .bar = 1, .offset = cpu_to_le32(VPCI_CFG_DEV_START), .length = cpu_to_le32(VPCI_CFG_DEV_SIZE), }; BUILD_BUG_ON(VPCI_CFG_DEV_START & 0x3); /* * TODO: implement this weird proxy capability (it is a "MUST" in the * spec, but I don't know if anyone actually uses it). * It doesn't use any BAR space. Instead the driver writes .cap.offset * and .cap.length to access a register in a BAR. */ hdr->virtio.pci = (struct virtio_pci_cfg_cap) { .cap.cap_vndr = PCI_CAP_ID_VNDR, .cap.cap_next = 0, .cap.cap_len = sizeof(hdr->virtio.pci), .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG, }; return 0; }