plugins: Add memory hardware address read/write API

This patch adds functions to the plugins API to allow plugins to read
and write memory via hardware addresses. The functions use the current
address space of the current CPU in order to avoid exposing address
space information to users. A later patch may want to add a function to
permit a specified address space, for example to facilitate
architecture-specific plugins that want to operate on them, for example
reading ARM secure memory.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
Message-ID: <20250624175351.440780-6-rowanbhart@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250627112512.1880708-10-alex.bennee@linaro.org>
This commit is contained in:
Rowan Hart 2025-06-27 12:25:05 +01:00 committed by Alex Bennée
parent f00373b895
commit 30424b8d42
2 changed files with 190 additions and 0 deletions

View file

@ -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"
@ -494,6 +495,102 @@ bool qemu_plugin_write_memory_vaddr(uint64_t addr, GByteArray *data)
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)
{
return plugin_scoreboard_new(element_size);