vfio_pci_rdwr.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * VFIO PCI I/O Port & MMIO access
  3. *
  4. * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
  5. * Author: Alex Williamson <alex.williamson@redhat.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * Derived from original vfio:
  12. * Copyright 2010 Cisco Systems, Inc. All rights reserved.
  13. * Author: Tom Lyon, pugs@cisco.com
  14. */
  15. #include <linux/fs.h>
  16. #include <linux/pci.h>
  17. #include <linux/uaccess.h>
  18. #include <linux/io.h>
  19. #include "vfio_pci_private.h"
  20. /* I/O Port BAR access */
  21. ssize_t vfio_pci_io_readwrite(struct vfio_pci_device *vdev, char __user *buf,
  22. size_t count, loff_t *ppos, bool iswrite)
  23. {
  24. struct pci_dev *pdev = vdev->pdev;
  25. loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
  26. int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
  27. void __iomem *io;
  28. size_t done = 0;
  29. if (!pci_resource_start(pdev, bar))
  30. return -EINVAL;
  31. if (pos + count > pci_resource_len(pdev, bar))
  32. return -EINVAL;
  33. if (!vdev->barmap[bar]) {
  34. int ret;
  35. ret = pci_request_selected_regions(pdev, 1 << bar, "vfio");
  36. if (ret)
  37. return ret;
  38. vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
  39. if (!vdev->barmap[bar]) {
  40. pci_release_selected_regions(pdev, 1 << bar);
  41. return -EINVAL;
  42. }
  43. }
  44. io = vdev->barmap[bar];
  45. while (count) {
  46. int filled;
  47. if (count >= 3 && !(pos % 4)) {
  48. __le32 val;
  49. if (iswrite) {
  50. if (copy_from_user(&val, buf, 4))
  51. return -EFAULT;
  52. iowrite32(le32_to_cpu(val), io + pos);
  53. } else {
  54. val = cpu_to_le32(ioread32(io + pos));
  55. if (copy_to_user(buf, &val, 4))
  56. return -EFAULT;
  57. }
  58. filled = 4;
  59. } else if ((pos % 2) == 0 && count >= 2) {
  60. __le16 val;
  61. if (iswrite) {
  62. if (copy_from_user(&val, buf, 2))
  63. return -EFAULT;
  64. iowrite16(le16_to_cpu(val), io + pos);
  65. } else {
  66. val = cpu_to_le16(ioread16(io + pos));
  67. if (copy_to_user(buf, &val, 2))
  68. return -EFAULT;
  69. }
  70. filled = 2;
  71. } else {
  72. u8 val;
  73. if (iswrite) {
  74. if (copy_from_user(&val, buf, 1))
  75. return -EFAULT;
  76. iowrite8(val, io + pos);
  77. } else {
  78. val = ioread8(io + pos);
  79. if (copy_to_user(buf, &val, 1))
  80. return -EFAULT;
  81. }
  82. filled = 1;
  83. }
  84. count -= filled;
  85. done += filled;
  86. buf += filled;
  87. pos += filled;
  88. }
  89. *ppos += done;
  90. return done;
  91. }
  92. /*
  93. * MMIO BAR access
  94. * We handle two excluded ranges here as well, if the user tries to read
  95. * the ROM beyond what PCI tells us is available or the MSI-X table region,
  96. * we return 0xFF and writes are dropped.
  97. */
  98. ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, char __user *buf,
  99. size_t count, loff_t *ppos, bool iswrite)
  100. {
  101. struct pci_dev *pdev = vdev->pdev;
  102. loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
  103. int bar = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
  104. void __iomem *io;
  105. resource_size_t end;
  106. size_t done = 0;
  107. size_t x_start = 0, x_end = 0; /* excluded range */
  108. if (!pci_resource_start(pdev, bar))
  109. return -EINVAL;
  110. end = pci_resource_len(pdev, bar);
  111. if (pos > end)
  112. return -EINVAL;
  113. if (pos == end)
  114. return 0;
  115. if (pos + count > end)
  116. count = end - pos;
  117. if (bar == PCI_ROM_RESOURCE) {
  118. io = pci_map_rom(pdev, &x_start);
  119. x_end = end;
  120. } else {
  121. if (!vdev->barmap[bar]) {
  122. int ret;
  123. ret = pci_request_selected_regions(pdev, 1 << bar,
  124. "vfio");
  125. if (ret)
  126. return ret;
  127. vdev->barmap[bar] = pci_iomap(pdev, bar, 0);
  128. if (!vdev->barmap[bar]) {
  129. pci_release_selected_regions(pdev, 1 << bar);
  130. return -EINVAL;
  131. }
  132. }
  133. io = vdev->barmap[bar];
  134. if (bar == vdev->msix_bar) {
  135. x_start = vdev->msix_offset;
  136. x_end = vdev->msix_offset + vdev->msix_size;
  137. }
  138. }
  139. if (!io)
  140. return -EINVAL;
  141. while (count) {
  142. size_t fillable, filled;
  143. if (pos < x_start)
  144. fillable = x_start - pos;
  145. else if (pos >= x_end)
  146. fillable = end - pos;
  147. else
  148. fillable = 0;
  149. if (fillable >= 4 && !(pos % 4) && (count >= 4)) {
  150. __le32 val;
  151. if (iswrite) {
  152. if (copy_from_user(&val, buf, 4))
  153. goto out;
  154. iowrite32(le32_to_cpu(val), io + pos);
  155. } else {
  156. val = cpu_to_le32(ioread32(io + pos));
  157. if (copy_to_user(buf, &val, 4))
  158. goto out;
  159. }
  160. filled = 4;
  161. } else if (fillable >= 2 && !(pos % 2) && (count >= 2)) {
  162. __le16 val;
  163. if (iswrite) {
  164. if (copy_from_user(&val, buf, 2))
  165. goto out;
  166. iowrite16(le16_to_cpu(val), io + pos);
  167. } else {
  168. val = cpu_to_le16(ioread16(io + pos));
  169. if (copy_to_user(buf, &val, 2))
  170. goto out;
  171. }
  172. filled = 2;
  173. } else if (fillable) {
  174. u8 val;
  175. if (iswrite) {
  176. if (copy_from_user(&val, buf, 1))
  177. goto out;
  178. iowrite8(val, io + pos);
  179. } else {
  180. val = ioread8(io + pos);
  181. if (copy_to_user(buf, &val, 1))
  182. goto out;
  183. }
  184. filled = 1;
  185. } else {
  186. /* Drop writes, fill reads with FF */
  187. if (!iswrite) {
  188. char val = 0xFF;
  189. size_t i;
  190. for (i = 0; i < x_end - pos; i++) {
  191. if (put_user(val, buf + i))
  192. goto out;
  193. }
  194. }
  195. filled = x_end - pos;
  196. }
  197. count -= filled;
  198. done += filled;
  199. buf += filled;
  200. pos += filled;
  201. }
  202. *ppos += done;
  203. out:
  204. if (bar == PCI_ROM_RESOURCE)
  205. pci_unmap_rom(pdev, io);
  206. return count ? -EFAULT : done;
  207. }