qemu/injection.c
<<
>>
Prefs
   1/*
   2 * fault_injection.c
   3 *
   4 * Copyright (C) 2016 Fred KONRAD <fred.konrad@greensocs.com>
   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
  11#include "qemu/osdep.h"
  12#include "qemu-common.h"
  13#include "cpu.h"
  14#include "qapi/qmp/qerror.h"
  15#include "qapi/qmp/qjson.h"
  16#include "qapi/qapi-commands-ui.h"
  17#include "qapi/qapi-events-ui.h"
  18#include "qapi/qapi-events-injection.h"
  19#include "qapi/error.h"
  20#include "qapi/qapi-types-injection.h"
  21#include "qapi/qapi-commands-injection.h"
  22#include "qemu/timer.h"
  23#include "exec/memory.h"
  24#include "hw/irq.h"
  25#include "qemu/log.h"
  26#include "qemu/queue.h"
  27#include "sysemu/sysemu.h"
  28#include "sysemu/runstate.h"
  29#include "exec/exec-all.h"
  30
  31typedef struct FaultEventEntry FaultEventEntry;
  32static QLIST_HEAD(, FaultEventEntry) events = QLIST_HEAD_INITIALIZER(events);
  33static QEMUTimer *timer;
  34
  35#ifndef DEBUG_FAULT_INJECTION
  36#define DEBUG_FAULT_INJECTION 0
  37#endif
  38
  39#define DPRINTF(fmt, ...) do {                                                 \
  40    if (DEBUG_FAULT_INJECTION) {                                               \
  41        qemu_log("fault_injection: " fmt , ## __VA_ARGS__);                    \
  42    }                                                                          \
  43} while (0);
  44
  45void qmp_write_mem(int64_t addr, int64_t val, int64_t size, bool has_cpu,
  46                   int64_t cpu, bool has_qom, const char *qom, bool debug,
  47                   Error **errp)
  48{
  49    int cpu_id = 0;
  50    Object *obj;
  51    CPUState *s;
  52    MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
  53
  54    attrs.debug = debug;
  55    if (has_qom) {
  56        obj = object_resolve_path(qom, NULL);
  57        s = (CPUState *)object_dynamic_cast(obj, TYPE_CPU);
  58        if (s) {
  59            cpu_id = s->cpu_index;
  60            DPRINTF("write memory addr=0x%" PRIx64 " val=0x%" PRIx64
  61                    " ld size=%"PRId64" cpu_path=%s (cpu=%d)\n", addr, val,
  62                    size, qom, cpu_id);
  63        } else {
  64            error_setg(errp, "'%s' is not a CPU or doesn't exists", qom);
  65            DPRINTF("write memory failed.\n");
  66            return;
  67        }
  68    } else {
  69        if (has_cpu) {
  70            cpu_id = cpu;
  71        }
  72        DPRINTF("write memory addr=0x%" PRIx64 "val=0x%" PRIx64 " "
  73                "size=%"PRId64" cpu=%d\n", addr, val, size, cpu_id);
  74    }
  75
  76    if (address_space_write(cpu_get_address_space(qemu_get_cpu(cpu_id), 0),
  77                            addr, attrs, ((uint8_t *)&val), size)) {
  78        DPRINTF("write memory failed.\n");
  79    } else {
  80        DPRINTF("write memory succeed.\n");
  81    }
  82}
  83
  84ReadValue *qmp_read_mem(int64_t addr, int64_t size, bool has_cpu, int64_t cpu,
  85                     bool has_qom, const char *qom, Error **errp)
  86{
  87    ReadValue *ret = g_new0(ReadValue, 1);
  88    int cpu_id = 0;
  89    Object *obj;
  90    CPUState *s;
  91
  92    ret->value = 0;
  93
  94    if (has_qom) {
  95        obj = object_resolve_path(qom, NULL);
  96        s = (CPUState *)object_dynamic_cast(obj, TYPE_CPU);
  97        if (s) {
  98            cpu_id = s->cpu_index;
  99            DPRINTF("read memory addr=0x%" PRIx64 " size=%"PRId64" cpu_path=%s"
 100                    " (cpu=%d)\n", addr, size, qom, cpu_id);
 101        } else {
 102            error_setg(errp, "'%s' is not a CPU or doesn't exists", qom);
 103            DPRINTF("read memory failed.\n");
 104            return ret;
 105        }
 106    } else {
 107        if (has_cpu) {
 108            cpu_id = cpu;
 109        }
 110        DPRINTF("read memory addr=0x%" PRIx64 " size=%"PRId64" (cpu=%d)\n",
 111                addr, size, cpu_id);
 112    }
 113
 114    if (address_space_read(cpu_get_address_space(qemu_get_cpu(cpu_id), 0), addr,
 115                           MEMTXATTRS_UNSPECIFIED, (uint8_t *) &(ret->value), size)) {
 116        DPRINTF("read memory failed.\n");
 117        return ret;
 118    } else {
 119        DPRINTF("read memory succeed 0x%" PRIx64 ".\n", ret->value);
 120        return ret;
 121    }
 122}
 123
 124struct FaultEventEntry {
 125    uint64_t time_ns;
 126    int64_t val;
 127    QLIST_ENTRY(FaultEventEntry) node;
 128};
 129
 130static void mod_next_event_timer(void)
 131{
 132    uint64_t val;
 133    FaultEventEntry *entry;
 134
 135    if (QLIST_EMPTY(&events)) {
 136        return;
 137    } else {
 138        val = QLIST_FIRST(&events)->time_ns;
 139    }
 140
 141    QLIST_FOREACH(entry, &events, node) {
 142        if (val > entry->time_ns) {
 143            val = entry->time_ns;
 144        }
 145    }
 146
 147    timer_mod(timer, val);
 148}
 149
 150static void do_fault(void *opaque)
 151{
 152    FaultEventEntry *entry;
 153    FaultEventEntry *next;
 154    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 155
 156    QLIST_FOREACH_SAFE(entry, &events, node, next) {
 157        if (entry->time_ns < current_time) {
 158            DPRINTF("fault %"PRId64" happened @%"PRId64"!\n", entry->val,
 159                    qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
 160            qapi_event_send_fault_event(entry->val, current_time);
 161            QLIST_REMOVE(entry, node);
 162            g_free(entry);
 163            vm_stop_from_timer(RUN_STATE_DEBUG);
 164        }
 165    }
 166
 167    mod_next_event_timer();
 168}
 169
 170void qmp_trigger_event(int64_t time_ns, int64_t event_id, Error **errp)
 171{
 172    FaultEventEntry *entry;
 173
 174    DPRINTF("trigger_event(%"PRId64", %"PRId64")\n", time_ns, event_id);
 175
 176    entry = g_new0(FaultEventEntry, 1);
 177    entry->time_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time_ns;
 178    entry->val = event_id;
 179    QLIST_INSERT_HEAD(&events, entry, node);
 180
 181    if (!timer) {
 182        timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, do_fault, NULL);
 183    }
 184
 185    mod_next_event_timer();
 186}
 187
 188void qmp_inject_gpio(const char *device_name, bool has_gpio, const char *gpio,
 189                     int64_t num, int64_t val, Error **errp)
 190{
 191    DeviceState *dev;
 192    qemu_irq irq;
 193
 194    dev = DEVICE(object_resolve_path(device_name, NULL));
 195    if (!dev) {
 196        error_setg(errp, "Device '%s' is not a device", device_name);
 197        return;
 198    }
 199
 200    irq = qdev_get_gpio_in_named(dev, has_gpio ? gpio : NULL, num);
 201    if (!irq) {
 202        error_setg(errp, "GPIO '%s' doesn't exists", has_gpio ? gpio : "unnammed");
 203        return;
 204    }
 205
 206    DPRINTF("inject gpio device %s, gpio %s, num %" PRId64 ", val %" PRIx64
 207            "\n", device_name, gpio, num, val);
 208
 209    qemu_set_irq(irq, val);
 210}
 211