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