1
2
3
4
5
6
7
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