diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/api.c | 135 | ||||
-rw-r--r-- | plugins/core.c | 33 |
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; + } +} |