xref: /openbmc/qemu/hw/remote/remote-obj.c (revision c09124dc)
1 /*
2  * Copyright © 2020, 2021 Oracle and/or its affiliates.
3  *
4  * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
5  *
6  * See the COPYING file in the top-level directory.
7  *
8  */
9 
10 #include "qemu/osdep.h"
11 #include "qemu-common.h"
12 
13 #include "qemu/error-report.h"
14 #include "qemu/notify.h"
15 #include "qom/object_interfaces.h"
16 #include "hw/qdev-core.h"
17 #include "io/channel.h"
18 #include "hw/qdev-core.h"
19 #include "hw/remote/machine.h"
20 #include "io/channel-util.h"
21 #include "qapi/error.h"
22 #include "sysemu/sysemu.h"
23 #include "hw/pci/pci.h"
24 #include "qemu/sockets.h"
25 #include "monitor/monitor.h"
26 
27 #define TYPE_REMOTE_OBJECT "x-remote-object"
28 OBJECT_DECLARE_TYPE(RemoteObject, RemoteObjectClass, REMOTE_OBJECT)
29 
30 struct RemoteObjectClass {
31     ObjectClass parent_class;
32 
33     unsigned int nr_devs;
34     unsigned int max_devs;
35 };
36 
37 struct RemoteObject {
38     /* private */
39     Object parent;
40 
41     Notifier machine_done;
42 
43     int32_t fd;
44     char *devid;
45 
46     QIOChannel *ioc;
47 
48     DeviceState *dev;
49     DeviceListener listener;
50 };
51 
52 static void remote_object_set_fd(Object *obj, const char *str, Error **errp)
53 {
54     RemoteObject *o = REMOTE_OBJECT(obj);
55     int fd = -1;
56 
57     fd = monitor_fd_param(monitor_cur(), str, errp);
58     if (fd == -1) {
59         error_prepend(errp, "Could not parse remote object fd %s:", str);
60         return;
61     }
62 
63     if (!fd_is_socket(fd)) {
64         error_setg(errp, "File descriptor '%s' is not a socket", str);
65         close(fd);
66         return;
67     }
68 
69     o->fd = fd;
70 }
71 
72 static void remote_object_set_devid(Object *obj, const char *str, Error **errp)
73 {
74     RemoteObject *o = REMOTE_OBJECT(obj);
75 
76     g_free(o->devid);
77 
78     o->devid = g_strdup(str);
79 }
80 
81 static void remote_object_unrealize_listener(DeviceListener *listener,
82                                              DeviceState *dev)
83 {
84     RemoteObject *o = container_of(listener, RemoteObject, listener);
85 
86     if (o->dev == dev) {
87         object_unref(OBJECT(o));
88     }
89 }
90 
91 static void remote_object_machine_done(Notifier *notifier, void *data)
92 {
93     RemoteObject *o = container_of(notifier, RemoteObject, machine_done);
94     DeviceState *dev = NULL;
95     QIOChannel *ioc = NULL;
96     Coroutine *co = NULL;
97     RemoteCommDev *comdev = NULL;
98     Error *err = NULL;
99 
100     dev = qdev_find_recursive(sysbus_get_default(), o->devid);
101     if (!dev || !object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
102         error_report("%s is not a PCI device", o->devid);
103         return;
104     }
105 
106     ioc = qio_channel_new_fd(o->fd, &err);
107     if (!ioc) {
108         error_report_err(err);
109         return;
110     }
111     qio_channel_set_blocking(ioc, false, NULL);
112 
113     o->dev = dev;
114 
115     o->listener.unrealize = remote_object_unrealize_listener;
116     device_listener_register(&o->listener);
117 
118     /* co-routine should free this. */
119     comdev = g_new0(RemoteCommDev, 1);
120     *comdev = (RemoteCommDev) {
121         .ioc = ioc,
122         .dev = PCI_DEVICE(dev),
123     };
124 
125     co = qemu_coroutine_create(mpqemu_remote_msg_loop_co, comdev);
126     qemu_coroutine_enter(co);
127 }
128 
129 static void remote_object_init(Object *obj)
130 {
131     RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj);
132     RemoteObject *o = REMOTE_OBJECT(obj);
133 
134     if (k->nr_devs >= k->max_devs) {
135         error_report("Reached maximum number of devices: %u", k->max_devs);
136         return;
137     }
138 
139     o->ioc = NULL;
140     o->fd = -1;
141     o->devid = NULL;
142 
143     k->nr_devs++;
144 
145     o->machine_done.notify = remote_object_machine_done;
146     qemu_add_machine_init_done_notifier(&o->machine_done);
147 }
148 
149 static void remote_object_finalize(Object *obj)
150 {
151     RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj);
152     RemoteObject *o = REMOTE_OBJECT(obj);
153 
154     device_listener_unregister(&o->listener);
155 
156     if (o->ioc) {
157         qio_channel_shutdown(o->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
158         qio_channel_close(o->ioc, NULL);
159     }
160 
161     object_unref(OBJECT(o->ioc));
162 
163     k->nr_devs--;
164     g_free(o->devid);
165 }
166 
167 static void remote_object_class_init(ObjectClass *klass, void *data)
168 {
169     RemoteObjectClass *k = REMOTE_OBJECT_CLASS(klass);
170 
171     /*
172      * Limit number of supported devices to 1. This is done to avoid devices
173      * from one VM accessing the RAM of another VM. This is done until we
174      * start using separate address spaces for individual devices.
175      */
176     k->max_devs = 1;
177     k->nr_devs = 0;
178 
179     object_class_property_add_str(klass, "fd", NULL, remote_object_set_fd);
180     object_class_property_add_str(klass, "devid", NULL,
181                                   remote_object_set_devid);
182 }
183 
184 static const TypeInfo remote_object_info = {
185     .name = TYPE_REMOTE_OBJECT,
186     .parent = TYPE_OBJECT,
187     .instance_size = sizeof(RemoteObject),
188     .instance_init = remote_object_init,
189     .instance_finalize = remote_object_finalize,
190     .class_size = sizeof(RemoteObjectClass),
191     .class_init = remote_object_class_init,
192     .interfaces = (InterfaceInfo[]) {
193         { TYPE_USER_CREATABLE },
194         { }
195     }
196 };
197 
198 static void register_types(void)
199 {
200     type_register_static(&remote_object_info);
201 }
202 
203 type_init(register_types);
204