diff options
-rw-r--r-- | drivers/vfio/pci/Kconfig | 10 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 75 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 52 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci_private.h | 19 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci_rdwr.c | 281 | ||||
-rw-r--r-- | drivers/vfio/vfio.c | 35 | ||||
-rw-r--r-- | include/uapi/linux/vfio.h | 9 |
7 files changed, 254 insertions, 227 deletions
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 5980758563eb..c41b01e2b693 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig | |||
@@ -6,3 +6,13 @@ config VFIO_PCI | |||
6 | use of PCI drivers using the VFIO framework. | 6 | use of PCI drivers using the VFIO framework. |
7 | 7 | ||
8 | If you don't know what to do here, say N. | 8 | If you don't know what to do here, say N. |
9 | |||
10 | config VFIO_PCI_VGA | ||
11 | bool "VFIO PCI support for VGA devices" | ||
12 | depends on VFIO_PCI && X86 && VGA_ARB | ||
13 | help | ||
14 | Support for VGA extension to VFIO PCI. This exposes an additional | ||
15 | region on VGA devices for accessing legacy VGA addresses used by | ||
16 | BIOS and generic video drivers. | ||
17 | |||
18 | If you don't know what to do here, say N. | ||
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index b28e66c4376a..8189cb6a86af 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
@@ -84,6 +84,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) | |||
84 | } else | 84 | } else |
85 | vdev->msix_bar = 0xFF; | 85 | vdev->msix_bar = 0xFF; |
86 | 86 | ||
87 | #ifdef CONFIG_VFIO_PCI_VGA | ||
88 | if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | ||
89 | vdev->has_vga = true; | ||
90 | #endif | ||
91 | |||
87 | return 0; | 92 | return 0; |
88 | } | 93 | } |
89 | 94 | ||
@@ -285,6 +290,16 @@ static long vfio_pci_ioctl(void *device_data, | |||
285 | info.flags = VFIO_REGION_INFO_FLAG_READ; | 290 | info.flags = VFIO_REGION_INFO_FLAG_READ; |
286 | break; | 291 | break; |
287 | } | 292 | } |
293 | case VFIO_PCI_VGA_REGION_INDEX: | ||
294 | if (!vdev->has_vga) | ||
295 | return -EINVAL; | ||
296 | |||
297 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
298 | info.size = 0xc0000; | ||
299 | info.flags = VFIO_REGION_INFO_FLAG_READ | | ||
300 | VFIO_REGION_INFO_FLAG_WRITE; | ||
301 | |||
302 | break; | ||
288 | default: | 303 | default: |
289 | return -EINVAL; | 304 | return -EINVAL; |
290 | } | 305 | } |
@@ -366,52 +381,50 @@ static long vfio_pci_ioctl(void *device_data, | |||
366 | return -ENOTTY; | 381 | return -ENOTTY; |
367 | } | 382 | } |
368 | 383 | ||
369 | static ssize_t vfio_pci_read(void *device_data, char __user *buf, | 384 | static ssize_t vfio_pci_rw(void *device_data, char __user *buf, |
370 | size_t count, loff_t *ppos) | 385 | size_t count, loff_t *ppos, bool iswrite) |
371 | { | 386 | { |
372 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | 387 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); |
373 | struct vfio_pci_device *vdev = device_data; | 388 | struct vfio_pci_device *vdev = device_data; |
374 | struct pci_dev *pdev = vdev->pdev; | ||
375 | 389 | ||
376 | if (index >= VFIO_PCI_NUM_REGIONS) | 390 | if (index >= VFIO_PCI_NUM_REGIONS) |
377 | return -EINVAL; | 391 | return -EINVAL; |
378 | 392 | ||
379 | if (index == VFIO_PCI_CONFIG_REGION_INDEX) | 393 | switch (index) { |
380 | return vfio_pci_config_readwrite(vdev, buf, count, ppos, false); | 394 | case VFIO_PCI_CONFIG_REGION_INDEX: |
381 | else if (index == VFIO_PCI_ROM_REGION_INDEX) | 395 | return vfio_pci_config_rw(vdev, buf, count, ppos, iswrite); |
382 | return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false); | 396 | |
383 | else if (pci_resource_flags(pdev, index) & IORESOURCE_IO) | 397 | case VFIO_PCI_ROM_REGION_INDEX: |
384 | return vfio_pci_io_readwrite(vdev, buf, count, ppos, false); | 398 | if (iswrite) |
385 | else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) | 399 | return -EINVAL; |
386 | return vfio_pci_mem_readwrite(vdev, buf, count, ppos, false); | 400 | return vfio_pci_bar_rw(vdev, buf, count, ppos, false); |
401 | |||
402 | case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: | ||
403 | return vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite); | ||
404 | |||
405 | case VFIO_PCI_VGA_REGION_INDEX: | ||
406 | return vfio_pci_vga_rw(vdev, buf, count, ppos, iswrite); | ||
407 | } | ||
387 | 408 | ||
388 | return -EINVAL; | 409 | return -EINVAL; |
389 | } | 410 | } |
390 | 411 | ||
391 | static ssize_t vfio_pci_write(void *device_data, const char __user *buf, | 412 | static ssize_t vfio_pci_read(void *device_data, char __user *buf, |
392 | size_t count, loff_t *ppos) | 413 | size_t count, loff_t *ppos) |
393 | { | 414 | { |
394 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | 415 | if (!count) |
395 | struct vfio_pci_device *vdev = device_data; | 416 | return 0; |
396 | struct pci_dev *pdev = vdev->pdev; | ||
397 | 417 | ||
398 | if (index >= VFIO_PCI_NUM_REGIONS) | 418 | return vfio_pci_rw(device_data, buf, count, ppos, false); |
399 | return -EINVAL; | 419 | } |
400 | 420 | ||
401 | if (index == VFIO_PCI_CONFIG_REGION_INDEX) | 421 | static ssize_t vfio_pci_write(void *device_data, const char __user *buf, |
402 | return vfio_pci_config_readwrite(vdev, (char __user *)buf, | 422 | size_t count, loff_t *ppos) |
403 | count, ppos, true); | 423 | { |
404 | else if (index == VFIO_PCI_ROM_REGION_INDEX) | 424 | if (!count) |
405 | return -EINVAL; | 425 | return 0; |
406 | else if (pci_resource_flags(pdev, index) & IORESOURCE_IO) | ||
407 | return vfio_pci_io_readwrite(vdev, (char __user *)buf, | ||
408 | count, ppos, true); | ||
409 | else if (pci_resource_flags(pdev, index) & IORESOURCE_MEM) { | ||
410 | return vfio_pci_mem_readwrite(vdev, (char __user *)buf, | ||
411 | count, ppos, true); | ||
412 | } | ||
413 | 426 | ||
414 | return -EINVAL; | 427 | return vfio_pci_rw(device_data, (char __user *)buf, count, ppos, true); |
415 | } | 428 | } |
416 | 429 | ||
417 | static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) | 430 | static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) |
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 8b8f7d11e102..964ff22bf281 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c | |||
@@ -587,12 +587,46 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm) | |||
587 | return 0; | 587 | return 0; |
588 | } | 588 | } |
589 | 589 | ||
590 | static int vfio_pm_config_write(struct vfio_pci_device *vdev, int pos, | ||
591 | int count, struct perm_bits *perm, | ||
592 | int offset, __le32 val) | ||
593 | { | ||
594 | count = vfio_default_config_write(vdev, pos, count, perm, offset, val); | ||
595 | if (count < 0) | ||
596 | return count; | ||
597 | |||
598 | if (offset == PCI_PM_CTRL) { | ||
599 | pci_power_t state; | ||
600 | |||
601 | switch (le32_to_cpu(val) & PCI_PM_CTRL_STATE_MASK) { | ||
602 | case 0: | ||
603 | state = PCI_D0; | ||
604 | break; | ||
605 | case 1: | ||
606 | state = PCI_D1; | ||
607 | break; | ||
608 | case 2: | ||
609 | state = PCI_D2; | ||
610 | break; | ||
611 | case 3: | ||
612 | state = PCI_D3hot; | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | pci_set_power_state(vdev->pdev, state); | ||
617 | } | ||
618 | |||
619 | return count; | ||
620 | } | ||
621 | |||
590 | /* Permissions for the Power Management capability */ | 622 | /* Permissions for the Power Management capability */ |
591 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) | 623 | static int __init init_pci_cap_pm_perm(struct perm_bits *perm) |
592 | { | 624 | { |
593 | if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM])) | 625 | if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_PM])) |
594 | return -ENOMEM; | 626 | return -ENOMEM; |
595 | 627 | ||
628 | perm->writefn = vfio_pm_config_write; | ||
629 | |||
596 | /* | 630 | /* |
597 | * We always virtualize the next field so we can remove | 631 | * We always virtualize the next field so we can remove |
598 | * capabilities from the chain if we want to. | 632 | * capabilities from the chain if we want to. |
@@ -600,10 +634,11 @@ static int __init init_pci_cap_pm_perm(struct perm_bits *perm) | |||
600 | p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); | 634 | p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE); |
601 | 635 | ||
602 | /* | 636 | /* |
603 | * Power management is defined *per function*, | 637 | * Power management is defined *per function*, so we can let |
604 | * so we let the user write this | 638 | * the user change power state, but we trap and initiate the |
639 | * change ourselves, so the state bits are read-only. | ||
605 | */ | 640 | */ |
606 | p_setd(perm, PCI_PM_CTRL, NO_VIRT, ALL_WRITE); | 641 | p_setd(perm, PCI_PM_CTRL, NO_VIRT, ~PCI_PM_CTRL_STATE_MASK); |
607 | return 0; | 642 | return 0; |
608 | } | 643 | } |
609 | 644 | ||
@@ -985,12 +1020,12 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos) | |||
985 | if (ret) | 1020 | if (ret) |
986 | return pcibios_err_to_errno(ret); | 1021 | return pcibios_err_to_errno(ret); |
987 | 1022 | ||
1023 | vdev->extended_caps = true; | ||
1024 | |||
988 | if ((word & PCI_EXP_FLAGS_VERS) == 1) | 1025 | if ((word & PCI_EXP_FLAGS_VERS) == 1) |
989 | return PCI_CAP_EXP_ENDPOINT_SIZEOF_V1; | 1026 | return PCI_CAP_EXP_ENDPOINT_SIZEOF_V1; |
990 | else { | 1027 | else |
991 | vdev->extended_caps = true; | ||
992 | return PCI_CAP_EXP_ENDPOINT_SIZEOF_V2; | 1028 | return PCI_CAP_EXP_ENDPOINT_SIZEOF_V2; |
993 | } | ||
994 | case PCI_CAP_ID_HT: | 1029 | case PCI_CAP_ID_HT: |
995 | ret = pci_read_config_byte(pdev, pos + 3, &byte); | 1030 | ret = pci_read_config_byte(pdev, pos + 3, &byte); |
996 | if (ret) | 1031 | if (ret) |
@@ -1501,9 +1536,8 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_device *vdev, char __user *buf, | |||
1501 | return ret; | 1536 | return ret; |
1502 | } | 1537 | } |
1503 | 1538 | ||
1504 | ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev, | 1539 | ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev, char __user *buf, |
1505 | char __user *buf, size_t count, | 1540 | size_t count, loff_t *ppos, bool iswrite) |
1506 | loff_t *ppos, bool iswrite) | ||
1507 | { | 1541 | { |
1508 | size_t done = 0; | 1542 | size_t done = 0; |
1509 | int ret = 0; | 1543 | int ret = 0; |
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index 611827cba8cd..d7e55d03f49e 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h | |||
@@ -53,6 +53,7 @@ struct vfio_pci_device { | |||
53 | bool reset_works; | 53 | bool reset_works; |
54 | bool extended_caps; | 54 | bool extended_caps; |
55 | bool bardirty; | 55 | bool bardirty; |
56 | bool has_vga; | ||
56 | struct pci_saved_state *pci_saved_state; | 57 | struct pci_saved_state *pci_saved_state; |
57 | atomic_t refcnt; | 58 | atomic_t refcnt; |
58 | }; | 59 | }; |
@@ -70,15 +71,15 @@ extern int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, | |||
70 | uint32_t flags, unsigned index, | 71 | uint32_t flags, unsigned index, |
71 | unsigned start, unsigned count, void *data); | 72 | unsigned start, unsigned count, void *data); |
72 | 73 | ||
73 | extern ssize_t vfio_pci_config_readwrite(struct vfio_pci_device *vdev, | 74 | extern ssize_t vfio_pci_config_rw(struct vfio_pci_device *vdev, |
74 | char __user *buf, size_t count, | 75 | char __user *buf, size_t count, |
75 | loff_t *ppos, bool iswrite); | 76 | loff_t *ppos, bool iswrite); |
76 | extern ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, | 77 | |
77 | char __user *buf, size_t count, | 78 | extern ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf, |
78 | loff_t *ppos, bool iswrite); | 79 | size_t count, loff_t *ppos, bool iswrite); |
79 | extern ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev, | 80 | |
80 | char __user *buf, size_t count, | 81 | extern ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf, |
81 | loff_t *ppos, bool iswrite); | 82 | size_t count, loff_t *ppos, bool iswrite); |
82 | 83 | ||
83 | extern int vfio_pci_init_perm_bits(void); | 84 | extern int vfio_pci_init_perm_bits(void); |
84 | extern void vfio_pci_uninit_perm_bits(void); | 85 | extern void vfio_pci_uninit_perm_bits(void); |
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index f72323ef618f..210db24d2204 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c | |||
@@ -17,253 +17,222 @@ | |||
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/vgaarb.h> | ||
20 | 21 | ||
21 | #include "vfio_pci_private.h" | 22 | #include "vfio_pci_private.h" |
22 | 23 | ||
23 | /* I/O Port BAR access */ | 24 | /* |
24 | ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev, char __user *buf, | 25 | * Read or write from an __iomem region (MMIO or I/O port) with an excluded |
25 | size_t count, loff_t *ppos, bool iswrite) | 26 | * range which is inaccessible. The excluded range drops writes and fills |
27 | * reads with -1. This is intended for handling MSI-X vector tables and | ||
28 | * leftover space for ROM BARs. | ||
29 | */ | ||
30 | static ssize_t do_io_rw(void __iomem *io, char __user *buf, | ||
31 | loff_t off, size_t count, size_t x_start, | ||
32 | size_t x_end, bool iswrite) | ||
26 | { | 33 | { |
27 | struct pci_dev *pdev = vdev->pdev; | 34 | ssize_t done = 0; |
28 | loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; | ||
29 | int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | ||
30 | void __iomem *io; | ||
31 | size_t done = 0; | ||
32 | |||
33 | if (!pci_resource_start(pdev, bar)) | ||
34 | return -EINVAL; | ||
35 | |||
36 | if (pos + count > pci_resource_len(pdev, bar)) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (!vdev->barmap[bar]) { | ||
40 | int ret; | ||
41 | |||
42 | ret = pci_request_selected_regions(pdev, 1 << bar, "vfio"); | ||
43 | if (ret) | ||
44 | return ret; | ||
45 | |||
46 | vdev->barmap[bar] = pci_iomap(pdev, bar, 0); | ||
47 | |||
48 | if (!vdev->barmap[bar]) { | ||
49 | pci_release_selected_regions(pdev, 1 << bar); | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | io = vdev->barmap[bar]; | ||
55 | 35 | ||
56 | while (count) { | 36 | while (count) { |
57 | int filled; | 37 | size_t fillable, filled; |
38 | |||
39 | if (off < x_start) | ||
40 | fillable = min(count, (size_t)(x_start - off)); | ||
41 | else if (off >= x_end) | ||
42 | fillable = count; | ||
43 | else | ||
44 | fillable = 0; | ||
58 | 45 | ||
59 | if (count >= 3 && !(pos % 4)) { | 46 | if (fillable >= 4 && !(off % 4)) { |
60 | __le32 val; | 47 | __le32 val; |
61 | 48 | ||
62 | if (iswrite) { | 49 | if (iswrite) { |
63 | if (copy_from_user(&val, buf, 4)) | 50 | if (copy_from_user(&val, buf, 4)) |
64 | return -EFAULT; | 51 | return -EFAULT; |
65 | 52 | ||
66 | iowrite32(le32_to_cpu(val), io + pos); | 53 | iowrite32(le32_to_cpu(val), io + off); |
67 | } else { | 54 | } else { |
68 | val = cpu_to_le32(ioread32(io + pos)); | 55 | val = cpu_to_le32(ioread32(io + off)); |
69 | 56 | ||
70 | if (copy_to_user(buf, &val, 4)) | 57 | if (copy_to_user(buf, &val, 4)) |
71 | return -EFAULT; | 58 | return -EFAULT; |
72 | } | 59 | } |
73 | 60 | ||
74 | filled = 4; | 61 | filled = 4; |
75 | 62 | } else if (fillable >= 2 && !(off % 2)) { | |
76 | } else if ((pos % 2) == 0 && count >= 2) { | ||
77 | __le16 val; | 63 | __le16 val; |
78 | 64 | ||
79 | if (iswrite) { | 65 | if (iswrite) { |
80 | if (copy_from_user(&val, buf, 2)) | 66 | if (copy_from_user(&val, buf, 2)) |
81 | return -EFAULT; | 67 | return -EFAULT; |
82 | 68 | ||
83 | iowrite16(le16_to_cpu(val), io + pos); | 69 | iowrite16(le16_to_cpu(val), io + off); |
84 | } else { | 70 | } else { |
85 | val = cpu_to_le16(ioread16(io + pos)); | 71 | val = cpu_to_le16(ioread16(io + off)); |
86 | 72 | ||
87 | if (copy_to_user(buf, &val, 2)) | 73 | if (copy_to_user(buf, &val, 2)) |
88 | return -EFAULT; | 74 | return -EFAULT; |
89 | } | 75 | } |
90 | 76 | ||
91 | filled = 2; | 77 | filled = 2; |
92 | } else { | 78 | } else if (fillable) { |
93 | u8 val; | 79 | u8 val; |
94 | 80 | ||
95 | if (iswrite) { | 81 | if (iswrite) { |
96 | if (copy_from_user(&val, buf, 1)) | 82 | if (copy_from_user(&val, buf, 1)) |
97 | return -EFAULT; | 83 | return -EFAULT; |
98 | 84 | ||
99 | iowrite8(val, io + pos); | 85 | iowrite8(val, io + off); |
100 | } else { | 86 | } else { |
101 | val = ioread8(io + pos); | 87 | val = ioread8(io + off); |
102 | 88 | ||
103 | if (copy_to_user(buf, &val, 1)) | 89 | if (copy_to_user(buf, &val, 1)) |
104 | return -EFAULT; | 90 | return -EFAULT; |
105 | } | 91 | } |
106 | 92 | ||
107 | filled = 1; | 93 | filled = 1; |
94 | } else { | ||
95 | /* Fill reads with -1, drop writes */ | ||
96 | filled = min(count, (size_t)(x_end - off)); | ||
97 | if (!iswrite) { | ||
98 | u8 val = 0xFF; | ||
99 | size_t i; | ||
100 | |||
101 | for (i = 0; i < filled; i++) | ||
102 | if (copy_to_user(buf + i, &val, 1)) | ||
103 | return -EFAULT; | ||
104 | } | ||
108 | } | 105 | } |
109 | 106 | ||
110 | count -= filled; | 107 | count -= filled; |
111 | done += filled; | 108 | done += filled; |
109 | off += filled; | ||
112 | buf += filled; | 110 | buf += filled; |
113 | pos += filled; | ||
114 | } | 111 | } |
115 | 112 | ||
116 | *ppos += done; | ||
117 | |||
118 | return done; | 113 | return done; |
119 | } | 114 | } |
120 | 115 | ||
121 | /* | 116 | ssize_t vfio_pci_bar_rw(struct vfio_pci_device *vdev, char __user *buf, |
122 | * MMIO BAR access | 117 | size_t count, loff_t *ppos, bool iswrite) |
123 | * We handle two excluded ranges here as well, if the user tries to read | ||
124 | * the ROM beyond what PCI tells us is available or the MSI-X table region, | ||
125 | * we return 0xFF and writes are dropped. | ||
126 | */ | ||
127 | ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, char __user *buf, | ||
128 | size_t count, loff_t *ppos, bool iswrite) | ||
129 | { | 118 | { |
130 | struct pci_dev *pdev = vdev->pdev; | 119 | struct pci_dev *pdev = vdev->pdev; |
131 | loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; | 120 | loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; |
132 | int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | 121 | int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos); |
133 | void __iomem *io; | 122 | size_t x_start = 0, x_end = 0; |
134 | resource_size_t end; | 123 | resource_size_t end; |
135 | size_t done = 0; | 124 | void __iomem *io; |
136 | size_t x_start = 0, x_end = 0; /* excluded range */ | 125 | ssize_t done; |
137 | 126 | ||
138 | if (!pci_resource_start(pdev, bar)) | 127 | if (!pci_resource_start(pdev, bar)) |
139 | return -EINVAL; | 128 | return -EINVAL; |
140 | 129 | ||
141 | end = pci_resource_len(pdev, bar); | 130 | end = pci_resource_len(pdev, bar); |
142 | 131 | ||
143 | if (pos > end) | 132 | if (pos >= end) |
144 | return -EINVAL; | 133 | return -EINVAL; |
145 | 134 | ||
146 | if (pos == end) | 135 | count = min(count, (size_t)(end - pos)); |
147 | return 0; | ||
148 | |||
149 | if (pos + count > end) | ||
150 | count = end - pos; | ||
151 | 136 | ||
152 | if (bar == PCI_ROM_RESOURCE) { | 137 | if (bar == PCI_ROM_RESOURCE) { |
138 | /* | ||
139 | * The ROM can fill less space than the BAR, so we start the | ||
140 | * excluded range at the end of the actual ROM. This makes | ||
141 | * filling large ROM BARs much faster. | ||
142 | */ | ||
153 | io = pci_map_rom(pdev, &x_start); | 143 | io = pci_map_rom(pdev, &x_start); |
144 | if (!io) | ||
145 | return -ENOMEM; | ||
154 | x_end = end; | 146 | x_end = end; |
155 | } else { | 147 | } else if (!vdev->barmap[bar]) { |
156 | if (!vdev->barmap[bar]) { | 148 | int ret; |
157 | int ret; | ||
158 | |||
159 | ret = pci_request_selected_regions(pdev, 1 << bar, | ||
160 | "vfio"); | ||
161 | if (ret) | ||
162 | return ret; | ||
163 | 149 | ||
164 | vdev->barmap[bar] = pci_iomap(pdev, bar, 0); | 150 | ret = pci_request_selected_regions(pdev, 1 << bar, "vfio"); |
151 | if (ret) | ||
152 | return ret; | ||
165 | 153 | ||
166 | if (!vdev->barmap[bar]) { | 154 | io = pci_iomap(pdev, bar, 0); |
167 | pci_release_selected_regions(pdev, 1 << bar); | 155 | if (!io) { |
168 | return -EINVAL; | 156 | pci_release_selected_regions(pdev, 1 << bar); |
169 | } | 157 | return -ENOMEM; |
170 | } | 158 | } |
171 | 159 | ||
160 | vdev->barmap[bar] = io; | ||
161 | } else | ||
172 | io = vdev->barmap[bar]; | 162 | io = vdev->barmap[bar]; |
173 | 163 | ||
174 | if (bar == vdev->msix_bar) { | 164 | if (bar == vdev->msix_bar) { |
175 | x_start = vdev->msix_offset; | 165 | x_start = vdev->msix_offset; |
176 | x_end = vdev->msix_offset + vdev->msix_size; | 166 | x_end = vdev->msix_offset + vdev->msix_size; |
177 | } | ||
178 | } | 167 | } |
179 | 168 | ||
180 | if (!io) | 169 | done = do_io_rw(io, buf, pos, count, x_start, x_end, iswrite); |
181 | return -EINVAL; | ||
182 | |||
183 | while (count) { | ||
184 | size_t fillable, filled; | ||
185 | |||
186 | if (pos < x_start) | ||
187 | fillable = x_start - pos; | ||
188 | else if (pos >= x_end) | ||
189 | fillable = end - pos; | ||
190 | else | ||
191 | fillable = 0; | ||
192 | |||
193 | if (fillable >= 4 && !(pos % 4) && (count >= 4)) { | ||
194 | __le32 val; | ||
195 | |||
196 | if (iswrite) { | ||
197 | if (copy_from_user(&val, buf, 4)) | ||
198 | goto out; | ||
199 | |||
200 | iowrite32(le32_to_cpu(val), io + pos); | ||
201 | } else { | ||
202 | val = cpu_to_le32(ioread32(io + pos)); | ||
203 | 170 | ||
204 | if (copy_to_user(buf, &val, 4)) | 171 | if (done >= 0) |
205 | goto out; | 172 | *ppos += done; |
206 | } | ||
207 | 173 | ||
208 | filled = 4; | 174 | if (bar == PCI_ROM_RESOURCE) |
209 | } else if (fillable >= 2 && !(pos % 2) && (count >= 2)) { | 175 | pci_unmap_rom(pdev, io); |
210 | __le16 val; | ||
211 | |||
212 | if (iswrite) { | ||
213 | if (copy_from_user(&val, buf, 2)) | ||
214 | goto out; | ||
215 | |||
216 | iowrite16(le16_to_cpu(val), io + pos); | ||
217 | } else { | ||
218 | val = cpu_to_le16(ioread16(io + pos)); | ||
219 | |||
220 | if (copy_to_user(buf, &val, 2)) | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | filled = 2; | ||
225 | } else if (fillable) { | ||
226 | u8 val; | ||
227 | 176 | ||
228 | if (iswrite) { | 177 | return done; |
229 | if (copy_from_user(&val, buf, 1)) | 178 | } |
230 | goto out; | ||
231 | 179 | ||
232 | iowrite8(val, io + pos); | 180 | ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf, |
233 | } else { | 181 | size_t count, loff_t *ppos, bool iswrite) |
234 | val = ioread8(io + pos); | 182 | { |
183 | int ret; | ||
184 | loff_t off, pos = *ppos & VFIO_PCI_OFFSET_MASK; | ||
185 | void __iomem *iomem = NULL; | ||
186 | unsigned int rsrc; | ||
187 | bool is_ioport; | ||
188 | ssize_t done; | ||
189 | |||
190 | if (!vdev->has_vga) | ||
191 | return -EINVAL; | ||
235 | 192 | ||
236 | if (copy_to_user(buf, &val, 1)) | 193 | switch (pos) { |
237 | goto out; | 194 | case 0xa0000 ... 0xbffff: |
238 | } | 195 | count = min(count, (size_t)(0xc0000 - pos)); |
196 | iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1); | ||
197 | off = pos - 0xa0000; | ||
198 | rsrc = VGA_RSRC_LEGACY_MEM; | ||
199 | is_ioport = false; | ||
200 | break; | ||
201 | case 0x3b0 ... 0x3bb: | ||
202 | count = min(count, (size_t)(0x3bc - pos)); | ||
203 | iomem = ioport_map(0x3b0, 0x3bb - 0x3b0 + 1); | ||
204 | off = pos - 0x3b0; | ||
205 | rsrc = VGA_RSRC_LEGACY_IO; | ||
206 | is_ioport = true; | ||
207 | break; | ||
208 | case 0x3c0 ... 0x3df: | ||
209 | count = min(count, (size_t)(0x3e0 - pos)); | ||
210 | iomem = ioport_map(0x3c0, 0x3df - 0x3c0 + 1); | ||
211 | off = pos - 0x3c0; | ||
212 | rsrc = VGA_RSRC_LEGACY_IO; | ||
213 | is_ioport = true; | ||
214 | break; | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
239 | 218 | ||
240 | filled = 1; | 219 | if (!iomem) |
241 | } else { | 220 | return -ENOMEM; |
242 | /* Drop writes, fill reads with FF */ | ||
243 | filled = min((size_t)(x_end - pos), count); | ||
244 | if (!iswrite) { | ||
245 | char val = 0xFF; | ||
246 | size_t i; | ||
247 | 221 | ||
248 | for (i = 0; i < filled; i++) { | 222 | ret = vga_get_interruptible(vdev->pdev, rsrc); |
249 | if (put_user(val, buf + i)) | 223 | if (ret) { |
250 | goto out; | 224 | is_ioport ? ioport_unmap(iomem) : iounmap(iomem); |
251 | } | 225 | return ret; |
252 | } | 226 | } |
253 | 227 | ||
254 | } | 228 | done = do_io_rw(iomem, buf, off, count, 0, 0, iswrite); |
255 | 229 | ||
256 | count -= filled; | 230 | vga_put(vdev->pdev, rsrc); |
257 | done += filled; | ||
258 | buf += filled; | ||
259 | pos += filled; | ||
260 | } | ||
261 | 231 | ||
262 | *ppos += done; | 232 | is_ioport ? ioport_unmap(iomem) : iounmap(iomem); |
263 | 233 | ||
264 | out: | 234 | if (done >= 0) |
265 | if (bar == PCI_ROM_RESOURCE) | 235 | *ppos += done; |
266 | pci_unmap_rom(pdev, io); | ||
267 | 236 | ||
268 | return count ? -EFAULT : done; | 237 | return done; |
269 | } | 238 | } |
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 12c264d3b058..28e2d5b2c0c7 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -442,7 +442,7 @@ static struct vfio_device *vfio_group_get_device(struct vfio_group *group, | |||
442 | * a device. It's not always practical to leave a device within a group | 442 | * a device. It's not always practical to leave a device within a group |
443 | * driverless as it could get re-bound to something unsafe. | 443 | * driverless as it could get re-bound to something unsafe. |
444 | */ | 444 | */ |
445 | static const char * const vfio_driver_whitelist[] = { "pci-stub" }; | 445 | static const char * const vfio_driver_whitelist[] = { "pci-stub", "pcieport" }; |
446 | 446 | ||
447 | static bool vfio_whitelisted_driver(struct device_driver *drv) | 447 | static bool vfio_whitelisted_driver(struct device_driver *drv) |
448 | { | 448 | { |
@@ -642,33 +642,16 @@ int vfio_add_group_dev(struct device *dev, | |||
642 | } | 642 | } |
643 | EXPORT_SYMBOL_GPL(vfio_add_group_dev); | 643 | EXPORT_SYMBOL_GPL(vfio_add_group_dev); |
644 | 644 | ||
645 | /* Test whether a struct device is present in our tracking */ | 645 | /* Given a referenced group, check if it contains the device */ |
646 | static bool vfio_dev_present(struct device *dev) | 646 | static bool vfio_dev_present(struct vfio_group *group, struct device *dev) |
647 | { | 647 | { |
648 | struct iommu_group *iommu_group; | ||
649 | struct vfio_group *group; | ||
650 | struct vfio_device *device; | 648 | struct vfio_device *device; |
651 | 649 | ||
652 | iommu_group = iommu_group_get(dev); | ||
653 | if (!iommu_group) | ||
654 | return false; | ||
655 | |||
656 | group = vfio_group_get_from_iommu(iommu_group); | ||
657 | if (!group) { | ||
658 | iommu_group_put(iommu_group); | ||
659 | return false; | ||
660 | } | ||
661 | |||
662 | device = vfio_group_get_device(group, dev); | 650 | device = vfio_group_get_device(group, dev); |
663 | if (!device) { | 651 | if (!device) |
664 | vfio_group_put(group); | ||
665 | iommu_group_put(iommu_group); | ||
666 | return false; | 652 | return false; |
667 | } | ||
668 | 653 | ||
669 | vfio_device_put(device); | 654 | vfio_device_put(device); |
670 | vfio_group_put(group); | ||
671 | iommu_group_put(iommu_group); | ||
672 | return true; | 655 | return true; |
673 | } | 656 | } |
674 | 657 | ||
@@ -682,10 +665,18 @@ void *vfio_del_group_dev(struct device *dev) | |||
682 | struct iommu_group *iommu_group = group->iommu_group; | 665 | struct iommu_group *iommu_group = group->iommu_group; |
683 | void *device_data = device->device_data; | 666 | void *device_data = device->device_data; |
684 | 667 | ||
668 | /* | ||
669 | * The group exists so long as we have a device reference. Get | ||
670 | * a group reference and use it to scan for the device going away. | ||
671 | */ | ||
672 | vfio_group_get(group); | ||
673 | |||
685 | vfio_device_put(device); | 674 | vfio_device_put(device); |
686 | 675 | ||
687 | /* TODO send a signal to encourage this to be released */ | 676 | /* TODO send a signal to encourage this to be released */ |
688 | wait_event(vfio.release_q, !vfio_dev_present(dev)); | 677 | wait_event(vfio.release_q, !vfio_dev_present(group, dev)); |
678 | |||
679 | vfio_group_put(group); | ||
689 | 680 | ||
690 | iommu_group_put(iommu_group); | 681 | iommu_group_put(iommu_group); |
691 | 682 | ||
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 4758d1bfcf41..4f41f309911e 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h | |||
@@ -303,6 +303,15 @@ enum { | |||
303 | VFIO_PCI_BAR5_REGION_INDEX, | 303 | VFIO_PCI_BAR5_REGION_INDEX, |
304 | VFIO_PCI_ROM_REGION_INDEX, | 304 | VFIO_PCI_ROM_REGION_INDEX, |
305 | VFIO_PCI_CONFIG_REGION_INDEX, | 305 | VFIO_PCI_CONFIG_REGION_INDEX, |
306 | /* | ||
307 | * Expose VGA regions defined for PCI base class 03, subclass 00. | ||
308 | * This includes I/O port ranges 0x3b0 to 0x3bb and 0x3c0 to 0x3df | ||
309 | * as well as the MMIO range 0xa0000 to 0xbffff. Each implemented | ||
310 | * range is found at it's identity mapped offset from the region | ||
311 | * offset, for example 0x3b0 is region_info.offset + 0x3b0. Areas | ||
312 | * between described ranges are unimplemented. | ||
313 | */ | ||
314 | VFIO_PCI_VGA_REGION_INDEX, | ||
306 | VFIO_PCI_NUM_REGIONS | 315 | VFIO_PCI_NUM_REGIONS |
307 | }; | 316 | }; |
308 | 317 | ||