Qtest pull request

- RISCV CSR test
 - migration recover changed to OOB
 - removal of dead code in test-x86-cpuid-compat
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEqhtIsKIjJqWkw2TPx5jcdBvsMZ0FAmeKbx4QHGZhcm9zYXNA
 c3VzZS5kZQAKCRDHmNx0G+wxnRD7D/9v4ovvGn/IwSXjjpOpkjhCSgV8TMi1F61P
 hqB5TTCY8yejvT7JauplMUHmcJsVCNx+HF36D+YjxBjqrhQE8vzPRXgcLxHL9RX4
 Kwgdk24kFKADE3gsiys9gOpwRhmtY0/2CT5LvitfJRMxUNPtm0Mr7qM3Z0Taeusu
 lxZgIMTBeNakpY5vua8nlLQ4r+/Df6S3TFFAaQ4UYab/T5zHVcjKaySXDlT1QXpp
 M+Be21jPxuUYJnKCSxMCUtuY9wkSPcITzJW91V+JxL9STSpsKpnQe10JWDRbwLBt
 /am2Jg5f8iFEblCwr5aQRMwXB+e/Y7K4qKPOUalj+weGnCXh9DmWPXnV6qzdZNO8
 sePKoFj1AMtqbVf3iOpDBRkH8dECiDh1jHmflW1grF0BuOwOw8dKYW+i2qz9ZDiW
 rKWKfRcZZ059aOCQWqpMC9TGQ8osMC/v6GGJwiPBDLapGjnAm5d1683w4Z1l8tAg
 vf9yti2mpzK15PB6doEj/IuZr8WKWFMklizmMMZpXgHIUpjtm3JFKXX/jGHcD3KU
 E8F4ns3zPMlq7ncIwc6GADRB3XzEuzzuXAaEO8HMN0fYHevfnFIon749udyBDI/n
 a1/CTzTmchItwzgpdvcoiKO6gkg6DO9n08QULCMPSVCtl5KAlz5yuwxWGI/rM6u7
 ixPi8i24oA==
 =i4AD
 -----END PGP SIGNATURE-----

Merge tag 'qtest-20250117-pull-request' of https://gitlab.com/farosas/qemu into staging

Qtest pull request

- RISCV CSR test
- migration recover changed to OOB
- removal of dead code in test-x86-cpuid-compat

# -----BEGIN PGP SIGNATURE-----
#
# iQJEBAABCAAuFiEEqhtIsKIjJqWkw2TPx5jcdBvsMZ0FAmeKbx4QHGZhcm9zYXNA
# c3VzZS5kZQAKCRDHmNx0G+wxnRD7D/9v4ovvGn/IwSXjjpOpkjhCSgV8TMi1F61P
# hqB5TTCY8yejvT7JauplMUHmcJsVCNx+HF36D+YjxBjqrhQE8vzPRXgcLxHL9RX4
# Kwgdk24kFKADE3gsiys9gOpwRhmtY0/2CT5LvitfJRMxUNPtm0Mr7qM3Z0Taeusu
# lxZgIMTBeNakpY5vua8nlLQ4r+/Df6S3TFFAaQ4UYab/T5zHVcjKaySXDlT1QXpp
# M+Be21jPxuUYJnKCSxMCUtuY9wkSPcITzJW91V+JxL9STSpsKpnQe10JWDRbwLBt
# /am2Jg5f8iFEblCwr5aQRMwXB+e/Y7K4qKPOUalj+weGnCXh9DmWPXnV6qzdZNO8
# sePKoFj1AMtqbVf3iOpDBRkH8dECiDh1jHmflW1grF0BuOwOw8dKYW+i2qz9ZDiW
# rKWKfRcZZ059aOCQWqpMC9TGQ8osMC/v6GGJwiPBDLapGjnAm5d1683w4Z1l8tAg
# vf9yti2mpzK15PB6doEj/IuZr8WKWFMklizmMMZpXgHIUpjtm3JFKXX/jGHcD3KU
# E8F4ns3zPMlq7ncIwc6GADRB3XzEuzzuXAaEO8HMN0fYHevfnFIon749udyBDI/n
# a1/CTzTmchItwzgpdvcoiKO6gkg6DO9n08QULCMPSVCtl5KAlz5yuwxWGI/rM6u7
# ixPi8i24oA==
# =i4AD
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 17 Jan 2025 09:54:22 EST
# gpg:                using RSA key AA1B48B0A22326A5A4C364CFC798DC741BEC319D
# gpg:                issuer "farosas@suse.de"
# gpg: Good signature from "Fabiano Rosas <farosas@suse.de>" [unknown]
# gpg:                 aka "Fabiano Almeida Rosas <fabiano.rosas@suse.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: AA1B 48B0 A223 26A5 A4C3  64CF C798 DC74 1BEC 319D

