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

yank.c (5061B)


      1/*
      2 * QEMU yank feature
      3 *
      4 * Copyright (c) Lukas Straub <lukasstraub2@web.de>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7 * See the COPYING file in the top-level directory.
      8 */
      9
     10#include "qemu/osdep.h"
     11#include "qapi/error.h"
     12#include "qemu/thread.h"
     13#include "qemu/queue.h"
     14#include "qemu/lockable.h"
     15#include "qapi/qapi-commands-yank.h"
     16#include "qapi/qapi-visit-yank.h"
     17#include "qapi/clone-visitor.h"
     18#include "qemu/yank.h"
     19
     20struct YankFuncAndParam {
     21    YankFn *func;
     22    void *opaque;
     23    QLIST_ENTRY(YankFuncAndParam) next;
     24};
     25
     26struct YankInstanceEntry {
     27    YankInstance *instance;
     28    QLIST_HEAD(, YankFuncAndParam) yankfns;
     29    QLIST_ENTRY(YankInstanceEntry) next;
     30};
     31
     32typedef struct YankFuncAndParam YankFuncAndParam;
     33typedef struct YankInstanceEntry YankInstanceEntry;
     34
     35/*
     36 * This lock protects the yank_instance_list below. Because it's taken by
     37 * OOB-capable commands, it must be "fast", i.e. it may only be held for a
     38 * bounded, short time. See docs/devel/qapi-code-gen.txt for additional
     39 * information.
     40 */
     41static QemuMutex yank_lock;
     42
     43static QLIST_HEAD(, YankInstanceEntry) yank_instance_list
     44    = QLIST_HEAD_INITIALIZER(yank_instance_list);
     45
     46static bool yank_instance_equal(const YankInstance *a, const YankInstance *b)
     47{
     48    if (a->type != b->type) {
     49        return false;
     50    }
     51
     52    switch (a->type) {
     53    case YANK_INSTANCE_TYPE_BLOCK_NODE:
     54        return g_str_equal(a->u.block_node.node_name,
     55                           b->u.block_node.node_name);
     56
     57    case YANK_INSTANCE_TYPE_CHARDEV:
     58        return g_str_equal(a->u.chardev.id, b->u.chardev.id);
     59
     60    case YANK_INSTANCE_TYPE_MIGRATION:
     61        return true;
     62
     63    default:
     64        abort();
     65    }
     66}
     67
     68static YankInstanceEntry *yank_find_entry(const YankInstance *instance)
     69{
     70    YankInstanceEntry *entry;
     71
     72    QLIST_FOREACH(entry, &yank_instance_list, next) {
     73        if (yank_instance_equal(entry->instance, instance)) {
     74            return entry;
     75        }
     76    }
     77    return NULL;
     78}
     79
     80bool yank_register_instance(const YankInstance *instance, Error **errp)
     81{
     82    YankInstanceEntry *entry;
     83
     84    QEMU_LOCK_GUARD(&yank_lock);
     85
     86    if (yank_find_entry(instance)) {
     87        error_setg(errp, "duplicate yank instance");
     88        return false;
     89    }
     90
     91    entry = g_new0(YankInstanceEntry, 1);
     92    entry->instance = QAPI_CLONE(YankInstance, instance);
     93    QLIST_INIT(&entry->yankfns);
     94    QLIST_INSERT_HEAD(&yank_instance_list, entry, next);
     95
     96    return true;
     97}
     98
     99void yank_unregister_instance(const YankInstance *instance)
    100{
    101    YankInstanceEntry *entry;
    102
    103    QEMU_LOCK_GUARD(&yank_lock);
    104    entry = yank_find_entry(instance);
    105    assert(entry);
    106
    107    assert(QLIST_EMPTY(&entry->yankfns));
    108    QLIST_REMOVE(entry, next);
    109    qapi_free_YankInstance(entry->instance);
    110    g_free(entry);
    111}
    112
    113void yank_register_function(const YankInstance *instance,
    114                            YankFn *func,
    115                            void *opaque)
    116{
    117    YankInstanceEntry *entry;
    118    YankFuncAndParam *func_entry;
    119
    120    QEMU_LOCK_GUARD(&yank_lock);
    121    entry = yank_find_entry(instance);
    122    assert(entry);
    123
    124    func_entry = g_new0(YankFuncAndParam, 1);
    125    func_entry->func = func;
    126    func_entry->opaque = opaque;
    127
    128    QLIST_INSERT_HEAD(&entry->yankfns, func_entry, next);
    129}
    130
    131void yank_unregister_function(const YankInstance *instance,
    132                              YankFn *func,
    133                              void *opaque)
    134{
    135    YankInstanceEntry *entry;
    136    YankFuncAndParam *func_entry;
    137
    138    QEMU_LOCK_GUARD(&yank_lock);
    139    entry = yank_find_entry(instance);
    140    assert(entry);
    141
    142    QLIST_FOREACH(func_entry, &entry->yankfns, next) {
    143        if (func_entry->func == func && func_entry->opaque == opaque) {
    144            QLIST_REMOVE(func_entry, next);
    145            g_free(func_entry);
    146            return;
    147        }
    148    }
    149
    150    abort();
    151}
    152
    153void qmp_yank(YankInstanceList *instances,
    154              Error **errp)
    155{
    156    YankInstanceList *tail;
    157    YankInstanceEntry *entry;
    158    YankFuncAndParam *func_entry;
    159
    160    QEMU_LOCK_GUARD(&yank_lock);
    161    for (tail = instances; tail; tail = tail->next) {
    162        entry = yank_find_entry(tail->value);
    163        if (!entry) {
    164            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Instance not found");
    165            return;
    166        }
    167    }
    168    for (tail = instances; tail; tail = tail->next) {
    169        entry = yank_find_entry(tail->value);
    170        assert(entry);
    171        QLIST_FOREACH(func_entry, &entry->yankfns, next) {
    172            func_entry->func(func_entry->opaque);
    173        }
    174    }
    175}
    176
    177YankInstanceList *qmp_query_yank(Error **errp)
    178{
    179    YankInstanceEntry *entry;
    180    YankInstanceList *ret;
    181
    182    ret = NULL;
    183
    184    QEMU_LOCK_GUARD(&yank_lock);
    185    QLIST_FOREACH(entry, &yank_instance_list, next) {
    186        YankInstanceList *new_entry;
    187        new_entry = g_new0(YankInstanceList, 1);
    188        new_entry->value = QAPI_CLONE(YankInstance, entry->instance);
    189        new_entry->next = ret;
    190        ret = new_entry;
    191    }
    192
    193    return ret;
    194}
    195
    196static void __attribute__((__constructor__)) yank_init(void)
    197{
    198    qemu_mutex_init(&yank_lock);
    199}