1 /** 2 * QEMU vfio-user-server server object 3 * 4 * Copyright © 2022 Oracle and/or its affiliates. 5 * 6 * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. 7 * 8 * See the COPYING file in the top-level directory. 9 * 10 */ 11 12 /** 13 * Usage: add options: 14 * -machine x-remote,vfio-user=on,auto-shutdown=on 15 * -device <PCI-device>,id=<pci-dev-id> 16 * -object x-vfio-user-server,id=<id>,type=unix,path=<socket-path>, 17 * device=<pci-dev-id> 18 * 19 * Note that x-vfio-user-server object must be used with x-remote machine only. 20 * This server could only support PCI devices for now. 21 * 22 * type - SocketAddress type - presently "unix" alone is supported. Required 23 * option 24 * 25 * path - named unix socket, it will be created by the server. It is 26 * a required option 27 * 28 * device - id of a device on the server, a required option. PCI devices 29 * alone are supported presently. 30 */ 31 32 #include "qemu/osdep.h" 33 34 #include "qom/object.h" 35 #include "qom/object_interfaces.h" 36 #include "qemu/error-report.h" 37 #include "trace.h" 38 #include "sysemu/runstate.h" 39 #include "hw/boards.h" 40 #include "hw/remote/machine.h" 41 #include "qapi/error.h" 42 #include "qapi/qapi-visit-sockets.h" 43 #include "qemu/notify.h" 44 #include "sysemu/sysemu.h" 45 #include "libvfio-user.h" 46 #include "hw/qdev-core.h" 47 #include "hw/pci/pci.h" 48 49 #define TYPE_VFU_OBJECT "x-vfio-user-server" 50 OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) 51 52 /** 53 * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown 54 * is set, it aborts the machine on error. Otherwise, it logs an 55 * error message without aborting. 56 */ 57 #define VFU_OBJECT_ERROR(o, fmt, ...) \ 58 { \ 59 if (vfu_object_auto_shutdown()) { \ 60 error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ 61 } else { \ 62 error_report((fmt), ## __VA_ARGS__); \ 63 } \ 64 } \ 65 66 struct VfuObjectClass { 67 ObjectClass parent_class; 68 69 unsigned int nr_devs; 70 }; 71 72 struct VfuObject { 73 /* private */ 74 Object parent; 75 76 SocketAddress *socket; 77 78 char *device; 79 80 Error *err; 81 82 Notifier machine_done; 83 84 vfu_ctx_t *vfu_ctx; 85 86 PCIDevice *pci_dev; 87 88 Error *unplug_blocker; 89 }; 90 91 static void vfu_object_init_ctx(VfuObject *o, Error **errp); 92 93 static bool vfu_object_auto_shutdown(void) 94 { 95 bool auto_shutdown = true; 96 Error *local_err = NULL; 97 98 if (!current_machine) { 99 return auto_shutdown; 100 } 101 102 auto_shutdown = object_property_get_bool(OBJECT(current_machine), 103 "auto-shutdown", 104 &local_err); 105 106 /* 107 * local_err would be set if no such property exists - safe to ignore. 108 * Unlikely scenario as auto-shutdown is always defined for 109 * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with 110 * TYPE_REMOTE_MACHINE 111 */ 112 if (local_err) { 113 auto_shutdown = true; 114 error_free(local_err); 115 } 116 117 return auto_shutdown; 118 } 119 120 static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, 121 void *opaque, Error **errp) 122 { 123 VfuObject *o = VFU_OBJECT(obj); 124 125 if (o->vfu_ctx) { 126 error_setg(errp, "vfu: Unable to set socket property - server busy"); 127 return; 128 } 129 130 qapi_free_SocketAddress(o->socket); 131 132 o->socket = NULL; 133 134 visit_type_SocketAddress(v, name, &o->socket, errp); 135 136 if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 137 error_setg(errp, "vfu: Unsupported socket type - %s", 138 SocketAddressType_str(o->socket->type)); 139 qapi_free_SocketAddress(o->socket); 140 o->socket = NULL; 141 return; 142 } 143 144 trace_vfu_prop("socket", o->socket->u.q_unix.path); 145 146 vfu_object_init_ctx(o, errp); 147 } 148 149 static void vfu_object_set_device(Object *obj, const char *str, Error **errp) 150 { 151 VfuObject *o = VFU_OBJECT(obj); 152 153 if (o->vfu_ctx) { 154 error_setg(errp, "vfu: Unable to set device property - server busy"); 155 return; 156 } 157 158 g_free(o->device); 159 160 o->device = g_strdup(str); 161 162 trace_vfu_prop("device", str); 163 164 vfu_object_init_ctx(o, errp); 165 } 166 167 /* 168 * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device' 169 * properties. It also depends on devices instantiated in QEMU. These 170 * dependencies are not available during the instance_init phase of this 171 * object's life-cycle. As such, the server is initialized after the 172 * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT 173 * when the machine is setup, and the dependencies are available. 174 */ 175 static void vfu_object_machine_done(Notifier *notifier, void *data) 176 { 177 VfuObject *o = container_of(notifier, VfuObject, machine_done); 178 Error *err = NULL; 179 180 vfu_object_init_ctx(o, &err); 181 182 if (err) { 183 error_propagate(&error_abort, err); 184 } 185 } 186 187 static void vfu_object_init_ctx(VfuObject *o, Error **errp) 188 { 189 ERRP_GUARD(); 190 DeviceState *dev = NULL; 191 vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL; 192 int ret; 193 194 if (o->vfu_ctx || !o->socket || !o->device || 195 !phase_check(PHASE_MACHINE_READY)) { 196 return; 197 } 198 199 if (o->err) { 200 error_propagate(errp, o->err); 201 o->err = NULL; 202 return; 203 } 204 205 o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, 0, 206 o, VFU_DEV_TYPE_PCI); 207 if (o->vfu_ctx == NULL) { 208 error_setg(errp, "vfu: Failed to create context - %s", strerror(errno)); 209 return; 210 } 211 212 dev = qdev_find_recursive(sysbus_get_default(), o->device); 213 if (dev == NULL) { 214 error_setg(errp, "vfu: Device %s not found", o->device); 215 goto fail; 216 } 217 218 if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 219 error_setg(errp, "vfu: %s not a PCI device", o->device); 220 goto fail; 221 } 222 223 o->pci_dev = PCI_DEVICE(dev); 224 225 object_ref(OBJECT(o->pci_dev)); 226 227 if (pci_is_express(o->pci_dev)) { 228 pci_type = VFU_PCI_TYPE_EXPRESS; 229 } 230 231 ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0); 232 if (ret < 0) { 233 error_setg(errp, 234 "vfu: Failed to attach PCI device %s to context - %s", 235 o->device, strerror(errno)); 236 goto fail; 237 } 238 239 error_setg(&o->unplug_blocker, 240 "vfu: %s for %s must be deleted before unplugging", 241 TYPE_VFU_OBJECT, o->device); 242 qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 243 244 return; 245 246 fail: 247 vfu_destroy_ctx(o->vfu_ctx); 248 if (o->unplug_blocker && o->pci_dev) { 249 qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 250 error_free(o->unplug_blocker); 251 o->unplug_blocker = NULL; 252 } 253 if (o->pci_dev) { 254 object_unref(OBJECT(o->pci_dev)); 255 o->pci_dev = NULL; 256 } 257 o->vfu_ctx = NULL; 258 } 259 260 static void vfu_object_init(Object *obj) 261 { 262 VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 263 VfuObject *o = VFU_OBJECT(obj); 264 265 k->nr_devs++; 266 267 if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 268 error_setg(&o->err, "vfu: %s only compatible with %s machine", 269 TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 270 return; 271 } 272 273 if (!phase_check(PHASE_MACHINE_READY)) { 274 o->machine_done.notify = vfu_object_machine_done; 275 qemu_add_machine_init_done_notifier(&o->machine_done); 276 } 277 278 } 279 280 static void vfu_object_finalize(Object *obj) 281 { 282 VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 283 VfuObject *o = VFU_OBJECT(obj); 284 285 k->nr_devs--; 286 287 qapi_free_SocketAddress(o->socket); 288 289 o->socket = NULL; 290 291 if (o->vfu_ctx) { 292 vfu_destroy_ctx(o->vfu_ctx); 293 o->vfu_ctx = NULL; 294 } 295 296 g_free(o->device); 297 298 o->device = NULL; 299 300 if (o->unplug_blocker && o->pci_dev) { 301 qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 302 error_free(o->unplug_blocker); 303 o->unplug_blocker = NULL; 304 } 305 306 if (o->pci_dev) { 307 object_unref(OBJECT(o->pci_dev)); 308 o->pci_dev = NULL; 309 } 310 311 if (!k->nr_devs && vfu_object_auto_shutdown()) { 312 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 313 } 314 315 if (o->machine_done.notify) { 316 qemu_remove_machine_init_done_notifier(&o->machine_done); 317 o->machine_done.notify = NULL; 318 } 319 } 320 321 static void vfu_object_class_init(ObjectClass *klass, void *data) 322 { 323 VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 324 325 k->nr_devs = 0; 326 327 object_class_property_add(klass, "socket", "SocketAddress", NULL, 328 vfu_object_set_socket, NULL, NULL); 329 object_class_property_set_description(klass, "socket", 330 "SocketAddress " 331 "(ex: type=unix,path=/tmp/sock). " 332 "Only UNIX is presently supported"); 333 object_class_property_add_str(klass, "device", NULL, 334 vfu_object_set_device); 335 object_class_property_set_description(klass, "device", 336 "device ID - only PCI devices " 337 "are presently supported"); 338 } 339 340 static const TypeInfo vfu_object_info = { 341 .name = TYPE_VFU_OBJECT, 342 .parent = TYPE_OBJECT, 343 .instance_size = sizeof(VfuObject), 344 .instance_init = vfu_object_init, 345 .instance_finalize = vfu_object_finalize, 346 .class_size = sizeof(VfuObjectClass), 347 .class_init = vfu_object_class_init, 348 .interfaces = (InterfaceInfo[]) { 349 { TYPE_USER_CREATABLE }, 350 { } 351 } 352 }; 353 354 static void vfu_register_types(void) 355 { 356 type_register_static(&vfu_object_info); 357 } 358 359 type_init(vfu_register_types); 360