Skip to contentSkip to conversation

vfio-pci: Towards VGA support

PATCH New Alex Williamson 1 participant 2 messages Jan 7, 2013

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover vfio-pci: Towards VGA support

vfio makes a nice interface to start looking at supporting VGA devices assigned to virtual machines (ie. userspace drivers) because we can so easily add additional ranges for a device. In this patch we add legacy MMIO (below 1MB) and I/O port (64k) to devices with PCI class code VGA. We can then use the kernel VGA arbiter service to change chipset routing for each access to the VGA ranges defined in the PCI spec. The rest of the region space not used by VGA is left inaccessible until we add future feature that needs some other legacy range.

There's also a qemu userspace companion series to this which learns how to look for this new feature flag and setup ranges. Together they get a step closer to supporting vfio-based VGA assignment, but it doesn't yet work. I'm posting in this broken state both for archival purposes as well as the hope that someone has ideas of what might be missing or be able to pick up and run with this code.

Some cards are able to get through execution of their VGA BIOS with these patches, but none that I've seen sync the monitor to VGA text mode from seabios. With a hack in qemu for a card specific backdoor on a Radeon HD5450 I've been able to get syslinux graphics mode to work and Windows will use it during normal bootup. I have no idea what might be missing for VGA text mode. Thanks,

Alex

---

Alex Williamson (1):
vfio-pci: [NOT FOR COMMIT] Add support for legacy MMIO & I/O port towards VGA support

 drivers/vfio/pci/vfio_pci.c         |   74 ++++++++++++---
 drivers/vfio/pci/vfio_pci_private.h |    6 +
 drivers/vfio/pci/vfio_pci_rdwr.c    |  170 +++++++++++++++++++++++++++--------
 include/uapi/linux/vfio.h           |    3 +
 4 files changed, 197 insertions(+), 56 deletions(-)
#1 lore raw

PATCH 1/1 vfio-pci: [NOT FOR COMMIT] Add support for legacy MMIO & I/O port towards VGA support

Create two new legacy regions, one for MMIO space below 1MB and another for 64k of I/O port space. For devices of PCI class VGA these ranges will be exposed and allow direct access to the device at the PCI defined VGA addresses, 0xa0000, 0x3b0, 0x3c0. VFIO makes use of the host VGA arbiter to manage host chipset config to route each access to the correct device.

---
 drivers/vfio/pci/vfio_pci.c         |   74 ++++++++++++---
 drivers/vfio/pci/vfio_pci_private.h |    6 +
 drivers/vfio/pci/vfio_pci_rdwr.c    |  170 +++++++++++++++++++++++++++--------
 include/uapi/linux/vfio.h           |    3 +
 4 files changed, 197 insertions(+), 56 deletions(-)
drivers/vfio/pci/vfio_pci.c +59 -15
index b28e66c..8a09c33 100644
@@ -223,9 +223,14 @@ static long vfio_pci_ioctl(void *device_data,
 		if (vdev->reset_works)
 			info.flags |= VFIO_DEVICE_FLAGS_RESET;
 
-		info.num_regions = VFIO_PCI_NUM_REGIONS;
+		info.num_regions = VFIO_PCI_CONFIG_REGION_INDEX + 1;
 		info.num_irqs = VFIO_PCI_NUM_IRQS;
 
+		if ((vdev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+			info.flags |= VFIO_DEVICE_FLAGS_VGA;
+			info.num_regions += 2;
+		}
+
 		return copy_to_user((void __user *)arg, &info, minsz);
 
 	} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
@@ -285,6 +290,26 @@ static long vfio_pci_ioctl(void *device_data,
 			info.flags = VFIO_REGION_INFO_FLAG_READ;
 			break;
 		}
+		case VFIO_PCI_LEGACY_MMIO_REGION_INDEX:
+			if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+				return -EINVAL;
+
+			info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+			info.size = 1024 * 1024;
+			info.flags = VFIO_REGION_INFO_FLAG_READ |
+				     VFIO_REGION_INFO_FLAG_WRITE;
+
+			break;
+		case VFIO_PCI_LEGACY_IOPORT_REGION_INDEX:
+			if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+				return -EINVAL;
+
+			info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+			info.size = 64 * 1024;
+			info.flags = VFIO_REGION_INFO_FLAG_READ |
+				     VFIO_REGION_INFO_FLAG_WRITE;
+
+			break;
 		default:
 			return -EINVAL;
 		}
