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

qdev-clock.c (5905B)


      1/*
      2 * Device's clock input and output
      3 *
      4 * Copyright GreenSocs 2016-2020
      5 *
      6 * Authors:
      7 *  Frederic Konrad
      8 *  Damien Hedde
      9 *
     10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     11 * See the COPYING file in the top-level directory.
     12 */
     13
     14#include "qemu/osdep.h"
     15#include "qemu/error-report.h"
     16#include "hw/qdev-clock.h"
     17#include "hw/qdev-core.h"
     18#include "qapi/error.h"
     19
     20/*
     21 * qdev_init_clocklist:
     22 * Add a new clock in a device
     23 */
     24static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name,
     25                                           bool output, Clock *clk)
     26{
     27    NamedClockList *ncl;
     28
     29    /*
     30     * Clock must be added before realize() so that we can compute the
     31     * clock's canonical path during device_realize().
     32     */
     33    assert(!dev->realized);
     34
     35    /*
     36     * The ncl structure is freed by qdev_finalize_clocklist() which will
     37     * be called during @dev's device_finalize().
     38     */
     39    ncl = g_new0(NamedClockList, 1);
     40    ncl->name = g_strdup(name);
     41    ncl->output = output;
     42    ncl->alias = (clk != NULL);
     43
     44    /*
     45     * Trying to create a clock whose name clashes with some other
     46     * clock or property is a bug in the caller and we will abort().
     47     */
     48    if (clk == NULL) {
     49        clk = CLOCK(object_new(TYPE_CLOCK));
     50        object_property_add_child(OBJECT(dev), name, OBJECT(clk));
     51        if (output) {
     52            /*
     53             * Remove object_new()'s initial reference.
     54             * Note that for inputs, the reference created by object_new()
     55             * will be deleted in qdev_finalize_clocklist().
     56             */
     57            object_unref(OBJECT(clk));
     58        }
     59    } else {
     60        object_property_add_link(OBJECT(dev), name,
     61                                 object_get_typename(OBJECT(clk)),
     62                                 (Object **) &ncl->clock,
     63                                 NULL, OBJ_PROP_LINK_STRONG);
     64        /*
     65         * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
     66         * object reference count gets decremented on property deletion.
     67         * However object_property_add_link does not increment it since it
     68         * doesn't know the linked object. Increment it here to ensure the
     69         * aliased clock stays alive during this device life-time.
     70         */
     71        object_ref(OBJECT(clk));
     72    }
     73
     74    ncl->clock = clk;
     75
     76    QLIST_INSERT_HEAD(&dev->clocks, ncl, node);
     77    return ncl;
     78}
     79
     80void qdev_finalize_clocklist(DeviceState *dev)
     81{
     82    /* called by @dev's device_finalize() */
     83    NamedClockList *ncl, *ncl_next;
     84
     85    QLIST_FOREACH_SAFE(ncl, &dev->clocks, node, ncl_next) {
     86        QLIST_REMOVE(ncl, node);
     87        if (!ncl->output && !ncl->alias) {
     88            /*
     89             * We kept a reference on the input clock to ensure it lives up to
     90             * this point so we can safely remove the callback.
     91             * It avoids having a callback to a deleted object if ncl->clock
     92             * is still referenced somewhere else (eg: by a clock output).
     93             */
     94            clock_clear_callback(ncl->clock);
     95            object_unref(OBJECT(ncl->clock));
     96        }
     97        g_free(ncl->name);
     98        g_free(ncl);
     99    }
    100}
    101
    102Clock *qdev_init_clock_out(DeviceState *dev, const char *name)
    103{
    104    NamedClockList *ncl;
    105
    106    assert(name);
    107
    108    ncl = qdev_init_clocklist(dev, name, true, NULL);
    109
    110    return ncl->clock;
    111}
    112
    113Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
    114                          ClockCallback *callback, void *opaque,
    115                          unsigned int events)
    116{
    117    NamedClockList *ncl;
    118
    119    assert(name);
    120
    121    ncl = qdev_init_clocklist(dev, name, false, NULL);
    122
    123    if (callback) {
    124        clock_set_callback(ncl->clock, callback, opaque, events);
    125    }
    126    return ncl->clock;
    127}
    128
    129void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
    130{
    131    const struct ClockPortInitElem *elem;
    132
    133    for (elem = &clocks[0]; elem->name != NULL; elem++) {
    134        Clock **clkp;
    135        /* offset cannot be inside the DeviceState part */
    136        assert(elem->offset > sizeof(DeviceState));
    137        clkp = (Clock **)(((void *) dev) + elem->offset);
    138        if (elem->is_output) {
    139            *clkp = qdev_init_clock_out(dev, elem->name);
    140        } else {
    141            *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev,
    142                                       elem->callback_events);
    143        }
    144    }
    145}
    146
    147static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name)
    148{
    149    NamedClockList *ncl;
    150
    151    QLIST_FOREACH(ncl, &dev->clocks, node) {
    152        if (strcmp(name, ncl->name) == 0) {
    153            return ncl;
    154        }
    155    }
    156
    157    return NULL;
    158}
    159
    160Clock *qdev_get_clock_in(DeviceState *dev, const char *name)
    161{
    162    NamedClockList *ncl;
    163
    164    assert(name);
    165
    166    ncl = qdev_get_clocklist(dev, name);
    167    if (!ncl) {
    168        error_report("Can not find clock-in '%s' for device type '%s'",
    169                     name, object_get_typename(OBJECT(dev)));
    170        abort();
    171    }
    172    assert(!ncl->output);
    173
    174    return ncl->clock;
    175}
    176
    177Clock *qdev_get_clock_out(DeviceState *dev, const char *name)
    178{
    179    NamedClockList *ncl;
    180
    181    assert(name);
    182
    183    ncl = qdev_get_clocklist(dev, name);
    184    if (!ncl) {
    185        error_report("Can not find clock-out '%s' for device type '%s'",
    186                     name, object_get_typename(OBJECT(dev)));
    187        abort();
    188    }
    189    assert(ncl->output);
    190
    191    return ncl->clock;
    192}
    193
    194Clock *qdev_alias_clock(DeviceState *dev, const char *name,
    195                        DeviceState *alias_dev, const char *alias_name)
    196{
    197    NamedClockList *ncl;
    198
    199    assert(name && alias_name);
    200
    201    ncl = qdev_get_clocklist(dev, name);
    202
    203    qdev_init_clocklist(alias_dev, alias_name, ncl->output, ncl->clock);
    204
    205    return ncl->clock;
    206}
    207
    208void qdev_connect_clock_in(DeviceState *dev, const char *name, Clock *source)
    209{
    210    assert(!dev->realized);
    211    clock_set_source(qdev_get_clock_in(dev, name), source);
    212}