hw/vfio/helpers.c: extract kvm helpers in kvm-helpers.c
Because those functions use kvm specific types, they need to be isolated in another source file. This allows us to link kvm-helpers only in configurations with CONFIG_KVM. Reviewed-by: Cédric Le Goater <clg@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Tested-by: Cédric Le Goater <clg@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Link: https://lore.kernel.org/qemu-devel/20260318174733.1717643-3-pierrick.bouvier@linaro.org Signed-off-by: Cédric Le Goater <clg@redhat.com>
Pierrick Bouvier committed
Mar 18, 2026 at 10:47 UTC
09df2b17ed75b45dc8bf83ac79bac26064bc6745
4 files changed
+220
-172
hw/vfio/helpers.c
-172
@@ -22,7 +22,6 @@
22
#include "qemu/osdep.h"
23
#include <sys/ioctl.h>
24
25
-#include "system/kvm.h"
25
#include "exec/cpu-common.h"
26
#include "hw/vfio/vfio-device.h"
27
#include "hw/core/hw-error.h"
@@ -107,177 +106,6 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
106
return true;
107
}
108
110
-#ifdef CONFIG_KVM
111
-/*
112
- * We have a single VFIO pseudo device per KVM VM. Once created it lives
113
- * for the life of the VM. Closing the file descriptor only drops our
114
- * reference to it and the device's reference to kvm. Therefore once
115
- * initialized, this file descriptor is only released on QEMU exit and
116
- * we'll re-use it should another vfio device be attached before then.
117
- */
118
-int vfio_kvm_device_fd = -1;
119
-
120
-/*
121
- * Confidential virtual machines:
122
- * During reset of confidential vms, the kvm vm file descriptor changes.
123
- * In this case, the old vfio kvm file descriptor is
124
- * closed and a new descriptor is created against the new kvm vm file
125
- * descriptor.
126
- */
127
-
128
-typedef struct VFIODeviceFd {
129
- int fd;
130
- QLIST_ENTRY(VFIODeviceFd) node;
131
-} VFIODeviceFd;
132
-
133
-static QLIST_HEAD(, VFIODeviceFd) vfio_device_fds =
134
- QLIST_HEAD_INITIALIZER(vfio_device_fds);
135
-
136
-static void vfio_device_fd_list_add(int fd)
137
-{
138
- VFIODeviceFd *file_fd;
139
- file_fd = g_malloc0(sizeof(*file_fd));
140
- file_fd->fd = fd;
141
- QLIST_INSERT_HEAD(&vfio_device_fds, file_fd, node);
142
-}
143
-
144
-static void vfio_device_fd_list_remove(int fd)
145
-{
146
- VFIODeviceFd *file_fd, *next;
147
-
148
- QLIST_FOREACH_SAFE(file_fd, &vfio_device_fds, node, next) {
149
- if (file_fd->fd == fd) {
150
- QLIST_REMOVE(file_fd, node);
151
- g_free(file_fd);
152
- break;
153
- }
154
- }
155
-}
156
-
157
-static int vfio_device_fd_rebind(NotifierWithReturn *notifier, void *data,
158
- Error **errp)
159
-{
160
- VFIODeviceFd *file_fd;
161
- struct kvm_device_attr attr = {
162
- .group = KVM_DEV_VFIO_FILE,
163
- .attr = KVM_DEV_VFIO_FILE_ADD,
164
- };
165
- struct kvm_create_device cd = {
166
- .type = KVM_DEV_TYPE_VFIO,
167
- };
168
-
169
- /* we are not interested in pre vmfd change notification */
170
- if (((VmfdChangeNotifier *)data)->pre) {
171
- return 0;
172
- }
173
-
174
- if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
175
- error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
176
- return -errno;
177
- }
178
-
179
- if (vfio_kvm_device_fd != -1) {
180
- close(vfio_kvm_device_fd);
181
- }
182
-
183
- vfio_kvm_device_fd = cd.fd;
184
-
185
- QLIST_FOREACH(file_fd, &vfio_device_fds, node) {
186
- attr.addr = (uint64_t)(unsigned long)&file_fd->fd;
187
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
188
- error_setg_errno(errp, errno,
189
- "Failed to add fd %d to KVM VFIO device",
190
- file_fd->fd);
191
- return -errno;
192
- }
193
- }
194
- return 0;
195
-}
196
-
197
-static struct NotifierWithReturn vfio_vmfd_change_notifier = {
198
- .notify = vfio_device_fd_rebind,
199
-};
200
-
201
-#endif
202
-
203
-void vfio_kvm_device_close(void)
204
-{
205
-#ifdef CONFIG_KVM
206
- kvm_close();
207
- if (vfio_kvm_device_fd != -1) {
208
- close(vfio_kvm_device_fd);
209
- vfio_kvm_device_fd = -1;
210
- }
211
-#endif
212
-}
213
-
214
-int vfio_kvm_device_add_fd(int fd, Error **errp)
215
-{
216
-#ifdef CONFIG_KVM
217
- struct kvm_device_attr attr = {
218
- .group = KVM_DEV_VFIO_FILE,
219
- .attr = KVM_DEV_VFIO_FILE_ADD,
220
- .addr = (uint64_t)(unsigned long)&fd,
221
- };
222
-
223
- if (!kvm_enabled()) {
224
- return 0;
225
- }
226
-
227
- if (vfio_kvm_device_fd < 0) {
228
- struct kvm_create_device cd = {
229
- .type = KVM_DEV_TYPE_VFIO,
230
- };
231
-
232
- if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
233
- error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
234
- return -errno;
235
- }
236
-
237
- vfio_kvm_device_fd = cd.fd;
238
- /*
239
- * If the vm file descriptor changes, add a notifier so that we can
240
- * re-create the vfio_kvm_device_fd.
241
- */
242
- kvm_vmfd_add_change_notifier(&vfio_vmfd_change_notifier);
243
- }
244
-
245
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
246
- error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
247
- fd);
248
- return -errno;
249
- }
250
-
251
- vfio_device_fd_list_add(fd);
252
-#endif
253
- return 0;
254
-}
255
-
256
-int vfio_kvm_device_del_fd(int fd, Error **errp)
257
-{
258
-#ifdef CONFIG_KVM
259
- struct kvm_device_attr attr = {
260
- .group = KVM_DEV_VFIO_FILE,
261
- .attr = KVM_DEV_VFIO_FILE_DEL,
262
- .addr = (uint64_t)(unsigned long)&fd,
263
- };
264
-
265
- if (vfio_kvm_device_fd < 0) {
266
- error_setg(errp, "KVM VFIO device isn't created yet");
267
- return -EINVAL;
268
- }
269
-
270
- if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
271
- error_setg_errno(errp, errno,
272
- "Failed to remove fd %d from KVM VFIO device", fd);
273
- return -errno;
274
- }
275
-
276
- vfio_device_fd_list_remove(fd);
277
-#endif
278
- return 0;
279
-}
280
-
109
struct vfio_device_info *vfio_get_device_info(int fd)
110
{
111
struct vfio_device_info *info;
hw/vfio/kvm-helpers.c
new
+192
@@ -0,0 +1,192 @@
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 "hw/core/hw-error.h"
29
+#include "qapi/error.h"
30
+#include "vfio-helpers.h"
31
+
32
+/*
33
+ * We have a single VFIO pseudo device per KVM VM. Once created it lives
34
+ * for the life of the VM. Closing the file descriptor only drops our
35
+ * reference to it and the device's reference to kvm. Therefore once
36
+ * initialized, this file descriptor is only released on QEMU exit and
37
+ * we'll re-use it should another vfio device be attached before then.
38
+ */
39
+int vfio_kvm_device_fd = -1;
40
+
41
+/*
42
+ * Confidential virtual machines:
43
+ * During reset of confidential vms, the kvm vm file descriptor changes.
44
+ * In this case, the old vfio kvm file descriptor is
45
+ * closed and a new descriptor is created against the new kvm vm file
46
+ * descriptor.
47
+ */
48
+
49
+typedef struct VFIODeviceFd {
50
+ int fd;
51
+ QLIST_ENTRY(VFIODeviceFd) node;
52
+} VFIODeviceFd;
53
+
54
+static QLIST_HEAD(, VFIODeviceFd) vfio_device_fds =
55
+ QLIST_HEAD_INITIALIZER(vfio_device_fds);
56
+
57
+static void vfio_device_fd_list_add(int fd)
58
+{
59
+ VFIODeviceFd *file_fd;
60
+ file_fd = g_malloc0(sizeof(*file_fd));
61
+ file_fd->fd = fd;
62
+ QLIST_INSERT_HEAD(&vfio_device_fds, file_fd, node);
63
+}
64
+
65
+static void vfio_device_fd_list_remove(int fd)
66
+{
67
+ VFIODeviceFd *file_fd, *next;
68
+
69
+ QLIST_FOREACH_SAFE(file_fd, &vfio_device_fds, node, next) {
70
+ if (file_fd->fd == fd) {
71
+ QLIST_REMOVE(file_fd, node);
72
+ g_free(file_fd);
73
+ break;
74
+ }
75
+ }
76
+}
77
+
78
+static int vfio_device_fd_rebind(NotifierWithReturn *notifier, void *data,
79
+ Error **errp)
80
+{
81
+ VFIODeviceFd *file_fd;
82
+ struct kvm_device_attr attr = {
83
+ .group = KVM_DEV_VFIO_FILE,
84
+ .attr = KVM_DEV_VFIO_FILE_ADD,
85
+ };
86
+ struct kvm_create_device cd = {
87
+ .type = KVM_DEV_TYPE_VFIO,
88
+ };
89
+
90
+ /* we are not interested in pre vmfd change notification */
91
+ if (((VmfdChangeNotifier *)data)->pre) {
92
+ return 0;
93
+ }
94
+
95
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
96
+ error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
97
+ return -errno;
98
+ }
99
+
100
+ if (vfio_kvm_device_fd != -1) {
101
+ close(vfio_kvm_device_fd);
102
+ }
103
+
104
+ vfio_kvm_device_fd = cd.fd;
105
+
106
+ QLIST_FOREACH(file_fd, &vfio_device_fds, node) {
107
+ attr.addr = (uint64_t)(unsigned long)&file_fd->fd;
108
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
109
+ error_setg_errno(errp, errno,
110
+ "Failed to add fd %d to KVM VFIO device",
111
+ file_fd->fd);
112
+ return -errno;
113
+ }
114
+ }
115
+ return 0;
116
+}
117
+
118
+static struct NotifierWithReturn vfio_vmfd_change_notifier = {
119
+ .notify = vfio_device_fd_rebind,
120
+};
121
+
122
+void vfio_kvm_device_close(void)
123
+{
124
+ kvm_close();
125
+ if (vfio_kvm_device_fd != -1) {
126
+ close(vfio_kvm_device_fd);
127
+ vfio_kvm_device_fd = -1;
128
+ }
129
+}
130
+
131
+int vfio_kvm_device_add_fd(int fd, Error **errp)
132
+{
133
+ struct kvm_device_attr attr = {
134
+ .group = KVM_DEV_VFIO_FILE,
135
+ .attr = KVM_DEV_VFIO_FILE_ADD,
136
+ .addr = (uint64_t)(unsigned long)&fd,
137
+ };
138
+
139
+ if (!kvm_enabled()) {
140
+ return 0;
141
+ }
142
+
143
+ if (vfio_kvm_device_fd < 0) {
144
+ struct kvm_create_device cd = {
145
+ .type = KVM_DEV_TYPE_VFIO,
146
+ };
147
+
148
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
149
+ error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
150
+ return -errno;
151
+ }
152
+
153
+ vfio_kvm_device_fd = cd.fd;
154
+ /*
155
+ * If the vm file descriptor changes, add a notifier so that we can
156
+ * re-create the vfio_kvm_device_fd.
157
+ */
158
+ kvm_vmfd_add_change_notifier(&vfio_vmfd_change_notifier);
159
+ }
160
+
161
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
162
+ error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
163
+ fd);
164
+ return -errno;
165
+ }
166
+
167
+ vfio_device_fd_list_add(fd);
168
+ return 0;
169
+}
170
+
171
+int vfio_kvm_device_del_fd(int fd, Error **errp)
172
+{
173
+ struct kvm_device_attr attr = {
174
+ .group = KVM_DEV_VFIO_FILE,
175
+ .attr = KVM_DEV_VFIO_FILE_DEL,
176
+ .addr = (uint64_t)(unsigned long)&fd,
177
+ };
178
+
179
+ if (vfio_kvm_device_fd < 0) {
180
+ error_setg(errp, "KVM VFIO device isn't created yet");
181
+ return -EINVAL;
182
+ }
183
+
184
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
185
+ error_setg_errno(errp, errno,
186
+ "Failed to remove fd %d from KVM VFIO device", fd);
187
+ return -errno;
188
+ }
189
+
190
+ vfio_device_fd_list_remove(fd);
191
+ return 0;
192
+}
hw/vfio/kvm-stubs.c
new
+26
@@ -0,0 +1,26 @@
1
+/*
2
+ * Stubs for kvm helpers
3
+ *
4
+ * SPDX-License-Identifier: GPL-2.0-or-later
5
+ */
6
+
7
+#include "qemu/osdep.h"
8
+
9
+#include "hw/vfio/vfio-device.h"
10
+#include "qapi/error.h"
11
+#include "vfio-helpers.h"
12
+
13
+void vfio_kvm_device_close(void)
14
+{
15
+ return;
16
+}
17
+
18
+int vfio_kvm_device_add_fd(int fd, Error **errp)
19
+{
20
+ return 0;
21
+}
22
+
23
+int vfio_kvm_device_del_fd(int fd, Error **errp)
24
+{
25
+ return 0;
26
+}
hw/vfio/meson.build
+2
@@ -7,6 +7,8 @@ vfio_ss.add(files(
7
'container-legacy.c',
8
'helpers.c',
9
))
10
+vfio_ss.add(when: 'CONFIG_KVM', if_true: files('kvm-helpers.c'))
11
+stub_ss.add(files('kvm-stubs.c'))
12
vfio_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr.c'))
13
vfio_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files(
14
'pci-quirks.c',