qemu/hw/remote/remote-obj.c
<<
>>
Prefs
   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);
 204