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