From nobody Tue Apr  8 12:47:17 2025
Delivered-To: importer@patchew.org
Authentication-Results: mx.zohomail.com;
	spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as
 permitted sender)
  smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org
Return-Path: <qemu-devel-bounces+importer=patchew.org@nongnu.org>
Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by
 mx.zohomail.com
	with SMTPS id 1741619920847258.4746233099652;
 Mon, 10 Mar 2025 08:18:40 -0700 (PDT)
Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <qemu-devel-bounces@nongnu.org>)
	id 1trenW-0002GM-Ea; Mon, 10 Mar 2025 11:12:06 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mario.fleischmann@lauterbach.com>)
 id 1tren3-00026Z-Qo
 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400
Received: from smtp1.lauterbach.com ([62.154.241.196])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <mario.fleischmann@lauterbach.com>)
 id 1tremy-0007hx-Do
 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400
Received: (qmail 30868 invoked by uid 484); 10 Mar 2025 15:11:12 -0000
Received: from unknown (HELO mflpc1.LTB.LAN)
 (Authenticated_SSL:mfleischmann@[10.2.13.100])
 (envelope-sender <mario.fleischmann@lauterbach.com>)
 by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384
 encrypted SMTP
 for <qemu-devel@nongnu.org>; 10 Mar 2025 15:11:12 -0000
X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com
 (envelope-from <mario.fleischmann@lauterbach.com>,
 uid 484) with qmail-scanner-2.11
 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0.  
 Clear:RC:1(10.2.13.100):.
 Processed in 0.012867 secs); 10 Mar 2025 15:11:12 -0000
From: Mario Fleischmann <mario.fleischmann@lauterbach.com>
To: qemu-devel@nongnu.org
Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com,
 christian.boenig@lauterbach.com,
 Mario Fleischmann <mario.fleischmann@lauterbach.com>,
 Eric Blake <eblake@redhat.com>, Fabiano Rosas <farosas@suse.de>,
 Laurent Vivier <lvivier@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
Subject: [PATCH 11/16] mcd test: Implement core state query
Date: Mon, 10 Mar 2025 16:05:05 +0100
Message-Id: <20250310150510.200607-12-mario.fleischmann@lauterbach.com>
X-Mailer: git-send-email 2.34.1
In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com>
References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com>
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
X-Qmail-Scanner-2.11: added fake Content-Type header
Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17
 as permitted sender) client-ip=209.51.188.17;
 envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org;
 helo=lists.gnu.org;
Received-SPF: pass client-ip=62.154.241.196;
 envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9,
 RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,
 SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-BeenThere: qemu-devel@nongnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: <qemu-devel.nongnu.org>
List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>
List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel>
List-Post: <mailto:qemu-devel@nongnu.org>
List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help>
List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>,
 <mailto:qemu-devel-request@nongnu.org?subject=subscribe>
Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org
Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org
X-ZM-MESSAGEID: 1741619923710019100
Content-Type: text/plain; charset="utf-8"

Depending on the VM and CPU state, core states can be queried:

* MCD_CORE_STATE_DEBUG:   VM halted or CPU artifically stopped
* MCD_CORE_STATE_RUNNING: VM and CPU running
* MCD_CORE_STATE_HALTED:  CPU suspended

Signed-off-by: Mario Fleischmann <mario.fleischmann@lauterbach.com>
---
 mcd/libmcd_qapi.c         |  16 +++++
 mcd/libmcd_qapi.h         |   2 +
 mcd/mcdserver.c           |  48 ++++++++++++++-
 mcd/mcdstub_qapi.c        |  21 +++++++
 qapi/mcd.json             |  55 +++++++++++++++++
 tests/qtest/libmcd-test.c |  59 +++++++++++++++++++
 tests/qtest/libmcd-test.h |   9 +++
 tests/qtest/mcd-test.c    | 120 +++++++++++++++++++++++++++++++++++++-
 8 files changed, 328 insertions(+), 2 deletions(-)

diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c
index 99177b2fd2..44fc9bd6b4 100644
--- a/mcd/libmcd_qapi.c
+++ b/mcd/libmcd_qapi.c
@@ -195,3 +195,19 @@ MCDRegisterInfo *marshal_mcd_register_info(const mcd_r=
egister_info_st *reg_info)
=20
     return marshal;
 }
+
+MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state)
+{
+    MCDCoreState *marshal =3D g_malloc0(sizeof(*marshal));
+
+    *marshal =3D (MCDCoreState) {
+        .state =3D state->state,
+        .event =3D state->event,
+        .hw_thread_id =3D state->hw_thread_id,
+        .trig_id =3D state->trig_id,
+        .stop_str =3D g_strdup(state->stop_str),
+        .info_str =3D g_strdup(state->info_str),
+    };
+
+    return marshal;
+}
diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h
index edcc6d0b7c..7d68d60f02 100644
--- a/mcd/libmcd_qapi.h
+++ b/mcd/libmcd_qapi.h
@@ -35,6 +35,8 @@ MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr);
 MCDRegisterInfo *marshal_mcd_register_info(
     const mcd_register_info_st *reg_info);
=20
+MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state);
+
 mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version);
=20
 mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info);
diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c
index 9e46ea5fa5..116fbfaa30 100644
--- a/mcd/mcdserver.c
+++ b/mcd/mcdserver.c
@@ -16,6 +16,7 @@
 #include "exec/gdbstub.h"
 #include "hw/core/cpu.h"
 #include "system/runstate.h"
+#include "system/hw_accel.h"
=20
 /* Custom memory space type */
 static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE =3D 0x00010000;
@@ -1192,7 +1193,52 @@ mcd_return_et mcd_set_global_f(const mcd_core_st *co=
re, bool enable)
=20
 mcd_return_et mcd_qry_state_f(const mcd_core_st *core, mcd_core_state_st *=
state)
 {
-    g_server_state.last_error =3D &MCD_ERROR_NOT_IMPLEMENTED;
+    mcdcore_state *core_state;
+    RunState rs;
+
+    if (!core || !state) {
+        g_server_state.last_error =3D &MCD_ERROR_INVALID_NULL_PARAM;
+        return g_server_state.last_error->return_status;
+    }
+
+    *state =3D (mcd_core_state_st) {
+        .stop_str =3D "",
+        .info_str =3D "",
+    };
+
+    core_state =3D find_core(core->core_con_info);
+    if (!core_state || core_state->open_core !=3D core) {
+        g_server_state.last_error =3D &MCD_ERROR_UNKNOWN_CORE;
+        return g_server_state.last_error->return_status;
+    }
+
+    cpu_synchronize_state(core_state->cpu);
+    rs =3D runstate_get();
+    switch (rs) {
+    case RUN_STATE_PRELAUNCH:
+    case RUN_STATE_DEBUG:
+    case RUN_STATE_PAUSED:
+        state->state =3D MCD_CORE_STATE_DEBUG;
+        pstrcpy(state->stop_str, MCD_INFO_STR_LEN, "RUN_STATE_PAUSED");
+        break;
+    case RUN_STATE_RUNNING:
+        if (core_state->cpu->running) {
+            state->state =3D MCD_CORE_STATE_RUNNING;
+        } else if (core_state->cpu->stopped) {
+            state->state =3D MCD_CORE_STATE_DEBUG;
+        } else if (core_state->cpu->halted) {
+            state->state =3D MCD_CORE_STATE_HALTED;
+            pstrcpy(state->info_str, MCD_INFO_STR_LEN, "halted");
+        } else {
+            state->state =3D MCD_CORE_STATE_UNKNOWN;
+        }
+        break;
+    default:
+        state->state =3D MCD_CORE_STATE_UNKNOWN;
+        break;
+    }
+
+    g_server_state.last_error =3D &MCD_ERROR_NONE;
     return g_server_state.last_error->return_status;
 }
