master
c 191 lines 5.19 KB
Raw
1 /*
2 * low level and IOMMU backend agnostic helpers used by VFIO devices,
3 * related to regions, interrupts, capabilities
4 *
5 * Copyright Red Hat, Inc. 2012
6 *
7 * Authors:
8 * Alex Williamson <alex.williamson@redhat.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 * Based on qemu-kvm device-assignment:
13 * Adapted for KVM by Qumranet.
14 * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
15 * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
16 * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
17 * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
18 * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
19 */
20
21 #include "qemu/osdep.h"
22 #include <sys/ioctl.h>
23
24 #include <linux/kvm.h>
25 #include "system/kvm.h"
26 #include "exec/cpu-common.h"
27 #include "hw/vfio/vfio-device.h"
28 #include "qapi/error.h"
29 #include "vfio-helpers.h"
30
31 /*
32 * We have a single VFIO pseudo device per KVM VM. Once created it lives
33 * for the life of the VM. Closing the file descriptor only drops our
34 * reference to it and the device's reference to kvm. Therefore once
35 * initialized, this file descriptor is only released on QEMU exit and
36 * we'll re-use it should another vfio device be attached before then.
37 */
38 int vfio_kvm_device_fd = -1;
39
40 /*
41 * Confidential virtual machines:
42 * During reset of confidential vms, the kvm vm file descriptor changes.
43 * In this case, the old vfio kvm file descriptor is
44 * closed and a new descriptor is created against the new kvm vm file
45 * descriptor.
46 */
47
48 typedef struct VFIODeviceFd {
49 int fd;
50 QLIST_ENTRY(VFIODeviceFd) node;
51 } VFIODeviceFd;
52
53 static QLIST_HEAD(, VFIODeviceFd) vfio_device_fds =
54 QLIST_HEAD_INITIALIZER(vfio_device_fds);
55
56 static void vfio_device_fd_list_add(int fd)
57 {
58 VFIODeviceFd *file_fd;
59 file_fd = g_malloc0(sizeof(*file_fd));
60 file_fd->fd = fd;
61 QLIST_INSERT_HEAD(&vfio_device_fds, file_fd, node);
62 }
63
64 static void vfio_device_fd_list_remove(int fd)
65 {
66 VFIODeviceFd *file_fd, *next;
67
68 QLIST_FOREACH_SAFE(file_fd, &vfio_device_fds, node, next) {
69 if (file_fd->fd == fd) {
70 QLIST_REMOVE(file_fd, node);
71 g_free(file_fd);
72 break;
73 }
74 }
75 }
76
77 static int vfio_device_fd_rebind(NotifierWithReturn *notifier, void *data,
78 Error **errp)
79 {
80 VFIODeviceFd *file_fd;
81 struct kvm_device_attr attr = {
82 .group = KVM_DEV_VFIO_FILE,
83 .attr = KVM_DEV_VFIO_FILE_ADD,
84 };
85 struct kvm_create_device cd = {
86 .type = KVM_DEV_TYPE_VFIO,
87 };
88
89 /* we are not interested in pre vmfd change notification */
90 if (((VmfdChangeNotifier *)data)->pre) {
91 return 0;
92 }
93
94 if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
95 error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
96 return -errno;
97 }
98
99 if (vfio_kvm_device_fd != -1) {
100 close(vfio_kvm_device_fd);
101 }
102
103 vfio_kvm_device_fd = cd.fd;
104
105 QLIST_FOREACH(file_fd, &vfio_device_fds, node) {
106 attr.addr = (uint64_t)(unsigned long)&file_fd->fd;
107 if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
108 error_setg_errno(errp, errno,
109 "Failed to add fd %d to KVM VFIO device",
110 file_fd->fd);
111 return -errno;
112 }
113 }
114 return 0;
115 }
116
117 static struct NotifierWithReturn vfio_vmfd_change_notifier = {
118 .notify = vfio_device_fd_rebind,
119 };
120
121 void vfio_kvm_device_close(void)
122 {
123 kvm_close();
124 if (vfio_kvm_device_fd != -1) {
125 close(vfio_kvm_device_fd);
126 vfio_kvm_device_fd = -1;
127 }
128 }
129
130 int vfio_kvm_device_add_fd(int fd, Error **errp)
131 {
132 struct kvm_device_attr attr = {
133 .group = KVM_DEV_VFIO_FILE,
134 .attr = KVM_DEV_VFIO_FILE_ADD,
135 .addr = (uint64_t)(unsigned long)&fd,
136 };
137
138 if (!kvm_enabled()) {
139 return 0;
140 }
141
142 if (vfio_kvm_device_fd < 0) {
143 struct kvm_create_device cd = {
144 .type = KVM_DEV_TYPE_VFIO,
145 };
146
147 if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
148 error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
149 return -errno;
150 }
151
152 vfio_kvm_device_fd = cd.fd;
153 /*
154 * If the vm file descriptor changes, add a notifier so that we can
155 * re-create the vfio_kvm_device_fd.
156 */
157 kvm_vmfd_add_change_notifier(&vfio_vmfd_change_notifier);
158 }
159
160 if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
161 error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
162 fd);
163 return -errno;
164 }
165
166 vfio_device_fd_list_add(fd);
167 return 0;
168 }
169
170 int vfio_kvm_device_del_fd(int fd, Error **errp)
171 {
172 struct kvm_device_attr attr = {
173 .group = KVM_DEV_VFIO_FILE,
174 .attr = KVM_DEV_VFIO_FILE_DEL,
175 .addr = (uint64_t)(unsigned long)&fd,
176 };
177
178 if (vfio_kvm_device_fd < 0) {
179 error_setg(errp, "KVM VFIO device isn't created yet");
180 return -EINVAL;
181 }
182
183 if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
184 error_setg_errno(errp, errno,
185 "Failed to remove fd %d from KVM VFIO device", fd);
186 return -errno;
187 }
188
189 vfio_device_fd_list_remove(fd);
190 return 0;
191 }