remote-obj.c (5043B)
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" 28OBJECT_DECLARE_TYPE(RemoteObject, RemoteObjectClass, REMOTE_OBJECT) 29 30struct RemoteObjectClass { 31 ObjectClass parent_class; 32 33 unsigned int nr_devs; 34 unsigned int max_devs; 35}; 36 37struct 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 52static 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 72static 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 81static 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 91static 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 129static 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 149static 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 167static 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 184static 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 198static void register_types(void) 199{ 200 type_register_static(&remote_object_info); 201} 202 203type_init(register_types);