=20
diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c
index 635f95181b..e1bde14b47 100644
--- a/mcd/mcdstub_qapi.c
+++ b/mcd/mcdstub_qapi.c
@@ -557,3 +557,24 @@ MCDSetGlobalResult *qmp_mcd_set_global(uint32_t core_u=
id, bool enable,
     g_stub_state.on_error_ask_server =3D true;
     return result;
 }
+
+MCDQryStateResult *qmp_mcd_qry_state(uint32_t core_uid, Error **errp)
+{
+    MCDQryStateResult *result =3D g_malloc0(sizeof(*result));
+    mcd_core_state_st state;
+    mcd_core_st *core =3D NULL;
+
+    result->return_status =3D retrieve_open_core(core_uid, &core);
+    if (result->return_status !=3D MCD_RET_ACT_NONE) {
+        g_stub_state.on_error_ask_server =3D false;
+        return result;
+    }
+
+    result->return_status =3D mcd_qry_state_f(core, &state);
+    if (result->return_status =3D=3D MCD_RET_ACT_NONE) {
+        result->state =3D marshal_mcd_core_state(&state);
+    }
+
+    g_stub_state.on_error_ask_server =3D true;
+    return result;
+}
diff --git a/qapi/mcd.json b/qapi/mcd.json
index c8b82e7f82..3560658451 100644
--- a/qapi/mcd.json
+++ b/qapi/mcd.json
@@ -307,6 +307,29 @@
     'hw-thread-id'        : 'uint32' } }
=20
=20
+##
+# @MCDCoreState:
+#
+# Structure type containing the state of a core.
+#
+# @state:        Core state.
+# @event:        Core events (OR'ed bitmask)
+# @hw-thread-id: ID of the hardware thread that caused the core to stop.
+# @trig-id:      ID of the trigger that caused the core to stop.
+# @stop-str:     Detailed description of a special stop reason.
+# @info-str:     Detailed description of the core state.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDCoreState',
+  'data': {
+    'state'       : 'uint32',
+    'event'       : 'uint32',
+    'hw-thread-id': 'uint32',
+    'trig-id'     : 'uint32',
+    'stop-str'    : 'str',
+    'info-str'    : 'str' } }
+
 ##
 # =3D=3D Target Initialization API
 ##
@@ -1473,3 +1496,35 @@
     'core-uid': 'uint32',
     'enable'  : 'bool' },
   'returns': 'MCDSetGlobalResult' }
+
+
+##
+# @MCDQryStateResult:
+#
+# Return value of @mcd-qry-state.
+#
+# @return-status: Return code.
+# @state:         The current execution state of the target core.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDQryStateResult',
+  'data': {
+    'return-status': 'uint32',
+    '*state': 'MCDCoreState' }}
+
+
+##
+# @mcd-qry-state:
+#
+# Function querying the execution state of a target core.
+#
+# @core-uid: Unique identifier of the open core as returned by @mcd-open-c=
ore.
+#
+# Returns: @MCDQryStateResult
+#
+# Since: 9.1
+##
+{ 'command': 'mcd-qry-state',
+  'data': { 'core-uid': 'uint32' },
+  'returns': 'MCDQryStateResult' }
diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c
index 82a39366b2..52f3ffcaa1 100644
--- a/tests/qtest/libmcd-test.c
+++ b/tests/qtest/libmcd-test.c
@@ -316,5 +316,64 @@ MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *=
qts,
=20
     UNMARSHAL_RESULT(MCDQryRegMapResult);
