Post

vfio

vfio

qemu

1
2
3
4
5
vfio_realize
=> vfio_attach_device
   => VFIOIOMMUClass->attach_device : vfio_iommu_legacy_class_init
                                    : iommufd_cdev_attach

vfio_iommu_legacy_attach_device

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
vfio_iommu_legacy_attach_device
=> groupid = vfio_device_groupid()
   => group_patch = readlink("/sys//sys/devices/pci{domain}:{bus}/{domain}:{bus}/{b:d.f}/iommu_group")
      # eg: ../../../kernel/iommu_groups/11
   => read/sscan  (group_patch) -> groupid # eg: 11
=> group = vfio_get_group
   => group->fd = open("/dev/vfio/{groupid}")
   => ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)
   => if ! status.flags & VFIO_GROUP_FLAGS_VIABLE:
      => goto error
   => vfio_connect_container()
      => foreach_container:
         => ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)
            => vfio_ram_block_discard_disable(container, true)
            => if ioctl() is success:
               => vfio_kvm_device_add_group(group);
               => return 
            => else:
               => continue

      # if have not fit container, need create new
      => fd = qemu_open("/dev/vfio/vfio", O_RDWR, errp)
      => ret = ioctl(fd, VFIO_GET_API_VERSION)
         => Determine if the API version is supported

      => vfio_ram_block_discard_disable(container, true)
      => vioc = VFIO_IOMMU_GET_CLASS(bcontainer)
      => vfio_kvm_device_add_group(group)
         => vfio_kvm_device_add_fd(group->fd, &err)
            => struct kvm_device_attr attr = {.group = KVM_DEV_VFIO_FILE,
                                              .attr = KVM_DEV_VFIO_FILE_ADD,
                                              .addr = &fd}
            => if vfio_kvm_device_fd < 0:
               # need create kvm_device fd
               => struct kvm_create_device cd = {.type = KVM_DEV_TYPE_VFIO}
               => kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)
               => vfio_kvm_device_fd = cd.fd
            => ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)
      => vfio_address_space_insert(space, bcontainer)
      => memory_listener_register(&bcontainer->listener, bcontainer->space->as)
=> vfio_get_device
   => 

kernel

KVM_CREATE_DEVICE, KVM_DEV_TYPE_VFIO

1
ioctl(, KVM_CREATE_DEVICE, cd = {.type = KVM_DEV_TYPE_VFIO})

流程

1
2
3
4
5
6
7
8
9
10
kvm_vm_ioctl
=> case KVM_CREATE_DEVICE:

   kvm_ioctl_create_device
   => dev(struct kvm_device) = kzalloc()
   => ops = kvm_device_ops_table[type]
   => init dev->ops, dev->kvm
   => ops->create()
   => list_add_rcu(&dev->vm_node, &kvm->devices);
   => anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);

TYPE KVM_DEV_TYPE_VFIO OPS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static const struct kvm_device_ops kvm_vfio_ops = {
        .name = "kvm-vfio",
        .create = kvm_vfio_create,
        .release = kvm_vfio_release,
        .set_attr = kvm_vfio_set_attr,
        .has_attr = kvm_vfio_has_attr,
};

kvm_vfio_create
=> determine if VFIO device of this vm is exist
   => {
     // Only one VFIO "device" per VM
     list_for_each_entry(tmp, &dev->kvm->devices, vm_node)
       if (tmp->ops == &kvm_vfio_ops)
         return -EBUSY;
   }
=> kv(struct kvm_vfio *) = kzalloc()
=> INIT_LIST_HEAD(&kv->file_list);
=> dev->private = kv

KVM_SET_DEVICE_ATTR, attr = {group = KVM_DEV_VFIO_FILE, attr = KVM_DEV_VFIO_FILE_ADD}

1
ioctl(, KVM_SET_DEVICE_ATTR, attr = {group = KVM_DEV_VFIO_FILE, attr = KVM_DEV_VFIO_FILE_ADD}

流程:

1
kvm_vfio_file_add
This post is licensed under CC BY 4.0 by the author.