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 "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