diff options
| -rw-r--r-- | drivers/vfio/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 8 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 31 | ||||
| -rw-r--r-- | include/uapi/linux/vfio.h | 50 | ||||
| -rw-r--r-- | samples/vfio-mdev/mbochs.c | 136 |
5 files changed, 204 insertions, 23 deletions
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig index c84333eb5eb5..9de5ed38da83 100644 --- a/drivers/vfio/Kconfig +++ b/drivers/vfio/Kconfig | |||
| @@ -21,7 +21,7 @@ config VFIO_VIRQFD | |||
| 21 | menuconfig VFIO | 21 | menuconfig VFIO |
| 22 | tristate "VFIO Non-Privileged userspace driver framework" | 22 | tristate "VFIO Non-Privileged userspace driver framework" |
| 23 | depends on IOMMU_API | 23 | depends on IOMMU_API |
| 24 | select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM_SMMU || ARM_SMMU_V3) | 24 | select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64) |
| 25 | select ANON_INODES | 25 | select ANON_INODES |
| 26 | help | 26 | help |
| 27 | VFIO provides a framework for secure userspace device drivers. | 27 | VFIO provides a framework for secure userspace device drivers. |
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index cddb453a1ba5..50cdedfca9fe 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
| @@ -434,10 +434,14 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type) | |||
| 434 | { | 434 | { |
| 435 | if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) { | 435 | if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) { |
| 436 | u8 pin; | 436 | u8 pin; |
| 437 | |||
| 438 | if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || | ||
| 439 | vdev->nointx || vdev->pdev->is_virtfn) | ||
| 440 | return 0; | ||
| 441 | |||
| 437 | pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin); | 442 | pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin); |
| 438 | if (IS_ENABLED(CONFIG_VFIO_PCI_INTX) && !vdev->nointx && pin) | ||
| 439 | return 1; | ||
| 440 | 443 | ||
| 444 | return pin ? 1 : 0; | ||
| 441 | } else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) { | 445 | } else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) { |
| 442 | u8 pos; | 446 | u8 pos; |
| 443 | u16 flags; | 447 | u16 flags; |
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 115a36f6f403..423ea1f98441 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c | |||
| @@ -1180,8 +1180,10 @@ static int vfio_msi_cap_len(struct vfio_pci_device *vdev, u8 pos) | |||
| 1180 | return -ENOMEM; | 1180 | return -ENOMEM; |
| 1181 | 1181 | ||
| 1182 | ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags); | 1182 | ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags); |
| 1183 | if (ret) | 1183 | if (ret) { |
| 1184 | kfree(vdev->msi_perm); | ||
| 1184 | return ret; | 1185 | return ret; |
| 1186 | } | ||
| 1185 | 1187 | ||
| 1186 | return len; | 1188 | return len; |
| 1187 | } | 1189 | } |
| @@ -1610,6 +1612,15 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev) | |||
| 1610 | } | 1612 | } |
| 1611 | 1613 | ||
| 1612 | /* | 1614 | /* |
| 1615 | * Nag about hardware bugs, hopefully to have vendors fix them, but at least | ||
| 1616 | * to collect a list of dependencies for the VF INTx pin quirk below. | ||
| 1617 | */ | ||
| 1618 | static const struct pci_device_id known_bogus_vf_intx_pin[] = { | ||
| 1619 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x270c) }, | ||
| 1620 | {} | ||
| 1621 | }; | ||
| 1622 | |||
| 1623 | /* | ||
| 1613 | * For each device we allocate a pci_config_map that indicates the | 1624 | * For each device we allocate a pci_config_map that indicates the |
| 1614 | * capability occupying each dword and thus the struct perm_bits we | 1625 | * capability occupying each dword and thus the struct perm_bits we |
| 1615 | * use for read and write. We also allocate a virtualized config | 1626 | * use for read and write. We also allocate a virtualized config |
| @@ -1674,6 +1685,24 @@ int vfio_config_init(struct vfio_pci_device *vdev) | |||
| 1674 | if (pdev->is_virtfn) { | 1685 | if (pdev->is_virtfn) { |
| 1675 | *(__le16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor); | 1686 | *(__le16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor); |
| 1676 | *(__le16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device); | 1687 | *(__le16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device); |
| 1688 | |||
| 1689 | /* | ||
| 1690 | * Per SR-IOV spec rev 1.1, 3.4.1.18 the interrupt pin register | ||
| 1691 | * does not apply to VFs and VFs must implement this register | ||
| 1692 | * as read-only with value zero. Userspace is not readily able | ||
| 1693 | * to identify whether a device is a VF and thus that the pin | ||
| 1694 | * definition on the device is bogus should it violate this | ||
| 1695 | * requirement. We already virtualize the pin register for | ||
| 1696 | * other purposes, so we simply need to replace the bogus value | ||
| 1697 | * and consider VFs when we determine INTx IRQ count. | ||
| 1698 | */ | ||
| 1699 | if (vconfig[PCI_INTERRUPT_PIN] && | ||
| 1700 | !pci_match_id(known_bogus_vf_intx_pin, pdev)) | ||
| 1701 | pci_warn(pdev, | ||
| 1702 | "Hardware bug: VF reports bogus INTx pin %d\n", | ||
| 1703 | vconfig[PCI_INTERRUPT_PIN]); | ||
| 1704 | |||
| 1705 | vconfig[PCI_INTERRUPT_PIN] = 0; /* Gratuitous for good VFs */ | ||
| 1677 | } | 1706 | } |
| 1678 | 1707 | ||
| 1679 | if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx) | 1708 | if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx) |
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index f378b9802d8b..813102810f53 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h | |||
| @@ -303,6 +303,56 @@ struct vfio_region_info_cap_type { | |||
| 303 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) | 303 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) |
| 304 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) | 304 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) |
| 305 | 305 | ||
| 306 | #define VFIO_REGION_TYPE_GFX (1) | ||
| 307 | #define VFIO_REGION_SUBTYPE_GFX_EDID (1) | ||
| 308 | |||
| 309 | /** | ||
| 310 | * struct vfio_region_gfx_edid - EDID region layout. | ||
| 311 | * | ||
| 312 | * Set display link state and EDID blob. | ||
| 313 | * | ||
| 314 | * The EDID blob has monitor information such as brand, name, serial | ||
| 315 | * number, physical size, supported video modes and more. | ||
| 316 | * | ||
| 317 | * This special region allows userspace (typically qemu) set a virtual | ||
| 318 | * EDID for the virtual monitor, which allows a flexible display | ||
| 319 | * configuration. | ||
| 320 | * | ||
| 321 | * For the edid blob spec look here: | ||
| 322 | * https://en.wikipedia.org/wiki/Extended_Display_Identification_Data | ||
| 323 | * | ||
| 324 | * On linux systems you can find the EDID blob in sysfs: | ||
| 325 | * /sys/class/drm/${card}/${connector}/edid | ||
| 326 | * | ||
| 327 | * You can use the edid-decode ulility (comes with xorg-x11-utils) to | ||
| 328 | * decode the EDID blob. | ||
| 329 | * | ||
| 330 | * @edid_offset: location of the edid blob, relative to the | ||
| 331 | * start of the region (readonly). | ||
| 332 | * @edid_max_size: max size of the edid blob (readonly). | ||
| 333 | * @edid_size: actual edid size (read/write). | ||
| 334 | * @link_state: display link state (read/write). | ||
| 335 | * VFIO_DEVICE_GFX_LINK_STATE_UP: Monitor is turned on. | ||
| 336 | * VFIO_DEVICE_GFX_LINK_STATE_DOWN: Monitor is turned off. | ||
| 337 | * @max_xres: max display width (0 == no limitation, readonly). | ||
| 338 | * @max_yres: max display height (0 == no limitation, readonly). | ||
| 339 | * | ||
| 340 | * EDID update protocol: | ||
| 341 | * (1) set link-state to down. | ||
| 342 | * (2) update edid blob and size. | ||
| 343 | * (3) set link-state to up. | ||
| 344 | */ | ||
| 345 | struct vfio_region_gfx_edid { | ||
| 346 | __u32 edid_offset; | ||
| 347 | __u32 edid_max_size; | ||
| 348 | __u32 edid_size; | ||
| 349 | __u32 max_xres; | ||
| 350 | __u32 max_yres; | ||
| 351 | __u32 link_state; | ||
| 352 | #define VFIO_DEVICE_GFX_LINK_STATE_UP 1 | ||
| 353 | #define VFIO_DEVICE_GFX_LINK_STATE_DOWN 2 | ||
| 354 | }; | ||
| 355 | |||
| 306 | /* | 356 | /* |
| 307 | * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped | 357 | * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped |
| 308 | * which allows direct access to non-MSIX registers which happened to be within | 358 | * which allows direct access to non-MSIX registers which happened to be within |
diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index 2535c3677c7b..ca7960adf5a3 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c | |||
| @@ -71,11 +71,19 @@ | |||
| 71 | #define MBOCHS_NAME "mbochs" | 71 | #define MBOCHS_NAME "mbochs" |
| 72 | #define MBOCHS_CLASS_NAME "mbochs" | 72 | #define MBOCHS_CLASS_NAME "mbochs" |
| 73 | 73 | ||
| 74 | #define MBOCHS_EDID_REGION_INDEX VFIO_PCI_NUM_REGIONS | ||
| 75 | #define MBOCHS_NUM_REGIONS (MBOCHS_EDID_REGION_INDEX+1) | ||
| 76 | |||
| 74 | #define MBOCHS_CONFIG_SPACE_SIZE 0xff | 77 | #define MBOCHS_CONFIG_SPACE_SIZE 0xff |
| 75 | #define MBOCHS_MMIO_BAR_OFFSET PAGE_SIZE | 78 | #define MBOCHS_MMIO_BAR_OFFSET PAGE_SIZE |
| 76 | #define MBOCHS_MMIO_BAR_SIZE PAGE_SIZE | 79 | #define MBOCHS_MMIO_BAR_SIZE PAGE_SIZE |
| 77 | #define MBOCHS_MEMORY_BAR_OFFSET (MBOCHS_MMIO_BAR_OFFSET + \ | 80 | #define MBOCHS_EDID_OFFSET (MBOCHS_MMIO_BAR_OFFSET + \ |
| 78 | MBOCHS_MMIO_BAR_SIZE) | 81 | MBOCHS_MMIO_BAR_SIZE) |
| 82 | #define MBOCHS_EDID_SIZE PAGE_SIZE | ||
| 83 | #define MBOCHS_MEMORY_BAR_OFFSET (MBOCHS_EDID_OFFSET + \ | ||
| 84 | MBOCHS_EDID_SIZE) | ||
| 85 | |||
| 86 | #define MBOCHS_EDID_BLOB_OFFSET (MBOCHS_EDID_SIZE/2) | ||
| 79 | 87 | ||
| 80 | #define STORE_LE16(addr, val) (*(u16 *)addr = val) | 88 | #define STORE_LE16(addr, val) (*(u16 *)addr = val) |
| 81 | #define STORE_LE32(addr, val) (*(u32 *)addr = val) | 89 | #define STORE_LE32(addr, val) (*(u32 *)addr = val) |
| @@ -95,16 +103,24 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices"); | |||
| 95 | static const struct mbochs_type { | 103 | static const struct mbochs_type { |
| 96 | const char *name; | 104 | const char *name; |
| 97 | u32 mbytes; | 105 | u32 mbytes; |
| 106 | u32 max_x; | ||
| 107 | u32 max_y; | ||
| 98 | } mbochs_types[] = { | 108 | } mbochs_types[] = { |
| 99 | { | 109 | { |
| 100 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, | 110 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, |
| 101 | .mbytes = 4, | 111 | .mbytes = 4, |
| 112 | .max_x = 800, | ||
| 113 | .max_y = 600, | ||
| 102 | }, { | 114 | }, { |
| 103 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, | 115 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, |
| 104 | .mbytes = 16, | 116 | .mbytes = 16, |
| 117 | .max_x = 1920, | ||
| 118 | .max_y = 1440, | ||
| 105 | }, { | 119 | }, { |
| 106 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, | 120 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, |
| 107 | .mbytes = 64, | 121 | .mbytes = 64, |
| 122 | .max_x = 0, | ||
| 123 | .max_y = 0, | ||
| 108 | }, | 124 | }, |
| 109 | }; | 125 | }; |
| 110 | 126 | ||
| @@ -115,6 +131,11 @@ static struct cdev mbochs_cdev; | |||
| 115 | static struct device mbochs_dev; | 131 | static struct device mbochs_dev; |
| 116 | static int mbochs_used_mbytes; | 132 | static int mbochs_used_mbytes; |
| 117 | 133 | ||
| 134 | struct vfio_region_info_ext { | ||
| 135 | struct vfio_region_info base; | ||
| 136 | struct vfio_region_info_cap_type type; | ||
| 137 | }; | ||
| 138 | |||
| 118 | struct mbochs_mode { | 139 | struct mbochs_mode { |
| 119 | u32 drm_format; | 140 | u32 drm_format; |
| 120 | u32 bytepp; | 141 | u32 bytepp; |
| @@ -144,13 +165,14 @@ struct mdev_state { | |||
| 144 | u32 memory_bar_mask; | 165 | u32 memory_bar_mask; |
| 145 | struct mutex ops_lock; | 166 | struct mutex ops_lock; |
| 146 | struct mdev_device *mdev; | 167 | struct mdev_device *mdev; |
| 147 | struct vfio_device_info dev_info; | ||
| 148 | 168 | ||
| 149 | const struct mbochs_type *type; | 169 | const struct mbochs_type *type; |
| 150 | u16 vbe[VBE_DISPI_INDEX_COUNT]; | 170 | u16 vbe[VBE_DISPI_INDEX_COUNT]; |
| 151 | u64 memsize; | 171 | u64 memsize; |
| 152 | struct page **pages; | 172 | struct page **pages; |
| 153 | pgoff_t pagecount; | 173 | pgoff_t pagecount; |
| 174 | struct vfio_region_gfx_edid edid_regs; | ||
| 175 | u8 edid_blob[0x400]; | ||
| 154 | 176 | ||
| 155 | struct list_head dmabufs; | 177 | struct list_head dmabufs; |
| 156 | u32 active_id; | 178 | u32 active_id; |
| @@ -342,10 +364,20 @@ static void handle_mmio_read(struct mdev_state *mdev_state, u16 offset, | |||
| 342 | char *buf, u32 count) | 364 | char *buf, u32 count) |
| 343 | { | 365 | { |
| 344 | struct device *dev = mdev_dev(mdev_state->mdev); | 366 | struct device *dev = mdev_dev(mdev_state->mdev); |
| 367 | struct vfio_region_gfx_edid *edid; | ||
| 345 | u16 reg16 = 0; | 368 | u16 reg16 = 0; |
| 346 | int index; | 369 | int index; |
| 347 | 370 | ||
| 348 | switch (offset) { | 371 | switch (offset) { |
| 372 | case 0x000 ... 0x3ff: /* edid block */ | ||
| 373 | edid = &mdev_state->edid_regs; | ||
| 374 | if (edid->link_state != VFIO_DEVICE_GFX_LINK_STATE_UP || | ||
| 375 | offset >= edid->edid_size) { | ||
| 376 | memset(buf, 0, count); | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | memcpy(buf, mdev_state->edid_blob + offset, count); | ||
| 380 | break; | ||
| 349 | case 0x500 ... 0x515: /* bochs dispi interface */ | 381 | case 0x500 ... 0x515: /* bochs dispi interface */ |
| 350 | if (count != 2) | 382 | if (count != 2) |
| 351 | goto unhandled; | 383 | goto unhandled; |
| @@ -365,6 +397,44 @@ unhandled: | |||
| 365 | } | 397 | } |
| 366 | } | 398 | } |
| 367 | 399 | ||
| 400 | static void handle_edid_regs(struct mdev_state *mdev_state, u16 offset, | ||
| 401 | char *buf, u32 count, bool is_write) | ||
| 402 | { | ||
| 403 | char *regs = (void *)&mdev_state->edid_regs; | ||
| 404 | |||
| 405 | if (offset + count > sizeof(mdev_state->edid_regs)) | ||
| 406 | return; | ||
| 407 | if (count != 4) | ||
| 408 | return; | ||
| 409 | if (offset % 4) | ||
| 410 | return; | ||
| 411 | |||
| 412 | if (is_write) { | ||
| 413 | switch (offset) { | ||
| 414 | case offsetof(struct vfio_region_gfx_edid, link_state): | ||
| 415 | case offsetof(struct vfio_region_gfx_edid, edid_size): | ||
| 416 | memcpy(regs + offset, buf, count); | ||
| 417 | break; | ||
| 418 | default: | ||
| 419 | /* read-only regs */ | ||
| 420 | break; | ||
| 421 | } | ||
| 422 | } else { | ||
| 423 | memcpy(buf, regs + offset, count); | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | static void handle_edid_blob(struct mdev_state *mdev_state, u16 offset, | ||
| 428 | char *buf, u32 count, bool is_write) | ||
| 429 | { | ||
| 430 | if (offset + count > mdev_state->edid_regs.edid_max_size) | ||
| 431 | return; | ||
| 432 | if (is_write) | ||
| 433 | memcpy(mdev_state->edid_blob + offset, buf, count); | ||
| 434 | else | ||
| 435 | memcpy(buf, mdev_state->edid_blob + offset, count); | ||
| 436 | } | ||
| 437 | |||
| 368 | static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count, | 438 | static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count, |
| 369 | loff_t pos, bool is_write) | 439 | loff_t pos, bool is_write) |
| 370 | { | 440 | { |
| @@ -384,13 +454,25 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count, | |||
| 384 | memcpy(buf, (mdev_state->vconfig + pos), count); | 454 | memcpy(buf, (mdev_state->vconfig + pos), count); |
| 385 | 455 | ||
| 386 | } else if (pos >= MBOCHS_MMIO_BAR_OFFSET && | 456 | } else if (pos >= MBOCHS_MMIO_BAR_OFFSET && |
| 387 | pos + count <= MBOCHS_MEMORY_BAR_OFFSET) { | 457 | pos + count <= (MBOCHS_MMIO_BAR_OFFSET + |
| 458 | MBOCHS_MMIO_BAR_SIZE)) { | ||
| 388 | pos -= MBOCHS_MMIO_BAR_OFFSET; | 459 | pos -= MBOCHS_MMIO_BAR_OFFSET; |
| 389 | if (is_write) | 460 | if (is_write) |
| 390 | handle_mmio_write(mdev_state, pos, buf, count); | 461 | handle_mmio_write(mdev_state, pos, buf, count); |
| 391 | else | 462 | else |
| 392 | handle_mmio_read(mdev_state, pos, buf, count); | 463 | handle_mmio_read(mdev_state, pos, buf, count); |
| 393 | 464 | ||
| 465 | } else if (pos >= MBOCHS_EDID_OFFSET && | ||
| 466 | pos + count <= (MBOCHS_EDID_OFFSET + | ||
| 467 | MBOCHS_EDID_SIZE)) { | ||
| 468 | pos -= MBOCHS_EDID_OFFSET; | ||
| 469 | if (pos < MBOCHS_EDID_BLOB_OFFSET) { | ||
| 470 | handle_edid_regs(mdev_state, pos, buf, count, is_write); | ||
| 471 | } else { | ||
| 472 | pos -= MBOCHS_EDID_BLOB_OFFSET; | ||
| 473 | handle_edid_blob(mdev_state, pos, buf, count, is_write); | ||
| 474 | } | ||
| 475 | |||
| 394 | } else if (pos >= MBOCHS_MEMORY_BAR_OFFSET && | 476 | } else if (pos >= MBOCHS_MEMORY_BAR_OFFSET && |
| 395 | pos + count <= | 477 | pos + count <= |
| 396 | MBOCHS_MEMORY_BAR_OFFSET + mdev_state->memsize) { | 478 | MBOCHS_MEMORY_BAR_OFFSET + mdev_state->memsize) { |
| @@ -471,6 +553,10 @@ static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev) | |||
| 471 | mdev_state->next_id = 1; | 553 | mdev_state->next_id = 1; |
| 472 | 554 | ||
| 473 | mdev_state->type = type; | 555 | mdev_state->type = type; |
| 556 | mdev_state->edid_regs.max_xres = type->max_x; | ||
| 557 | mdev_state->edid_regs.max_yres = type->max_y; | ||
| 558 | mdev_state->edid_regs.edid_offset = MBOCHS_EDID_BLOB_OFFSET; | ||
| 559 | mdev_state->edid_regs.edid_max_size = sizeof(mdev_state->edid_blob); | ||
| 474 | mbochs_create_config_space(mdev_state); | 560 | mbochs_create_config_space(mdev_state); |
| 475 | mbochs_reset(mdev); | 561 | mbochs_reset(mdev); |
| 476 | 562 | ||
| @@ -932,16 +1018,16 @@ static int mbochs_dmabuf_export(struct mbochs_dmabuf *dmabuf) | |||
| 932 | } | 1018 | } |
| 933 | 1019 | ||
| 934 | static int mbochs_get_region_info(struct mdev_device *mdev, | 1020 | static int mbochs_get_region_info(struct mdev_device *mdev, |
| 935 | struct vfio_region_info *region_info, | 1021 | struct vfio_region_info_ext *ext) |
| 936 | u16 *cap_type_id, void **cap_type) | ||
| 937 | { | 1022 | { |
| 1023 | struct vfio_region_info *region_info = &ext->base; | ||
| 938 | struct mdev_state *mdev_state; | 1024 | struct mdev_state *mdev_state; |
| 939 | 1025 | ||
| 940 | mdev_state = mdev_get_drvdata(mdev); | 1026 | mdev_state = mdev_get_drvdata(mdev); |
| 941 | if (!mdev_state) | 1027 | if (!mdev_state) |
| 942 | return -EINVAL; | 1028 | return -EINVAL; |
| 943 | 1029 | ||
| 944 | if (region_info->index >= VFIO_PCI_NUM_REGIONS) | 1030 | if (region_info->index >= MBOCHS_NUM_REGIONS) |
| 945 | return -EINVAL; | 1031 | return -EINVAL; |
| 946 | 1032 | ||
| 947 | switch (region_info->index) { | 1033 | switch (region_info->index) { |
| @@ -964,6 +1050,20 @@ static int mbochs_get_region_info(struct mdev_device *mdev, | |||
| 964 | region_info->flags = (VFIO_REGION_INFO_FLAG_READ | | 1050 | region_info->flags = (VFIO_REGION_INFO_FLAG_READ | |
| 965 | VFIO_REGION_INFO_FLAG_WRITE); | 1051 | VFIO_REGION_INFO_FLAG_WRITE); |
| 966 | break; | 1052 | break; |
| 1053 | case MBOCHS_EDID_REGION_INDEX: | ||
| 1054 | ext->base.argsz = sizeof(*ext); | ||
| 1055 | ext->base.offset = MBOCHS_EDID_OFFSET; | ||
| 1056 | ext->base.size = MBOCHS_EDID_SIZE; | ||
| 1057 | ext->base.flags = (VFIO_REGION_INFO_FLAG_READ | | ||
| 1058 | VFIO_REGION_INFO_FLAG_WRITE | | ||
| 1059 | VFIO_REGION_INFO_FLAG_CAPS); | ||
| 1060 | ext->base.cap_offset = offsetof(typeof(*ext), type); | ||
| 1061 | ext->type.header.id = VFIO_REGION_INFO_CAP_TYPE; | ||
| 1062 | ext->type.header.version = 1; | ||
| 1063 | ext->type.header.next = 0; | ||
| 1064 | ext->type.type = VFIO_REGION_TYPE_GFX; | ||
| 1065 | ext->type.subtype = VFIO_REGION_SUBTYPE_GFX_EDID; | ||
| 1066 | break; | ||
| 967 | default: | 1067 | default: |
| 968 | region_info->size = 0; | 1068 | region_info->size = 0; |
| 969 | region_info->offset = 0; | 1069 | region_info->offset = 0; |
| @@ -984,7 +1084,7 @@ static int mbochs_get_device_info(struct mdev_device *mdev, | |||
| 984 | struct vfio_device_info *dev_info) | 1084 | struct vfio_device_info *dev_info) |
| 985 | { | 1085 | { |
| 986 | dev_info->flags = VFIO_DEVICE_FLAGS_PCI; | 1086 | dev_info->flags = VFIO_DEVICE_FLAGS_PCI; |
| 987 | dev_info->num_regions = VFIO_PCI_NUM_REGIONS; | 1087 | dev_info->num_regions = MBOCHS_NUM_REGIONS; |
| 988 | dev_info->num_irqs = VFIO_PCI_NUM_IRQS; | 1088 | dev_info->num_irqs = VFIO_PCI_NUM_IRQS; |
| 989 | return 0; | 1089 | return 0; |
| 990 | } | 1090 | } |
| @@ -1084,7 +1184,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1084 | unsigned long arg) | 1184 | unsigned long arg) |
| 1085 | { | 1185 | { |
| 1086 | int ret = 0; | 1186 | int ret = 0; |
| 1087 | unsigned long minsz; | 1187 | unsigned long minsz, outsz; |
| 1088 | struct mdev_state *mdev_state; | 1188 | struct mdev_state *mdev_state; |
| 1089 | 1189 | ||
| 1090 | mdev_state = mdev_get_drvdata(mdev); | 1190 | mdev_state = mdev_get_drvdata(mdev); |
| @@ -1106,8 +1206,6 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1106 | if (ret) | 1206 | if (ret) |
| 1107 | return ret; | 1207 | return ret; |
| 1108 | 1208 | ||
| 1109 | memcpy(&mdev_state->dev_info, &info, sizeof(info)); | ||
| 1110 | |||
| 1111 | if (copy_to_user((void __user *)arg, &info, minsz)) | 1209 | if (copy_to_user((void __user *)arg, &info, minsz)) |
| 1112 | return -EFAULT; | 1210 | return -EFAULT; |
| 1113 | 1211 | ||
| @@ -1115,24 +1213,24 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1115 | } | 1213 | } |
| 1116 | case VFIO_DEVICE_GET_REGION_INFO: | 1214 | case VFIO_DEVICE_GET_REGION_INFO: |
| 1117 | { | 1215 | { |
| 1118 | struct vfio_region_info info; | 1216 | struct vfio_region_info_ext info; |
| 1119 | u16 cap_type_id = 0; | ||
| 1120 | void *cap_type = NULL; | ||
| 1121 | 1217 | ||
| 1122 | minsz = offsetofend(struct vfio_region_info, offset); | 1218 | minsz = offsetofend(typeof(info), base.offset); |
| 1123 | 1219 | ||
| 1124 | if (copy_from_user(&info, (void __user *)arg, minsz)) | 1220 | if (copy_from_user(&info, (void __user *)arg, minsz)) |
| 1125 | return -EFAULT; | 1221 | return -EFAULT; |
| 1126 | 1222 | ||
| 1127 | if (info.argsz < minsz) | 1223 | outsz = info.base.argsz; |
| 1224 | if (outsz < minsz) | ||
| 1225 | return -EINVAL; | ||
| 1226 | if (outsz > sizeof(info)) | ||
| 1128 | return -EINVAL; | 1227 | return -EINVAL; |
| 1129 | 1228 | ||
| 1130 | ret = mbochs_get_region_info(mdev, &info, &cap_type_id, | 1229 | ret = mbochs_get_region_info(mdev, &info); |
| 1131 | &cap_type); | ||
| 1132 | if (ret) | 1230 | if (ret) |
| 1133 | return ret; | 1231 | return ret; |
| 1134 | 1232 | ||
| 1135 | if (copy_to_user((void __user *)arg, &info, minsz)) | 1233 | if (copy_to_user((void __user *)arg, &info, outsz)) |
| 1136 | return -EFAULT; | 1234 | return -EFAULT; |
| 1137 | 1235 | ||
| 1138 | return 0; | 1236 | return 0; |
| @@ -1148,7 +1246,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1148 | return -EFAULT; | 1246 | return -EFAULT; |
| 1149 | 1247 | ||
| 1150 | if ((info.argsz < minsz) || | 1248 | if ((info.argsz < minsz) || |
| 1151 | (info.index >= mdev_state->dev_info.num_irqs)) | 1249 | (info.index >= VFIO_PCI_NUM_IRQS)) |
| 1152 | return -EINVAL; | 1250 | return -EINVAL; |
| 1153 | 1251 | ||
| 1154 | ret = mbochs_get_irq_info(mdev, &info); | 1252 | ret = mbochs_get_irq_info(mdev, &info); |
