target/riscv: Add RISC-V CSR qtest support

The RISC-V architecture supports the creation of custom
CSR-mapped devices. It would be convenient to test them in the same way
as MMIO-mapped devices. To do this, a new call has been added
to read/write CSR registers.

Signed-off-by: Ivan Klokov <ivan.klokov@syntacore.com>
Acked-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
Ivan Klokov 2025-01-09 12:10:43 +03:00 committed by Fabiano Rosas
parent 4d5d933bbc
commit 1addf57177
3 changed files with 96 additions and 0 deletions

View file

@ -22,6 +22,8 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "system/reset.h"
#include "system/qtest.h"
#include "qemu/cutils.h"
#include "hw/sysbus.h"
#include "target/riscv/cpu.h"
#include "hw/qdev-properties.h"
@ -41,6 +43,55 @@ static void riscv_harts_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
}
#ifndef CONFIG_USER_ONLY
static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val)
{
RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(cpu_num));
CPURISCVState *env = &cpu->env;
int ret = RISCV_EXCP_NONE;
if (strcmp(cmd, "get_csr") == 0) {
ret = riscv_csrr(env, csrno, (target_ulong *)val);
} else if (strcmp(cmd, "set_csr") == 0) {
ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val,
MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
}
g_assert(ret == RISCV_EXCP_NONE);
}
static bool csr_qtest_callback(CharBackend *chr, gchar **words)
{
if (strcmp(words[0], "csr") == 0) {
uint64_t cpu;
uint64_t val;
int rc, csr;
rc = qemu_strtou64(words[2], NULL, 0, &cpu);
g_assert(rc == 0);
rc = qemu_strtoi(words[3], NULL, 0, &csr);
g_assert(rc == 0);
rc = qemu_strtou64(words[4], NULL, 0, &val);
g_assert(rc == 0);
csr_call(words[1], cpu, csr, &val);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK 0 "TARGET_FMT_lx"\n", (target_ulong)val);
return true;
}
return false;
}
static void riscv_cpu_register_csr_qtest_callback(void)
{
static GOnce once;
g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback);
}
#endif
static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
char *cpu_type, Error **errp)
{
@ -58,6 +109,10 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp)
s->harts = g_new0(RISCVCPU, s->num_harts);
#ifndef CONFIG_USER_ONLY
riscv_cpu_register_csr_qtest_callback();
#endif
for (n = 0; n < s->num_harts; n++) {
if (!riscv_hart_realize(s, n, s->cpu_type, errp)) {
return;

View file

@ -1218,6 +1218,33 @@ uint64_t qtest_rtas_call(QTestState *s, const char *name,
return 0;
}
static void qtest_rsp_csr(QTestState *s, uint64_t *val)
{
gchar **args;
uint64_t ret;
int rc;
args = qtest_rsp_args(s, 3);
rc = qemu_strtou64(args[1], NULL, 16, &ret);
g_assert(rc == 0);
rc = qemu_strtou64(args[2], NULL, 16, val);
g_assert(rc == 0);
g_strfreev(args);
}
uint64_t qtest_csr_call(QTestState *s, const char *name,
uint64_t cpu, int csr,
uint64_t *val)
{
qtest_sendf(s, "csr %s 0x%"PRIx64" %d 0x%"PRIx64"\n",
name, cpu, csr, *val);
qtest_rsp_csr(s, val);
return 0;
}
void qtest_add_func(const char *str, void (*fn)(void))
{
gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);

View file

@ -600,6 +600,20 @@ uint64_t qtest_rtas_call(QTestState *s, const char *name,
uint32_t nargs, uint64_t args,
uint32_t nret, uint64_t ret);
/**
* qtest_csr_call:
* @s: #QTestState instance to operate on.
* @name: name of the command to call.
* @cpu: hart number.
* @csr: CSR number.
* @val: Value for reading/writing.
*
* Call an RISC-V CSR read/write function
*/
uint64_t qtest_csr_call(QTestState *s, const char *name,
uint64_t cpu, int csr,
uint64_t *val);
/**
* qtest_bufread:
* @s: #QTestState instance to operate on.