* tag 'qtest-20250117-pull-request' of https://gitlab.com/farosas/qemu:
  tests/qtest/test-x86-cpuid-compat: Remove tests related to pc-i440fx-2.3
  tests/qtest/migration: Use out-of-band execution for migrate-recover
  tests/qtest: Introduce qtest_init_with_env_and_capabilities()
  tests/qtest: QTest example for RISC-V CSR register
  target/riscv: Add RISC-V CSR qtest support

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-01-18 18:37:16 -05:00
commit 20fac491cf
9 changed files with 210 additions and 24 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

@ -543,7 +543,9 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
return qtest_init_internal(qtest_qemu_binary(NULL), extra_args);
}
QTestState *qtest_init_with_env(const char *var, const char *extra_args)
QTestState *qtest_init_with_env_and_capabilities(const char *var,
const char *extra_args,
QList *capabilities)
{
QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args);
QDict *greeting;
@ -551,11 +553,23 @@ QTestState *qtest_init_with_env(const char *var, const char *extra_args)
/* Read the QMP greeting and then do the handshake */
greeting = qtest_qmp_receive(s);
qobject_unref(greeting);
qobject_unref(qtest_qmp(s, "{ 'execute': 'qmp_capabilities' }"));
if (capabilities) {
qtest_qmp_assert_success(s,
"{ 'execute': 'qmp_capabilities', "
"'arguments': { 'enable': %p } }",
qobject_ref(capabilities));
} else {
qtest_qmp_assert_success(s, "{ 'execute': 'qmp_capabilities' }");
}
return s;
}
QTestState *qtest_init_with_env(const char *var, const char *extra_args)
{
return qtest_init_with_env_and_capabilities(var, extra_args, NULL);
}
QTestState *qtest_init(const char *extra_args)
{
return qtest_init_with_env(NULL, extra_args);
@ -1218,6 +1232,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

@ -19,6 +19,7 @@
#include "qapi/qmp/qobject.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
#include "libqmp.h"
typedef struct QTestState QTestState;
@ -68,6 +69,22 @@ QTestState *qtest_init(const char *extra_args);
*/
QTestState *qtest_init_with_env(const char *var, const char *extra_args);
/**
* qtest_init_with_env_and_capabilities:
* @var: Environment variable from where to take the QEMU binary
* @extra_args: Other arguments to pass to QEMU. CAUTION: these
* arguments are subject to word splitting and shell evaluation.
* @capabilities: list of QMP capabilities (strings) to enable
*
* Like qtest_init_with_env(), but enable specified capabilities during
* hadshake.
*
* Returns: #QTestState instance.
*/
QTestState *qtest_init_with_env_and_capabilities(const char *var,
const char *extra_args,
QList *capabilities);
/**
* qtest_init_without_qmp_handshake:
* @extra_args: other arguments to pass to QEMU. CAUTION: these
@ -600,6 +617,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.

View file

@ -274,7 +274,7 @@ qtests_s390x = \
qtests_riscv32 = \
(config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])
qtests_riscv64 = \
qtests_riscv64 = ['riscv-csr-test'] + \
(unpack_edk2_blobs ? ['bios-tables-test'] : [])
qos_test_ss = ss.source_set()

View file

@ -194,6 +194,16 @@ static void cleanup(const char *filename)
unlink(path);
}
static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args)
{
QList *capabilities = qlist_new();
if (args->oob) {
qlist_append_str(capabilities, "oob");
}
return capabilities;
}
int migrate_start(QTestState **from, QTestState **to, const char *uri,
MigrateStart *args)
{
@ -210,6 +220,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
const char *machine_alias, *machine_opts = "";
g_autofree char *machine = NULL;
const char *bootpath;
g_autoptr(QList) capabilities = migrate_start_get_qmp_capabilities(args);
if (args->use_shmem) {
if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
@ -314,7 +325,8 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
args->opts_source ? args->opts_source : "",
ignore_stderr);
if (!args->only_target) {
*from = qtest_init_with_env(QEMU_ENV_SRC, cmd_source);
*from = qtest_init_with_env_and_capabilities(QEMU_ENV_SRC, cmd_source,
capabilities);
qtest_qmp_set_event_callback(*from,
migrate_watch_for_events,
&src_state);
@ -334,7 +346,8 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri,
shmem_opts ? shmem_opts : "",
args->opts_target ? args->opts_target : "",
ignore_stderr);
*to = qtest_init_with_env(QEMU_ENV_DST, cmd_target);
*to = qtest_init_with_env_and_capabilities(QEMU_ENV_DST, cmd_target,
capabilities);
qtest_qmp_set_event_callback(*to,
migrate_watch_for_events,
&dst_state);
@ -601,6 +614,12 @@ void test_postcopy_recovery_common(MigrateCommon *args)
QTestState *from, *to;
g_autofree char *uri = NULL;
/*
* Always enable OOB QMP capability for recovery tests, migrate-recover is
* executed out-of-band
*/
args->start.oob = true;
/* Always hide errors for postcopy recover tests since they're expected */
args->start.hide_stderr = true;

View file

@ -109,6 +109,8 @@ typedef struct {
const char *opts_target;
/* suspend the src before migrating to dest. */
bool suspend_me;
/* enable OOB QMP capability */
bool oob;
} MigrateStart;
typedef enum PostcopyRecoveryFailStage {

View file

@ -464,7 +464,7 @@ void migrate_continue(QTestState *who, const char *state)
void migrate_recover(QTestState *who, const char *uri)
{
qtest_qmp_assert_success(who,
"{ 'execute': 'migrate-recover', "
"{ 'exec-oob': 'migrate-recover', "
" 'id': 'recover-cmd', "
" 'arguments': { 'uri': %s } }",
uri);

View file

@ -0,0 +1,56 @@
/*
* QTest testcase for RISC-V CSRs
*
* Copyright (c) 2024 Syntacore.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#define CSR_MVENDORID 0xf11
#define CSR_MISELECT 0x350
static void run_test_csr(void)
{
uint64_t res;
uint64_t val = 0;
QTestState *qts = qtest_init("-machine virt -cpu veyron-v1");
res = qtest_csr_call(qts, "get_csr", 0, CSR_MVENDORID, &val);
g_assert_cmpint(res, ==, 0);
g_assert_cmpint(val, ==, 0x61f);
val = 0xff;
res = qtest_csr_call(qts, "set_csr", 0, CSR_MISELECT, &val);
g_assert_cmpint(res, ==, 0);
val = 0;
res = qtest_csr_call(qts, "get_csr", 0, CSR_MISELECT, &val);
g_assert_cmpint(res, ==, 0);
g_assert_cmpint(val, ==, 0xff);
qtest_quit(qts);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
qtest_add_func("/cpu/csr", run_test_csr);
return g_test_run();
}

View file

@ -357,19 +357,6 @@ int main(int argc, char **argv)
"486", "xstore=on", "pc-i440fx-2.7",
"xlevel2", 0);
}
/*
* QEMU 2.3.0 had auto-level enabled for CPUID[7], already,
* and the compat code that sets default level shouldn't
* disable the auto-level=7 code:
*/
if (qtest_has_machine("pc-i440fx-2.3")) {
add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/off",
"Penryn", NULL, "pc-i440fx-2.3",
"level", 4);
add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.3/on",
"Penryn", "erms=on", "pc-i440fx-2.3",
"level", 7);
}
if (qtest_has_machine("pc-i440fx-2.9")) {
add_cpuid_test("x86/cpuid/auto-level7/pc-i440fx-2.9/off",
"Conroe", NULL, "pc-i440fx-2.9",
@ -384,11 +371,6 @@ int main(int argc, char **argv)
* code on old machine-types. Just check that the compat code
* is working correctly:
*/
if (qtest_has_machine("pc-i440fx-2.3")) {
add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.3",
"SandyBridge", NULL, "pc-i440fx-2.3",
"xlevel", 0x8000000a);
}
if (qtest_has_machine("pc-i440fx-2.4")) {
add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off",
"SandyBridge", NULL, "pc-i440fx-2.4",