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