vfio: Create pvIOMM for guest devices
Use new UAPI for KVM-VFIO device to create a pvIOMMU and attached
to guest VMs for VFIO assigned devices.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
diff --git a/vfio/core.c b/vfio/core.c
index c30044c..ee4e248 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -11,6 +11,8 @@
static int vfio_container;
static LIST_HEAD(vfio_groups);
static struct vfio_device *vfio_devices;
+/* Just a random start of SID for pvIOMMU, nothing special. */
+static int sid_offset = 0x55;
static int vfio_device_pci_parser(const struct option *opt, char *arg,
struct vfio_device_params *dev)
@@ -679,8 +681,9 @@
struct kvm_create_device cd = {
.type = KVM_DEV_TYPE_VFIO,
};
+ int ret, i, pviommufd;
+ u32 j;
- int ret;
ret = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &cd);
if (ret) {
pr_err("Failed to create kvm-vfio bridge %d\n", ret);
@@ -700,6 +703,53 @@
}
}
+ /* Create pvIOMMU for guest. */
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_PVIOMMU,
+ .attr = KVM_DEV_VFIO_PVIOMMU_ATTACH,
+ };
+
+ pviommufd = ioctl(cd.fd, KVM_SET_DEVICE_ATTR, &attr);
+ if (pviommufd < 0) {
+ pr_err("Failed to attach pviommu to kvm-vfio device %d\n", ret);
+ return pviommufd;
+ }
+
+ /* For VFIO devices, add to the pvIOMMU. */
+ for (i = 0 ; i < kvm->cfg.num_vfio_devices; ++i) {
+ struct kvm_vfio_iommu_info info = {
+ .device_fd = vfio_devices[i].fd,
+ };
+ /* Probe number of SIDs for this device. */
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_PVIOMMU,
+ .attr = KVM_DEV_VFIO_PVIOMMU_GET_INFO,
+ .addr = (uint64_t)&info,
+ };
+ ret = ioctl(cd.fd, KVM_SET_DEVICE_ATTR, &attr);
+ /* Set vSID => SID translation. */
+ for (j = 0; j < info.nr_sids; ++j) {
+ struct kvm_vfio_iommu_config config = {
+ .pviommu_fd = pviommufd,
+ .vfio_dev_fd = vfio_devices[i].fd,
+ .sid_idx = j,
+ .vsid = sid_offset++,
+ };
+
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_VFIO_PVIOMMU,
+ .attr = KVM_DEV_VFIO_PVIOMMU_SET_CONFIG,
+ .addr = (uint64_t)&config,
+ };
+
+ ret = ioctl(cd.fd, KVM_SET_DEVICE_ATTR, &attr);
+ if (ret) {
+ pr_err("Failed to set vsid(%d) => sid(%d) translation, err %d\n", config.vsid, j, ret);
+ return ret;
+ }
+ }
+ }
+
return 0;
}