@@ -376,14 +401,25 @@ static ssize_t vfio_pci_read(void *device_data, char __user *buf,
 	if (index >= VFIO_PCI_NUM_REGIONS)
 		return -EINVAL;
 
-	if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+	switch (index) {
+	case VFIO_PCI_CONFIG_REGION_INDEX:
 		return vfio_pci_config_readwrite(vdev, buf, count, ppos, false);
-	else if (index == VFIO_PCI_ROM_REGION_INDEX)
-		return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
-	else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
-		return vfio_pci_io_readwrite(vdev, buf, count, ppos, false);
-	else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM)
+	case VFIO_PCI_ROM_REGION_INDEX:
 		return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false);
+	case VFIO_PCI_LEGACY_MMIO_REGION_INDEX:
+		return vfio_pci_legacy_mem_readwrite(vdev, buf, count,
+						     ppos, false);
+	case VFIO_PCI_LEGACY_IOPORT_REGION_INDEX:
+		return vfio_pci_legacy_io_readwrite(vdev, buf, count,
+						    ppos, false);
+	default:
+		if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
+			return vfio_pci_io_readwrite(vdev, buf, count,
+						     ppos, false);
+		if (pci_resource_flags(pdev, index) & IORESOURCE_MEM)
+			return vfio_pci_mem_readwrite(vdev, buf, count,
+						      ppos, false);
+	}
 
 	return -EINVAL;
 }
@@ -398,17 +434,25 @@ static ssize_t vfio_pci_write(void *device_data, const char __user *buf,
 	if (index >= VFIO_PCI_NUM_REGIONS)
 		return -EINVAL;
 
-	if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+	switch (index) {
+	case VFIO_PCI_CONFIG_REGION_INDEX:
 		return vfio_pci_config_readwrite(vdev, (char __user *)buf,
 						 count, ppos, true);
-	else if (index == VFIO_PCI_ROM_REGION_INDEX)
+	case VFIO_PCI_ROM_REGION_INDEX:
 		return -EINVAL;
-	else if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
-		return vfio_pci_io_readwrite(vdev, (char __user *)buf,
-					     count, ppos, true);
-	else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) {
-		return vfio_pci_mem_readwrite(vdev, (char __user *)buf,
-					      count, ppos, true);
+	case VFIO_PCI_LEGACY_MMIO_REGION_INDEX:
+		return vfio_pci_legacy_mem_readwrite(vdev, buf, count,
+						     ppos, false);
+	case VFIO_PCI_LEGACY_IOPORT_REGION_INDEX:
+		return vfio_pci_legacy_io_readwrite(vdev, buf, count,
+						    ppos, false);
+	default:
+		if (pci_resource_flags(pdev, index) & IORESOURCE_IO)
+			return vfio_pci_io_readwrite(vdev, (char __user *)buf,
+						     count, ppos, true);
+		if (pci_resource_flags(pdev, index) & IORESOURCE_MEM)
+			return vfio_pci_mem_readwrite(vdev, (char __user *)buf,
+						      count, ppos, true);
 	}
 
 	return -EINVAL;
drivers/vfio/pci/vfio_pci_private.h +6 -0
index 611827c..203cf03 100644
@@ -79,6 +79,12 @@ extern ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev,
 extern ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev,
 				     char __user *buf, size_t count,
 				     loff_t *ppos, bool iswrite);
+extern ssize_t vfio_pci_legacy_mem_readwrite(struct vfio_pci_device *vdev,
+					     char __user *buf, size_t count,
+					     loff_t *ppos, bool iswrite);
+extern ssize_t vfio_pci_legacy_io_readwrite(struct vfio_pci_device *vdev,
+					    char __user *buf, size_t count,
+					    loff_t *ppos, bool iswrite);
 
 extern int vfio_pci_init_perm_bits(void);
 extern void vfio_pci_uninit_perm_bits(void);
drivers/vfio/pci/vfio_pci_rdwr.c +129 -41

224 lines not on this page · raw message

include/uapi/linux/vfio.h +3 -0
index 4758d1b..aa15851 100644
@@ -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
 };