xref: /qemu/hw/remote/vfio-user-obj.c (revision 8f9a9259d32c1b6ba41a38ad99fc67bcc0da0131)
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