aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/api.c135
-rw-r--r--plugins/core.c33
2 files changed, 166 insertions, 2 deletions
diff --git a/plugins/api.c b/plugins/api.c
index 3c9d483..eac04cc 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -39,6 +39,7 @@
#include "qemu/main-loop.h"
#include "qemu/plugin.h"
#include "qemu/log.h"
+#include "system/memory.h"
#include "tcg/tcg.h"
#include "exec/gdbstub.h"
#include "exec/target_page.h"
@@ -433,6 +434,29 @@ GArray *qemu_plugin_get_registers(void)
return create_register_handles(regs);
}
+int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
+{
+ g_assert(current_cpu);
+
+ if (qemu_plugin_get_cb_flags() == QEMU_PLUGIN_CB_NO_REGS) {
+ return -1;
+ }
+
+ return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
+}
+
+int qemu_plugin_write_register(struct qemu_plugin_register *reg,
+ GByteArray *buf)
+{
+ g_assert(current_cpu);
+
+ if (buf->len == 0 || qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS) {
+ return -1;
+ }
+
+ return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1);
+}
+
bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len)
{
g_assert(current_cpu);
@@ -453,11 +477,118 @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len)
return true;
}
-int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
+bool qemu_plugin_write_memory_vaddr(uint64_t addr, GByteArray *data)
{
g_assert(current_cpu);
- return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
+ if (data->len == 0) {
+ return false;
+ }
+
+ int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
+ data->len, true);
+
+ if (result < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+enum qemu_plugin_hwaddr_operation_result
+qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len)
+{
+#ifdef CONFIG_SOFTMMU
+ if (len == 0) {
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+ }
+
+ g_assert(current_cpu);
+
+
+ int as_idx = cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIED);
+ AddressSpace *as = cpu_get_address_space(current_cpu, as_idx);
+
+ if (as == NULL) {
+ return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE;
+ }
+
+ g_byte_array_set_size(data, len);
+ MemTxResult res = address_space_rw(as, addr,
+ MEMTXATTRS_UNSPECIFIED, data->data,
+ data->len, false);
+
+ switch (res) {
+ case MEMTX_OK:
+ return QEMU_PLUGIN_HWADDR_OPERATION_OK;
+ case MEMTX_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR;
+ case MEMTX_DECODE_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS;
+ case MEMTX_ACCESS_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED;
+ default:
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+ }
+#else
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+#endif
+}
+
+enum qemu_plugin_hwaddr_operation_result
+qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data)
+{
+#ifdef CONFIG_SOFTMMU
+ if (data->len == 0) {
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+ }
+
+ g_assert(current_cpu);
+
+ int as_idx = cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIED);
+ AddressSpace *as = cpu_get_address_space(current_cpu, as_idx);
+
+ if (as == NULL) {
+ return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE;
+ }
+
+ MemTxResult res = address_space_rw(as, addr,
+ MEMTXATTRS_UNSPECIFIED, data->data,
+ data->len, true);
+ switch (res) {
+ case MEMTX_OK:
+ return QEMU_PLUGIN_HWADDR_OPERATION_OK;
+ case MEMTX_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR;
+ case MEMTX_DECODE_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS;
+ case MEMTX_ACCESS_ERROR:
+ return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED;
+ default:
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+ }
+#else
+ return QEMU_PLUGIN_HWADDR_OPERATION_ERROR;
+#endif
+}
+
+bool qemu_plugin_translate_vaddr(uint64_t vaddr, uint64_t *hwaddr)
+{
+#ifdef CONFIG_SOFTMMU
+ g_assert(current_cpu);
+
+ uint64_t res = cpu_get_phys_page_debug(current_cpu, vaddr);
+
+ if (res == (uint64_t)-1) {
+ return false;
+ }
+
+ *hwaddr = res | (vaddr & ~TARGET_PAGE_MASK);
+
+ return true;
+#else
+ return false;
+#endif
}
struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
diff --git a/plugins/core.c b/plugins/core.c
index eb9281f..c6e9ef1 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -15,6 +15,7 @@
#include "qemu/lockable.h"
#include "qemu/option.h"
#include "qemu/plugin.h"
+#include "qemu/qemu-plugin.h"
#include "qemu/queue.h"
#include "qemu/rcu_queue.h"
#include "qemu/rcu.h"
@@ -266,7 +267,9 @@ static void qemu_plugin_vcpu_init__async(CPUState *cpu, run_on_cpu_data unused)
plugin_grow_scoreboards__locked(cpu);
qemu_rec_mutex_unlock(&plugin.lock);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
void qemu_plugin_vcpu_init_hook(CPUState *cpu)
@@ -279,7 +282,9 @@ void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
{
bool success;
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXIT);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
qemu_rec_mutex_lock(&plugin.lock);
@@ -367,6 +372,7 @@ void plugin_register_dyn_cb__udata(GArray **arr,
static TCGHelperInfo info[3] = {
[QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
[QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
+ [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
/*
* Match qemu_plugin_vcpu_udata_cb_t:
* void (*)(uint32_t, void *)
@@ -396,6 +402,7 @@ void plugin_register_dyn_cond_cb__udata(GArray **arr,
static TCGHelperInfo info[3] = {
[QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
[QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
+ [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
/*
* Match qemu_plugin_vcpu_udata_cb_t:
* void (*)(uint32_t, void *)
@@ -434,6 +441,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
static TCGHelperInfo info[3] = {
[QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
[QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
+ [QEMU_PLUGIN_CB_RW_REGS].flags = 0,
/*
* Match qemu_plugin_vcpu_mem_cb_t:
* void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
@@ -473,7 +481,9 @@ void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb)
QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
qemu_plugin_vcpu_tb_trans_cb_t func = cb->f.vcpu_tb_trans;
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
func(cb->ctx->id, tb);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
}
@@ -498,7 +508,9 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall;
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
}
@@ -520,7 +532,9 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret;
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
func(cb->ctx->id, cpu->cpu_index, num, ret);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
}
@@ -528,14 +542,18 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
{
/* idle and resume cb may be called before init, ignore in this case */
if (cpu->cpu_index < plugin.num_vcpus) {
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
}
void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
{
if (cpu->cpu_index < plugin.num_vcpus) {
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
}
@@ -615,9 +633,13 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
switch (cb->type) {
case PLUGIN_CB_MEM_REGULAR:
if (rw & cb->regular.rw) {
+ qemu_plugin_set_cb_flags(cpu,
+ tcg_call_to_qemu_plugin_cb_flags(cb->regular.info->flags));
+
cb->regular.f.vcpu_mem(cpu->cpu_index,
make_plugin_meminfo(oi, rw),
vaddr, cb->regular.userp);
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
}
break;
case PLUGIN_CB_INLINE_ADD_U64:
@@ -760,3 +782,14 @@ void plugin_scoreboard_free(struct qemu_plugin_scoreboard *score)
g_array_free(score->data, TRUE);
g_free(score);
}
+
+enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags)
+{
+ if (flags & TCG_CALL_NO_RWG) {
+ return QEMU_PLUGIN_CB_NO_REGS;
+ } else if (flags & TCG_CALL_NO_WG) {
+ return QEMU_PLUGIN_CB_R_REGS;
+ } else {
+ return QEMU_PLUGIN_CB_RW_REGS;
+ }
+}