=20
+    return unmarshal;
+
+}
+
+MCDRunResult *qtest_mcd_run(QTestState *qts, q_obj_mcd_run_arg *args)
+{
+    Visitor *v;
+    QObject *marshal;
+    QDict *arg, *resp;
+    QObject *ret;
+    bool ok;
+    MCDRunResult *unmarshal;
+
+    MARSHAL_ARGS(q_obj_mcd_run_arg);
+
+    resp =3D qtest_qmp(qts, "{'execute': 'mcd-run',"
+                          "'arguments': %p}", arg);
+
+    UNMARSHAL_RESULT(MCDRunResult);
+
+    return unmarshal;
+}
+
+MCDStopResult *qtest_mcd_stop(QTestState *qts, q_obj_mcd_stop_arg *args)
+{
+    Visitor *v;
+    QObject *marshal;
+    QDict *arg, *resp;
+    QObject *ret;
+    bool ok;
+    MCDStopResult *unmarshal;
+
+    MARSHAL_ARGS(q_obj_mcd_stop_arg);
+
+    resp =3D qtest_qmp(qts, "{'execute': 'mcd-stop',"
+                          "'arguments': %p}", arg);
+
+    UNMARSHAL_RESULT(MCDStopResult);
+
+    return unmarshal;
+}
+
+MCDQryStateResult *qtest_mcd_qry_state(QTestState *qts,
+                                       q_obj_mcd_qry_state_arg *args)
+{
+    Visitor *v;
+    QObject *marshal;
+    QDict *arg, *resp;
+    QObject *ret;
+    bool ok;
+    MCDQryStateResult *unmarshal;
+
+    MARSHAL_ARGS(q_obj_mcd_qry_state_arg);
+
+    resp =3D qtest_qmp(qts, "{'execute': 'mcd-qry-state',"
+                          "'arguments': %p}", arg);
+
+    UNMARSHAL_RESULT(MCDQryStateResult);
+
     return unmarshal;
 }
diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h
index 266b6fe854..e45386847d 100644
--- a/tests/qtest/libmcd-test.h
+++ b/tests/qtest/libmcd-test.h
@@ -56,4 +56,13 @@ MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(QTestSta=
te *qts,
 MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts,
                                           q_obj_mcd_qry_reg_map_arg *args);
=20
+MCDRunResult *qtest_mcd_run(QTestState *qts,
+                            q_obj_mcd_run_arg *args);
+
+MCDStopResult *qtest_mcd_stop(QTestState *qts,
+                              q_obj_mcd_stop_arg *args);
+
+MCDQryStateResult *qtest_mcd_qry_state(QTestState *qts,
+                                       q_obj_mcd_qry_state_arg *args);
+
 #endif /* LIBMCD_TEST_H */
diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c
index 820408a9a9..9ab6b8e675 100644
--- a/tests/qtest/mcd-test.c
+++ b/tests/qtest/mcd-test.c
@@ -18,7 +18,7 @@
 #include "qapi/compat-policy.h"
 #include "libmcd-test.h"
=20
-#define QEMU_EXTRA_ARGS ""
+#define QEMU_EXTRA_ARGS "-accel tcg"
=20
 static bool verbose;
=20
@@ -87,6 +87,45 @@ static MCDQryCoresResult *open_server_query_cores(QTestS=
tate *qts)
     return qry_cores_result;
 }
