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 44 #define TYPE_VFU_OBJECT "x-vfio-user-server" 45 OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) 46 47 /** 48 * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown 49 * is set, it aborts the machine on error. Otherwise, it logs an 50 * error message without aborting. 51 */ 52 #define VFU_OBJECT_ERROR(o, fmt, ...) \ 53 { \ 54 if (vfu_object_auto_shutdown()) { \ 55 error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ 56 } else { \ 57 error_report((fmt), ## __VA_ARGS__); \ 58 } \ 59 } \ 60 61 struct VfuObjectClass { 62 ObjectClass parent_class; 63 64 unsigned int nr_devs; 65 }; 66 67 struct VfuObject { 68 /* private */ 69 Object parent; 70 71 SocketAddress *socket; 72 73 char *device; 74 75 Error *err; 76 }; 77 78 static bool vfu_object_auto_shutdown(void) 79 { 80 bool auto_shutdown = true; 81 Error *local_err = NULL; 82 83 if (!current_machine) { 84 return auto_shutdown; 85 } 86 87 auto_shutdown = object_property_get_bool(OBJECT(current_machine), 88 "auto-shutdown", 89 &local_err); 90 91 /* 92 * local_err would be set if no such property exists - safe to ignore. 93 * Unlikely scenario as auto-shutdown is always defined for 94 * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with 95 * TYPE_REMOTE_MACHINE 96 */ 97 if (local_err) { 98 auto_shutdown = true; 99 error_free(local_err); 100 } 101 102 return auto_shutdown; 103 } 104 105 static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, 106 void *opaque, Error **errp) 107 { 108 VfuObject *o = VFU_OBJECT(obj); 109 110 qapi_free_SocketAddress(o->socket); 111 112 o->socket = NULL; 113 114 visit_type_SocketAddress(v, name, &o->socket, errp); 115 116 if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 117 error_setg(errp, "vfu: Unsupported socket type - %s", 118 SocketAddressType_str(o->socket->type)); 119 qapi_free_SocketAddress(o->socket); 120 o->socket = NULL; 121 return; 122 } 123 124 trace_vfu_prop("socket", o->socket->u.q_unix.path); 125 } 126 127 static void vfu_object_set_device(Object *obj, const char *str, Error **errp) 128 { 129 VfuObject *o = VFU_OBJECT(obj); 130 131 g_free(o->device); 132 133 o->device = g_strdup(str); 134 135 trace_vfu_prop("device", str); 136 } 137 138 static void vfu_object_init(Object *obj) 139 { 140 VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 141 VfuObject *o = VFU_OBJECT(obj); 142 143 k->nr_devs++; 144 145 if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 146 error_setg(&o->err, "vfu: %s only compatible with %s machine", 147 TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 148 return; 149 } 150 } 151 152 static void vfu_object_finalize(Object *obj) 153 { 154 VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 155 VfuObject *o = VFU_OBJECT(obj); 156 157 k->nr_devs--; 158 159 qapi_free_SocketAddress(o->socket); 160 161 o->socket = NULL; 162 163 g_free(o->device); 164 165 o->device = NULL; 166 167 if (!k->nr_devs && vfu_object_auto_shutdown()) { 168 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 169 } 170 } 171 172 static void vfu_object_class_init(ObjectClass *klass, void *data) 173 { 174 VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 175 176 k->nr_devs = 0; 177 178 object_class_property_add(klass, "socket", "SocketAddress", NULL, 179 vfu_object_set_socket, NULL, NULL); 180 object_class_property_set_description(klass, "socket", 181 "SocketAddress " 182 "(ex: type=unix,path=/tmp/sock). " 183 "Only UNIX is presently supported"); 184 object_class_property_add_str(klass, "device", NULL, 185 vfu_object_set_device); 186 object_class_property_set_description(klass, "device", 187 "device ID - only PCI devices " 188 "are presently supported"); 189 } 190 191 static const TypeInfo vfu_object_info = { 192 .name = TYPE_VFU_OBJECT, 193 .parent = TYPE_OBJECT, 194 .instance_size = sizeof(VfuObject), 195 .instance_init = vfu_object_init, 196 .instance_finalize = vfu_object_finalize, 197 .class_size = sizeof(VfuObjectClass), 198 .class_init = vfu_object_class_init, 199 .interfaces = (InterfaceInfo[]) { 200 { TYPE_USER_CREATABLE }, 201 { } 202 } 203 }; 204 205 static void vfu_register_types(void) 206 { 207 type_register_static(&vfu_object_info); 208 } 209 210 type_init(vfu_register_types); 211