1*8f9a9259SJagannathan Raman /** 2*8f9a9259SJagannathan Raman * QEMU vfio-user-server server object 3*8f9a9259SJagannathan Raman * 4*8f9a9259SJagannathan Raman * Copyright © 2022 Oracle and/or its affiliates. 5*8f9a9259SJagannathan Raman * 6*8f9a9259SJagannathan Raman * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. 7*8f9a9259SJagannathan Raman * 8*8f9a9259SJagannathan Raman * See the COPYING file in the top-level directory. 9*8f9a9259SJagannathan Raman * 10*8f9a9259SJagannathan Raman */ 11*8f9a9259SJagannathan Raman 12*8f9a9259SJagannathan Raman /** 13*8f9a9259SJagannathan Raman * Usage: add options: 14*8f9a9259SJagannathan Raman * -machine x-remote,vfio-user=on,auto-shutdown=on 15*8f9a9259SJagannathan Raman * -device <PCI-device>,id=<pci-dev-id> 16*8f9a9259SJagannathan Raman * -object x-vfio-user-server,id=<id>,type=unix,path=<socket-path>, 17*8f9a9259SJagannathan Raman * device=<pci-dev-id> 18*8f9a9259SJagannathan Raman * 19*8f9a9259SJagannathan Raman * Note that x-vfio-user-server object must be used with x-remote machine only. 20*8f9a9259SJagannathan Raman * This server could only support PCI devices for now. 21*8f9a9259SJagannathan Raman * 22*8f9a9259SJagannathan Raman * type - SocketAddress type - presently "unix" alone is supported. Required 23*8f9a9259SJagannathan Raman * option 24*8f9a9259SJagannathan Raman * 25*8f9a9259SJagannathan Raman * path - named unix socket, it will be created by the server. It is 26*8f9a9259SJagannathan Raman * a required option 27*8f9a9259SJagannathan Raman * 28*8f9a9259SJagannathan Raman * device - id of a device on the server, a required option. PCI devices 29*8f9a9259SJagannathan Raman * alone are supported presently. 30*8f9a9259SJagannathan Raman */ 31*8f9a9259SJagannathan Raman 32*8f9a9259SJagannathan Raman #include "qemu/osdep.h" 33*8f9a9259SJagannathan Raman 34*8f9a9259SJagannathan Raman #include "qom/object.h" 35*8f9a9259SJagannathan Raman #include "qom/object_interfaces.h" 36*8f9a9259SJagannathan Raman #include "qemu/error-report.h" 37*8f9a9259SJagannathan Raman #include "trace.h" 38*8f9a9259SJagannathan Raman #include "sysemu/runstate.h" 39*8f9a9259SJagannathan Raman #include "hw/boards.h" 40*8f9a9259SJagannathan Raman #include "hw/remote/machine.h" 41*8f9a9259SJagannathan Raman #include "qapi/error.h" 42*8f9a9259SJagannathan Raman #include "qapi/qapi-visit-sockets.h" 43*8f9a9259SJagannathan Raman 44*8f9a9259SJagannathan Raman #define TYPE_VFU_OBJECT "x-vfio-user-server" 45*8f9a9259SJagannathan Raman OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) 46*8f9a9259SJagannathan Raman 47*8f9a9259SJagannathan Raman /** 48*8f9a9259SJagannathan Raman * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown 49*8f9a9259SJagannathan Raman * is set, it aborts the machine on error. Otherwise, it logs an 50*8f9a9259SJagannathan Raman * error message without aborting. 51*8f9a9259SJagannathan Raman */ 52*8f9a9259SJagannathan Raman #define VFU_OBJECT_ERROR(o, fmt, ...) \ 53*8f9a9259SJagannathan Raman { \ 54*8f9a9259SJagannathan Raman if (vfu_object_auto_shutdown()) { \ 55*8f9a9259SJagannathan Raman error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ 56*8f9a9259SJagannathan Raman } else { \ 57*8f9a9259SJagannathan Raman error_report((fmt), ## __VA_ARGS__); \ 58*8f9a9259SJagannathan Raman } \ 59*8f9a9259SJagannathan Raman } \ 60*8f9a9259SJagannathan Raman 61*8f9a9259SJagannathan Raman struct VfuObjectClass { 62*8f9a9259SJagannathan Raman ObjectClass parent_class; 63*8f9a9259SJagannathan Raman 64*8f9a9259SJagannathan Raman unsigned int nr_devs; 65*8f9a9259SJagannathan Raman }; 66*8f9a9259SJagannathan Raman 67*8f9a9259SJagannathan Raman struct VfuObject { 68*8f9a9259SJagannathan Raman /* private */ 69*8f9a9259SJagannathan Raman Object parent; 70*8f9a9259SJagannathan Raman 71*8f9a9259SJagannathan Raman SocketAddress *socket; 72*8f9a9259SJagannathan Raman 73*8f9a9259SJagannathan Raman char *device; 74*8f9a9259SJagannathan Raman 75*8f9a9259SJagannathan Raman Error *err; 76*8f9a9259SJagannathan Raman }; 77*8f9a9259SJagannathan Raman 78*8f9a9259SJagannathan Raman static bool vfu_object_auto_shutdown(void) 79*8f9a9259SJagannathan Raman { 80*8f9a9259SJagannathan Raman bool auto_shutdown = true; 81*8f9a9259SJagannathan Raman Error *local_err = NULL; 82*8f9a9259SJagannathan Raman 83*8f9a9259SJagannathan Raman if (!current_machine) { 84*8f9a9259SJagannathan Raman return auto_shutdown; 85*8f9a9259SJagannathan Raman } 86*8f9a9259SJagannathan Raman 87*8f9a9259SJagannathan Raman auto_shutdown = object_property_get_bool(OBJECT(current_machine), 88*8f9a9259SJagannathan Raman "auto-shutdown", 89*8f9a9259SJagannathan Raman &local_err); 90*8f9a9259SJagannathan Raman 91*8f9a9259SJagannathan Raman /* 92*8f9a9259SJagannathan Raman * local_err would be set if no such property exists - safe to ignore. 93*8f9a9259SJagannathan Raman * Unlikely scenario as auto-shutdown is always defined for 94*8f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with 95*8f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE 96*8f9a9259SJagannathan Raman */ 97*8f9a9259SJagannathan Raman if (local_err) { 98*8f9a9259SJagannathan Raman auto_shutdown = true; 99*8f9a9259SJagannathan Raman error_free(local_err); 100*8f9a9259SJagannathan Raman } 101*8f9a9259SJagannathan Raman 102*8f9a9259SJagannathan Raman return auto_shutdown; 103*8f9a9259SJagannathan Raman } 104*8f9a9259SJagannathan Raman 105*8f9a9259SJagannathan Raman static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, 106*8f9a9259SJagannathan Raman void *opaque, Error **errp) 107*8f9a9259SJagannathan Raman { 108*8f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 109*8f9a9259SJagannathan Raman 110*8f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 111*8f9a9259SJagannathan Raman 112*8f9a9259SJagannathan Raman o->socket = NULL; 113*8f9a9259SJagannathan Raman 114*8f9a9259SJagannathan Raman visit_type_SocketAddress(v, name, &o->socket, errp); 115*8f9a9259SJagannathan Raman 116*8f9a9259SJagannathan Raman if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 117*8f9a9259SJagannathan Raman error_setg(errp, "vfu: Unsupported socket type - %s", 118*8f9a9259SJagannathan Raman SocketAddressType_str(o->socket->type)); 119*8f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 120*8f9a9259SJagannathan Raman o->socket = NULL; 121*8f9a9259SJagannathan Raman return; 122*8f9a9259SJagannathan Raman } 123*8f9a9259SJagannathan Raman 124*8f9a9259SJagannathan Raman trace_vfu_prop("socket", o->socket->u.q_unix.path); 125*8f9a9259SJagannathan Raman } 126*8f9a9259SJagannathan Raman 127*8f9a9259SJagannathan Raman static void vfu_object_set_device(Object *obj, const char *str, Error **errp) 128*8f9a9259SJagannathan Raman { 129*8f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 130*8f9a9259SJagannathan Raman 131*8f9a9259SJagannathan Raman g_free(o->device); 132*8f9a9259SJagannathan Raman 133*8f9a9259SJagannathan Raman o->device = g_strdup(str); 134*8f9a9259SJagannathan Raman 135*8f9a9259SJagannathan Raman trace_vfu_prop("device", str); 136*8f9a9259SJagannathan Raman } 137*8f9a9259SJagannathan Raman 138*8f9a9259SJagannathan Raman static void vfu_object_init(Object *obj) 139*8f9a9259SJagannathan Raman { 140*8f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 141*8f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 142*8f9a9259SJagannathan Raman 143*8f9a9259SJagannathan Raman k->nr_devs++; 144*8f9a9259SJagannathan Raman 145*8f9a9259SJagannathan Raman if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 146*8f9a9259SJagannathan Raman error_setg(&o->err, "vfu: %s only compatible with %s machine", 147*8f9a9259SJagannathan Raman TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 148*8f9a9259SJagannathan Raman return; 149*8f9a9259SJagannathan Raman } 150*8f9a9259SJagannathan Raman } 151*8f9a9259SJagannathan Raman 152*8f9a9259SJagannathan Raman static void vfu_object_finalize(Object *obj) 153*8f9a9259SJagannathan Raman { 154*8f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 155*8f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 156*8f9a9259SJagannathan Raman 157*8f9a9259SJagannathan Raman k->nr_devs--; 158*8f9a9259SJagannathan Raman 159*8f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 160*8f9a9259SJagannathan Raman 161*8f9a9259SJagannathan Raman o->socket = NULL; 162*8f9a9259SJagannathan Raman 163*8f9a9259SJagannathan Raman g_free(o->device); 164*8f9a9259SJagannathan Raman 165*8f9a9259SJagannathan Raman o->device = NULL; 166*8f9a9259SJagannathan Raman 167*8f9a9259SJagannathan Raman if (!k->nr_devs && vfu_object_auto_shutdown()) { 168*8f9a9259SJagannathan Raman qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 169*8f9a9259SJagannathan Raman } 170*8f9a9259SJagannathan Raman } 171*8f9a9259SJagannathan Raman 172*8f9a9259SJagannathan Raman static void vfu_object_class_init(ObjectClass *klass, void *data) 173*8f9a9259SJagannathan Raman { 174*8f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 175*8f9a9259SJagannathan Raman 176*8f9a9259SJagannathan Raman k->nr_devs = 0; 177*8f9a9259SJagannathan Raman 178*8f9a9259SJagannathan Raman object_class_property_add(klass, "socket", "SocketAddress", NULL, 179*8f9a9259SJagannathan Raman vfu_object_set_socket, NULL, NULL); 180*8f9a9259SJagannathan Raman object_class_property_set_description(klass, "socket", 181*8f9a9259SJagannathan Raman "SocketAddress " 182*8f9a9259SJagannathan Raman "(ex: type=unix,path=/tmp/sock). " 183*8f9a9259SJagannathan Raman "Only UNIX is presently supported"); 184*8f9a9259SJagannathan Raman object_class_property_add_str(klass, "device", NULL, 185*8f9a9259SJagannathan Raman vfu_object_set_device); 186*8f9a9259SJagannathan Raman object_class_property_set_description(klass, "device", 187*8f9a9259SJagannathan Raman "device ID - only PCI devices " 188*8f9a9259SJagannathan Raman "are presently supported"); 189*8f9a9259SJagannathan Raman } 190*8f9a9259SJagannathan Raman 191*8f9a9259SJagannathan Raman static const TypeInfo vfu_object_info = { 192*8f9a9259SJagannathan Raman .name = TYPE_VFU_OBJECT, 193*8f9a9259SJagannathan Raman .parent = TYPE_OBJECT, 194*8f9a9259SJagannathan Raman .instance_size = sizeof(VfuObject), 195*8f9a9259SJagannathan Raman .instance_init = vfu_object_init, 196*8f9a9259SJagannathan Raman .instance_finalize = vfu_object_finalize, 197*8f9a9259SJagannathan Raman .class_size = sizeof(VfuObjectClass), 198*8f9a9259SJagannathan Raman .class_init = vfu_object_class_init, 199*8f9a9259SJagannathan Raman .interfaces = (InterfaceInfo[]) { 200*8f9a9259SJagannathan Raman { TYPE_USER_CREATABLE }, 201*8f9a9259SJagannathan Raman { } 202*8f9a9259SJagannathan Raman } 203*8f9a9259SJagannathan Raman }; 204*8f9a9259SJagannathan Raman 205*8f9a9259SJagannathan Raman static void vfu_register_types(void) 206*8f9a9259SJagannathan Raman { 207*8f9a9259SJagannathan Raman type_register_static(&vfu_object_info); 208*8f9a9259SJagannathan Raman } 209*8f9a9259SJagannathan Raman 210*8f9a9259SJagannathan Raman type_init(vfu_register_types); 211