* [Qemu-devel] [PATCH 0/3] Towards vfio-base VGA device assignment
@ 2013-01-07 22:21 Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 1/3] qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA Alex Williamson
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Alex Williamson @ 2013-01-07 22:21 UTC (permalink / raw)
To: alex.williamson, kvm; +Cc: qemu-devel
This is the companion series to the vfio-pci kernel series for VGA
support. Combined, these don't do as much as you'd hope. Patch 1
is simpy a header update for the matching vfio kernel changes.
Patch 2 is the meat of the changes, enabling vfio-pci to claim access
to VGA ranges and pass them through to the kernel. The last patch
is a hard coded hack specific to my system and only known to be
needed on a Radeon HD5450 where there seems to be a backdoor for the
VGA BIOS to find the physical address of the device (physical devices
is at 0x4000, virtual device is at 0xc000).
With this and the kernel patch, some devices are able to get through
VGA bios execution. The HD5450 can even sync the monitor and show the
correct thing on the screen if you run something that uses VGA graphic
mode. Seabios seems to think VBE works, but for some reason VGA text
mode doesn't work, the monitor turns off. So, like the kernel side,
I'm posting these for archival purposes and with hopes that someone
may have some ideas on what's still missing. Thanks,
Alex
---
Alex Williamson (3):
qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA
vfio-pci: [NOT FOR COMMIT] Add support for VGA MMIO and I/O port access
vfio-pci: [NOT FOR COMMIT] Hack around HD5450 I/O port backdoor
hw/vfio_pci.c | 182 ++++++++++++++++++++++++++++++++++
linux-headers/asm-powerpc/kvm.h | 86 ++++++++++++++++
linux-headers/asm-powerpc/kvm_para.h | 13 +-
linux-headers/linux/kvm.h | 21 +++-
linux-headers/linux/kvm_para.h | 6 +
linux-headers/linux/vfio.h | 9 +-
linux-headers/linux/virtio_config.h | 6 +
linux-headers/linux/virtio_ring.h | 6 +
8 files changed, 305 insertions(+), 24 deletions(-)
^ permalink raw reply [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 1/3] qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA
2013-01-07 22:21 [Qemu-devel] [PATCH 0/3] Towards vfio-base VGA device assignment Alex Williamson
@ 2013-01-07 22:22 ` Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 2/3] vfio-pci: [NOT FOR COMMIT] Add support for VGA MMIO and I/O port access Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 3/3] vfio-pci: [NOT FOR COMMIT] Hack around HD5450 I/O port backdoor Alex Williamson
2 siblings, 0 replies; 4+ messages in thread
From: Alex Williamson @ 2013-01-07 22:22 UTC (permalink / raw)
To: alex.williamson, kvm; +Cc: qemu-devel
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
| 86 ++++++++++++++++++++++++++++++++++
| 13 +++--
| 21 ++++++--
| 6 +-
| 9 ++--
| 6 +-
| 6 +-
7 files changed, 124 insertions(+), 23 deletions(-)
--git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 1bea4d8..2fba8a6 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -221,6 +221,12 @@ struct kvm_sregs {
__u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */
__u32 dbcr[3];
+ /*
+ * iac/dac registers are 64bit wide, while this API
+ * interface provides only lower 32 bits on 64 bit
+ * processors. ONE_REG interface is added for 64bit
+ * iac/dac registers.
+ */
__u32 iac[4];
__u32 dac[2];
__u32 dvc[2];
@@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params {
__u32 reserved[8];
};
+/* For KVM_PPC_GET_HTAB_FD */
+struct kvm_get_htab_fd {
+ __u64 flags;
+ __u64 start_index;
+ __u64 reserved[2];
+};
+
+/* Values for kvm_get_htab_fd.flags */
+#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1)
+#define KVM_GET_HTAB_WRITE ((__u64)0x2)
+
+/*
+ * Data read on the file descriptor is formatted as a series of
+ * records, each consisting of a header followed by a series of
+ * `n_valid' HPTEs (16 bytes each), which are all valid. Following
+ * those valid HPTEs there are `n_invalid' invalid HPTEs, which
+ * are not represented explicitly in the stream. The same format
+ * is used for writing.
+ */
+struct kvm_get_htab_header {
+ __u32 index;
+ __u16 n_valid;
+ __u16 n_invalid;
+};
+
#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
+#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
+#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
+#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7)
+#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8)
+#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9)
+#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa)
+#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb)
+#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc)
+#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd)
+#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe)
+#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf)
+
+#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10)
+#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11)
+#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12)
+
+#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18)
+#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19)
+#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a)
+#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b)
+#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c)
+#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d)
+#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e)
+#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f)
+
+/* 32 floating-point registers */
+#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20)
+#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n))
+#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f)
+
+/* 32 VMX/Altivec vector registers */
+#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40)
+#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n))
+#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f)
+
+/* 32 double-width FP registers for VSX */
+/* High-order halves overlap with FP regs */
+#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60)
+#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n))
+#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f)
+
+/* FP and vector status/control registers */
+#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80)
+#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81)
+
+/* Virtual processor areas */
+/* For SLB & DTL, address in high (first) half, length in low half */
+#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82)
+#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83)
+#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84)
+
+#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85)
#endif /* __LINUX_KVM_POWERPC_H */
--git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h
index 5e04383..484bcaa 100644
--- a/linux-headers/asm-powerpc/kvm_para.h
+++ b/linux-headers/asm-powerpc/kvm_para.h
@@ -17,8 +17,8 @@
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
-#ifndef _UAPI__POWERPC_KVM_PARA_H__
-#define _UAPI__POWERPC_KVM_PARA_H__
+#ifndef __POWERPC_KVM_PARA_H__
+#define __POWERPC_KVM_PARA_H__
#include <linux/types.h>
@@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared {
};
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
-#define HC_VENDOR_KVM (42 << 16)
-#define HC_EV_SUCCESS 0
-#define HC_EV_UNIMPLEMENTED 12
+
+#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
+
+#include <uapi/asm/epapr_hcalls.h>
#define KVM_FEATURE_MAGIC_PAGE 1
@@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared {
#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
-#endif /* _UAPI__POWERPC_KVM_PARA_H__ */
+#endif /* __POWERPC_KVM_PARA_H__ */
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 81d2feb..bfdbf4d 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -167,10 +167,15 @@ struct kvm_pit_config {
#define KVM_EXIT_OSI 18
#define KVM_EXIT_PAPR_HCALL 19
#define KVM_EXIT_S390_UCONTROL 20
+#define KVM_EXIT_WATCHDOG 21
/* For KVM_EXIT_INTERNAL_ERROR */
-#define KVM_INTERNAL_ERROR_EMULATION 1
-#define KVM_INTERNAL_ERROR_SIMUL_EX 2
+/* Emulate instruction failed. */
+#define KVM_INTERNAL_ERROR_EMULATION 1
+/* Encounter unexpected simultaneous exceptions. */
+#define KVM_INTERNAL_ERROR_SIMUL_EX 2
+/* Encounter unexpected vm-exit due to delivery event. */
+#define KVM_INTERNAL_ERROR_DELIVERY_EV 3
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
@@ -477,6 +482,8 @@ struct kvm_ppc_smmu_info {
struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
};
+#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
+
#define KVMIO 0xAE
/* machine type bits, to be used as argument to KVM_CREATE_VM */
@@ -626,6 +633,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_READONLY_MEM 81
#endif
#define KVM_CAP_IRQFD_RESAMPLE 82
+#define KVM_CAP_PPC_BOOKE_WATCHDOG 83
+#define KVM_CAP_PPC_HTAB_FD 84
#ifdef KVM_CAP_IRQ_ROUTING
@@ -848,6 +857,11 @@ struct kvm_s390_ucas_mapping {
#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
/* Available with KVM_CAP_PPC_ALLOC_HTAB */
#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
+#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce)
+/* Available with KVM_CAP_RMA */
+#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_PPC_HTAB_FD */
+#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd)
/*
* ioctls for vcpu fds
@@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_XCRS */
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
-#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce)
-/* Available with KVM_CAP_RMA */
-#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma)
/* Available with KVM_CAP_SW_TLB */
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
/* Available with KVM_CAP_ONE_REG */
--git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index cea2c5c..7bdcf93 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -1,5 +1,5 @@
-#ifndef _UAPI__LINUX_KVM_PARA_H
-#define _UAPI__LINUX_KVM_PARA_H
+#ifndef __LINUX_KVM_PARA_H
+#define __LINUX_KVM_PARA_H
/*
* This header file provides a method for making a hypercall to the host
@@ -25,4 +25,4 @@
*/
#include <asm/kvm_para.h>
-#endif /* _UAPI__LINUX_KVM_PARA_H */
+#endif /* __LINUX_KVM_PARA_H */
--git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 4758d1b..1effe3f 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -8,8 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef _UAPIVFIO_H
-#define _UAPIVFIO_H
+#ifndef VFIO_H
+#define VFIO_H
#include <linux/types.h>
#include <linux/ioctl.h>
@@ -147,6 +147,7 @@ struct vfio_device_info {
__u32 flags;
#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
+#define VFIO_DEVICE_FLAGS_VGA (1 << 2) /* Device supports VGA ranges */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
};
@@ -303,6 +304,8 @@ enum {
VFIO_PCI_BAR5_REGION_INDEX,
VFIO_PCI_ROM_REGION_INDEX,
VFIO_PCI_CONFIG_REGION_INDEX,
+ VFIO_PCI_LEGACY_MMIO_REGION_INDEX,
+ VFIO_PCI_LEGACY_IOPORT_REGION_INDEX,
VFIO_PCI_NUM_REGIONS
};
@@ -365,4 +368,4 @@ struct vfio_iommu_type1_dma_unmap {
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
-#endif /* _UAPIVFIO_H */
+#endif /* VFIO_H */
--git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h
index b7cda39..4f51d8f 100644
--- a/linux-headers/linux/virtio_config.h
+++ b/linux-headers/linux/virtio_config.h
@@ -1,5 +1,5 @@
-#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H
-#define _UAPI_LINUX_VIRTIO_CONFIG_H
+#ifndef _LINUX_VIRTIO_CONFIG_H
+#define _LINUX_VIRTIO_CONFIG_H
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers.
*
@@ -51,4 +51,4 @@
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
-#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
+#endif /* _LINUX_VIRTIO_CONFIG_H */
--git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h
index 921694a..1b333e2 100644
--- a/linux-headers/linux/virtio_ring.h
+++ b/linux-headers/linux/virtio_ring.h
@@ -1,5 +1,5 @@
-#ifndef _UAPI_LINUX_VIRTIO_RING_H
-#define _UAPI_LINUX_VIRTIO_RING_H
+#ifndef _LINUX_VIRTIO_RING_H
+#define _LINUX_VIRTIO_RING_H
/* An interface for efficient virtio implementation, currently for use by KVM
* and lguest, but hopefully others soon. Do NOT change this since it will
* break existing servers and clients.
@@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old
return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
}
-#endif /* _UAPI_LINUX_VIRTIO_RING_H */
+#endif /* _LINUX_VIRTIO_RING_H */
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 2/3] vfio-pci: [NOT FOR COMMIT] Add support for VGA MMIO and I/O port access
2013-01-07 22:21 [Qemu-devel] [PATCH 0/3] Towards vfio-base VGA device assignment Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 1/3] qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA Alex Williamson
@ 2013-01-07 22:22 ` Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 3/3] vfio-pci: [NOT FOR COMMIT] Hack around HD5450 I/O port backdoor Alex Williamson
2 siblings, 0 replies; 4+ messages in thread
From: Alex Williamson @ 2013-01-07 22:22 UTC (permalink / raw)
To: alex.williamson, kvm; +Cc: qemu-devel
With this, some VGA cards can make it through VGA BIOS init, but I
have yet to see one sync the monitor in VGA text mode. Only tested
with -vga none. This adds a new option to vfio-pci, vga=on, which
enables legacy VGA ranges.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
hw/vfio_pci.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+), 1 deletion(-)
diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c
index 94c61ab..846e8de 100644
--- a/hw/vfio_pci.c
+++ b/hw/vfio_pci.c
@@ -59,6 +59,15 @@ typedef struct VFIOBAR {
uint8_t nr; /* cache the BAR number for debug */
} VFIOBAR;
+typedef struct VFIOLegacyIO {
+ off_t fd_offset;
+ int fd;
+ MemoryRegion mem;
+ off_t region_offset;
+ size_t size;
+ uint32_t flags;
+} VFIOLegacyIO;
+
typedef struct VFIOINTx {
bool pending; /* interrupt pending */
bool kvm_accel; /* set when QEMU bypass through KVM enabled */
@@ -126,10 +135,15 @@ typedef struct VFIODevice {
int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
int interrupt; /* Current interrupt type */
VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
+ VFIOLegacyIO vga[3]; /* 0xa0000, 0x3b0, 0x3c0 */
PCIHostDeviceAddress host;
QLIST_ENTRY(VFIODevice) next;
struct VFIOGroup *group;
+ uint32_t features;
+#define VFIO_FEATURE_ENABLE_VGA_BIT 0
+#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
bool reset_works;
+ bool has_vga;
} VFIODevice;
typedef struct VFIOGroup {
@@ -958,6 +972,87 @@ static const MemoryRegionOps vfio_bar_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static void vfio_legacy_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOLegacyIO *io = opaque;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ off_t offset = io->fd_offset + io->region_offset + addr;
+
+ switch (size) {
+ case 1:
+ buf.byte = data;
+ break;
+ case 2:
+ buf.word = cpu_to_le16(data);
+ break;
+ case 4:
+ buf.dword = cpu_to_le32(data);
+ break;
+ default:
+ hw_error("vfio: unsupported write size, %d bytes\n", size);
+ break;
+ }
+
+ if (pwrite(io->fd, &buf, size, offset) != size) {
+ error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m\n",
+ __func__, io->region_offset + addr, data, size);
+ }
+
+ DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
+ __func__, io->region_offset + addr, data, size);
+}
+
+static uint64_t vfio_legacy_read(void *opaque, hwaddr addr, unsigned size)
+{
+ VFIOLegacyIO *io = opaque;
+ union {
+ uint8_t byte;
+ uint16_t word;
+ uint32_t dword;
+ uint64_t qword;
+ } buf;
+ uint64_t data = 0;
+ off_t offset = io->fd_offset + io->region_offset + addr;
+
+ if (pread(io->fd, &buf, size, offset) != size) {
+ error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m\n",
+ __func__, io->region_offset + addr, size);
+ return (uint64_t)-1;
+ }
+
+ switch (size) {
+ case 1:
+ data = buf.byte;
+ break;
+ case 2:
+ data = le16_to_cpu(buf.word);
+ break;
+ case 4:
+ data = le32_to_cpu(buf.dword);
+ break;
+ default:
+ hw_error("vfio: unsupported read size, %d bytes\n", size);
+ break;
+ }
+
+ DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
+ __func__, io->region_offset + addr, size, data);
+
+ return data;
+}
+
+static const MemoryRegionOps vfio_legacy_ops = {
+ .read = vfio_legacy_read,
+ .write = vfio_legacy_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
/*
* PCI config space
*/
@@ -1498,6 +1593,27 @@ static void vfio_map_bars(VFIODevice *vdev)
for (i = 0; i < PCI_ROM_SLOT; i++) {
vfio_map_bar(vdev, i);
}
+
+ if (vdev->has_vga && (vdev->features & VFIO_FEATURE_ENABLE_VGA)) {
+ memory_region_init_io(&vdev->vga[0].mem, &vfio_legacy_ops,
+ &vdev->vga[0], "vfio-vga-mmio@0xa0000",
+ 0xc0000 - 0xa0000);
+ memory_region_add_subregion_overlap(pci_address_space(&vdev->pdev),
+ 0xa0000, &vdev->vga[0].mem, 1);
+ memory_region_set_coalescing(&vdev->vga[0].mem);
+
+ memory_region_init_io(&vdev->vga[1].mem, &vfio_legacy_ops,
+ &vdev->vga[1], "vfio-vga-io@0x3b0",
+ 0x3bc - 0x3b0);
+ memory_region_add_subregion_overlap(pci_address_space_io(&vdev->pdev),
+ 0x3b0, &vdev->vga[1].mem, 1);
+
+ memory_region_init_io(&vdev->vga[2].mem, &vfio_legacy_ops,
+ &vdev->vga[2], "vfio-vga-io@0x3c0",
+ 0x3e0 - 0x3c0);
+ memory_region_add_subregion_overlap(pci_address_space_io(&vdev->pdev),
+ 0x3c0, &vdev->vga[2].mem, 1);
+ }
}
static void vfio_unmap_bars(VFIODevice *vdev)
@@ -1507,6 +1623,20 @@ static void vfio_unmap_bars(VFIODevice *vdev)
for (i = 0; i < PCI_ROM_SLOT; i++) {
vfio_unmap_bar(vdev, i);
}
+
+ if (vdev->has_vga && (vdev->features & VFIO_FEATURE_ENABLE_VGA)) {
+ memory_region_del_subregion(pci_address_space(&vdev->pdev),
+ &vdev->vga[0].mem);
+ memory_region_destroy(&vdev->vga[0].mem);
+
+ memory_region_del_subregion(pci_address_space_io(&vdev->pdev),
+ &vdev->vga[1].mem);
+ memory_region_destroy(&vdev->vga[1].mem);
+
+ memory_region_del_subregion(pci_address_space_io(&vdev->pdev),
+ &vdev->vga[2].mem);
+ memory_region_destroy(&vdev->vga[2].mem);
+ }
}
/*
@@ -1838,7 +1968,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
error_report("Warning, device %s does not support reset\n", name);
}
- if (dev_info.num_regions != VFIO_PCI_NUM_REGIONS) {
+ if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
error_report("vfio: unexpected number of io regions %u\n",
dev_info.num_regions);
goto error;
@@ -1902,6 +2032,45 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
vdev->config_size = reg_info.size;
vdev->config_offset = reg_info.offset;
+ if (dev_info.num_regions > VFIO_PCI_CONFIG_REGION_INDEX + 1 &&
+ dev_info.flags & VFIO_DEVICE_FLAGS_VGA) {
+ struct vfio_region_info mmio_info, io_info;
+
+ mmio_info.argsz = io_info.argsz = sizeof(struct vfio_region_info);
+ mmio_info.index = VFIO_PCI_LEGACY_MMIO_REGION_INDEX;
+ io_info.index = VFIO_PCI_LEGACY_IOPORT_REGION_INDEX;
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &mmio_info);
+ if (ret) {
+ error_report("vfio: Unable to access VGA MMIO resources: %m\n");
+ ret = 0;
+ goto error;
+ }
+
+ vdev->vga[0].flags = mmio_info.flags;
+ vdev->vga[0].size = mmio_info.size;
+ vdev->vga[0].fd_offset = mmio_info.offset;
+ vdev->vga[0].fd = vdev->fd;
+ vdev->vga[0].region_offset = 0xa0000;
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &io_info);
+ if (ret) {
+ error_report("vfio: Unable to access VGA IOPORT resources: %m\n");
+ ret = 0;
+ goto error;
+ }
+
+ vdev->vga[1].flags = vdev->vga[2].flags = io_info.flags;
+ vdev->vga[1].size = vdev->vga[2].size = io_info.size;
+ vdev->vga[1].fd_offset = vdev->vga[2].fd_offset = io_info.offset;
+ vdev->vga[1].fd = vdev->vga[2].fd = vdev->fd;
+
+ vdev->vga[1].region_offset = 0x3b0;
+ vdev->vga[2].region_offset = 0x3c0;
+
+ vdev->has_vga = true;
+ }
+
error:
if (ret) {
QLIST_REMOVE(vdev, next);
@@ -2096,6 +2265,8 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host),
DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice,
intx.mmap_timeout, 1100),
+ DEFINE_PROP_BIT("vga", VFIODevice, features,
+ VFIO_FEATURE_ENABLE_VGA_BIT, false),
/*
* TODO - support passed fds... is this necessary?
* DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name),
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 3/3] vfio-pci: [NOT FOR COMMIT] Hack around HD5450 I/O port backdoor
2013-01-07 22:21 [Qemu-devel] [PATCH 0/3] Towards vfio-base VGA device assignment Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 1/3] qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 2/3] vfio-pci: [NOT FOR COMMIT] Add support for VGA MMIO and I/O port access Alex Williamson
@ 2013-01-07 22:22 ` Alex Williamson
2 siblings, 0 replies; 4+ messages in thread
From: Alex Williamson @ 2013-01-07 22:22 UTC (permalink / raw)
To: alex.williamson, kvm; +Cc: qemu-devel
This is a hack specific to my system which I haven't even attempted
to generalize yet. The ATI/AMD Radeon HD5450 VGA BIOS appears to have
a backdoor to determine the physical address of the device. It reads
a value matching the top byte of the I/O Port BAR from a register in
VGA I/O port space then uses in/out to that address during BIOS
execution. On my setup the I/O port BAR is at 0x4000 physically and
emulated for the guest at 0xc0000. So I simply look for this access
and replace 0x40 with 0xc0. That's enough for it to get through BIOS
init, but it's still only partially functional (no VGA text mode).
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---
hw/vfio_pci.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c
index 846e8de..5db076f 100644
--- a/hw/vfio_pci.c
+++ b/hw/vfio_pci.c
@@ -1041,6 +1041,15 @@ static uint64_t vfio_legacy_read(void *opaque, hwaddr addr, unsigned size)
break;
}
+ /* XXX - Complete hardcoded hack, need to figure out how common this is and
+ * come up with a device quirk and match host phys to guest phys. This is
+ * only known to be needed for an ATI/AMD Radeon HD5450 which stores the
+ * upper byte of the I/O port address in this unused VGA I/O port register.
+ */
+ if (io->region_offset == 0x3c0 && addr == 3 && size == 1 && data == 0x40) {
+ data = 0xc0;
+ }
+
DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
__func__, io->region_offset + addr, size, data);
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-01-07 22:22 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-07 22:21 [Qemu-devel] [PATCH 0/3] Towards vfio-base VGA device assignment Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 1/3] qemu: [NOT FOR COMMIT] Update linux headers for vfio VGA Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 2/3] vfio-pci: [NOT FOR COMMIT] Add support for VGA MMIO and I/O port access Alex Williamson
2013-01-07 22:22 ` [Qemu-devel] [PATCH 3/3] vfio-pci: [NOT FOR COMMIT] Hack around HD5450 I/O port backdoor Alex Williamson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).