=20
+static mcd_core_state_et check_core_state(QTestState *qts, uint32_t core_u=
id)
+{
+    mcd_core_state_et state;
+
+    q_obj_mcd_qry_state_arg qry_state_args =3D {
+        .core_uid =3D core_uid,
+    };
+
+    MCDQryStateResult *qry_state_result =3D qtest_mcd_qry_state(qts,
+                                                              &qry_state_a=
rgs);
+
+    g_assert(qry_state_result->return_status =3D=3D MCD_RET_ACT_NONE);
+    g_assert(qry_state_result->state);
+    state =3D qry_state_result->state->state;
+
+    if (verbose) {
+        fprintf(stderr, "[INFO]\tCore state: ");
+        switch (qry_state_result->state->state) {
+        case MCD_CORE_STATE_RUNNING:
+            fprintf(stderr, "running\n");
+            break;
+        case MCD_CORE_STATE_HALTED:
+            fprintf(stderr, "halted\n");
+            break;
+        case MCD_CORE_STATE_DEBUG:
+            fprintf(stderr, "debug\n");
+            break;
+        case MCD_CORE_STATE_UNKNOWN:
+            fprintf(stderr, "unknown\n");
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+    qapi_free_MCDQryStateResult(qry_state_result);
+    return state;
+}
+
 static void test_initialize(void)
 {
     QTestState *qts =3D qtest_init(QEMU_EXTRA_ARGS);
@@ -510,6 +549,84 @@ static void test_qry_core_info(void)
     qtest_quit(qts);
 }
=20
+static void test_go_stop(void)
+{
+    QTestState *qts =3D qtest_init(QEMU_EXTRA_ARGS);
+    mcd_core_state_et core_state;
+    MCDQryCoresResult *cores_query =3D open_server_query_cores(qts);
+
+    MCDCoreConInfoList *core_head =3D cores_query->core_con_info;
+    for (uint32_t c =3D 0; c < cores_query->num_cores; c++) {
+        q_obj_mcd_stop_arg stop_args =3D {
+            .global =3D true, /* only global stops currently supported */
+        };
+
+        q_obj_mcd_run_arg run_args =3D {
+            .global =3D true,
+        };
+
+        q_obj_mcd_close_core_arg close_core_args;
+
+        MCDRunResult *run_result;
+        MCDStopResult *stop_result;
+        MCDOpenCoreResult *open_core_result;
+        MCDCloseCoreResult *close_core_result;
+
+        MCDCoreConInfo *core_con_info =3D core_head->value;
+        q_obj_mcd_open_core_arg open_core_args =3D {
+            .core_con_info =3D core_con_info,
+        };
+
+        if (verbose) {
+            fprintf(stderr, "[INFO]\tTesting core %s (#%d)...\n",
+                            core_con_info->core,
+                            core_con_info->core_id);
+        }
+
+        open_core_result =3D qtest_mcd_open_core(qts, &open_core_args);
+        g_assert(open_core_result->return_status =3D=3D MCD_RET_ACT_NONE);
+        g_assert(open_core_result->has_core_uid);
+
+        check_core_state(qts, open_core_result->core_uid);
+
+        if (verbose) {
+            fprintf(stderr, "[INFO]\tStop core\n");
+        }
+
+        stop_args.core_uid =3D open_core_result->core_uid;
+        stop_result =3D qtest_mcd_stop(qts, &stop_args);
+        g_assert(stop_result->return_status =3D=3D MCD_RET_ACT_NONE);
+        qapi_free_MCDStopResult(stop_result);
+
+        core_state =3D check_core_state(qts, open_core_result->core_uid);
+        g_assert(core_state =3D=3D MCD_CORE_STATE_DEBUG);
+
+        if (verbose) {
+            fprintf(stderr, "[INFO]\tResume core\n");
+        }
+
+        run_args.core_uid =3D open_core_result->core_uid;
+        run_result =3D qtest_mcd_run(qts, &run_args);
+        g_assert(run_result->return_status =3D=3D MCD_RET_ACT_NONE);
+        qapi_free_MCDRunResult(run_result);
+
+        core_state =3D check_core_state(qts, open_core_result->core_uid);
+        g_assert(core_state =3D=3D MCD_CORE_STATE_RUNNING);
+
+        close_core_args.core_uid =3D open_core_result->core_uid;
+        close_core_result =3D qtest_mcd_close_core(qts, &close_core_args);
+        g_assert(close_core_result->return_status =3D=3D MCD_RET_ACT_NONE);
+
+        qapi_free_MCDCloseCoreResult(close_core_result);
+        qapi_free_MCDOpenCoreResult(open_core_result);
+        core_head =3D core_head->next;
+    }
+
+    qapi_free_MCDQryCoresResult(cores_query);
+    qtest_mcd_exit(qts);
+    qtest_quit(qts);
+}
+
 int main(int argc, char *argv[])
 {
     char *v_env =3D getenv("V");
@@ -522,5 +639,6 @@ int main(int argc, char *argv[])
     qtest_add_func("mcd/qry-cores", test_qry_cores);
     qtest_add_func("mcd/open-core", test_open_core);
     qtest_add_func("mcd/qry-core-info", test_qry_core_info);
+    qtest_add_func("mcd/go-stop", test_go_stop);
     return g_test_run();
 }
--=20
2.34.1