cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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);