@samitouri / QOSamiQemu / commits / 09df2b17ed

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',