diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-31 14:01:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-31 14:01:38 -0400 |
commit | 0c86e761b95131943c2b8af2ffb3c0554f9a71f5 (patch) | |
tree | 95f9563ca78ab077b5fbe53618d1fb30bfd28f94 | |
parent | b3491d8430dd25f0a4e00c33d60da22a9bd9d052 (diff) | |
parent | 104c7405a64d937254b6a154938e6151f91c9e0d (diff) |
Merge tag 'vfio-v4.20-rc1.v2' of git://github.com/awilliam/linux-vfio
Pull VFIO updates from Alex Williamson:
- EDID interfaces for vfio devices supporting display extensions (Gerd
Hoffmann)
- Generically select Type-1 IOMMU model support on ARM/ARM64 (Geert
Uytterhoeven)
- Quirk for VFs reporting INTx pin (Alex Williamson)
- Fix error path memory leak in MSI support (Li Qiang)
* tag 'vfio-v4.20-rc1.v2' of git://github.com/awilliam/linux-vfio:
vfio: add edid support to mbochs sample driver
vfio: add edid api for display (vgpu) devices.
drivers/vfio: Allow type-1 IOMMU instantiation with all ARM/ARM64 IOMMUs
vfio/pci: Mask buggy SR-IOV VF INTx support
vfio/pci: Fix potential memory leak in vfio_msi_cap_len
-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); |