@@ -195,3 +195,19 @@ MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st *reg_info)
return marshal;
}
+
+MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state)
+{
+ MCDCoreState *marshal = g_malloc0(sizeof(*marshal));
+
+ *marshal = (MCDCoreState) {
+ .state = state->state,
+ .event = state->event,
+ .hw_thread_id = state->hw_thread_id,
+ .trig_id = state->trig_id,
+ .stop_str = g_strdup(state->stop_str),
+ .info_str = g_strdup(state->info_str),
+ };
+
+ return marshal;
+}
@@ -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);
+MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state);
+
mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version);
mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info);
@@ -16,6 +16,7 @@
#include "exec/gdbstub.h"
#include "hw/core/cpu.h"
#include "system/runstate.h"
+#include "system/hw_accel.h"
/* Custom memory space type */
static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000;
@@ -1192,7 +1193,52 @@ mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable)
mcd_return_et mcd_qry_state_f(const mcd_core_st *core, mcd_core_state_st *state)
{
- g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED;
+ mcdcore_state *core_state;
+ RunState rs;
+
+ if (!core || !state) {
+ g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM;
+ return g_server_state.last_error->return_status;
+ }
+
+ *state = (mcd_core_state_st) {
+ .stop_str = "",
+ .info_str = "",
+ };
+
+ core_state = find_core(core->core_con_info);
+ if (!core_state || core_state->open_core != core) {
+ g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE;
+ return g_server_state.last_error->return_status;
+ }
+
+ cpu_synchronize_state(core_state->cpu);
+ rs = runstate_get();
+ switch (rs) {
+ case RUN_STATE_PRELAUNCH:
+ case RUN_STATE_DEBUG:
+ case RUN_STATE_PAUSED:
+ state->state = 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 = MCD_CORE_STATE_RUNNING;
+ } else if (core_state->cpu->stopped) {
+ state->state = MCD_CORE_STATE_DEBUG;
+ } else if (core_state->cpu->halted) {
+ state->state = MCD_CORE_STATE_HALTED;
+ pstrcpy(state->info_str, MCD_INFO_STR_LEN, "halted");
+ } else {
+ state->state = MCD_CORE_STATE_UNKNOWN;
+ }
+ break;
+ default:
+ state->state = MCD_CORE_STATE_UNKNOWN;
+ break;
+ }
+
+ g_server_state.last_error = &MCD_ERROR_NONE;
return g_server_state.last_error->return_status;
}
@@ -557,3 +557,24 @@ MCDSetGlobalResult *qmp_mcd_set_global(uint32_t core_uid, bool enable,
g_stub_state.on_error_ask_server = true;
return result;
}
+
+MCDQryStateResult *qmp_mcd_qry_state(uint32_t core_uid, Error **errp)
+{
+ MCDQryStateResult *result = g_malloc0(sizeof(*result));
+ mcd_core_state_st state;
+ mcd_core_st *core = NULL;
+
+ result->return_status = retrieve_open_core(core_uid, &core);
+ if (result->return_status != MCD_RET_ACT_NONE) {
+ g_stub_state.on_error_ask_server = false;
+ return result;
+ }
+
+ result->return_status = mcd_qry_state_f(core, &state);
+ if (result->return_status == MCD_RET_ACT_NONE) {
+ result->state = marshal_mcd_core_state(&state);
+ }
+
+ g_stub_state.on_error_ask_server = true;
+ return result;
+}
@@ -307,6 +307,29 @@
'hw-thread-id' : 'uint32' } }
+##
+# @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' } }
+
##
# == 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-core.
+#
+# Returns: @MCDQryStateResult
+#
+# Since: 9.1
+##
+{ 'command': 'mcd-qry-state',
+ 'data': { 'core-uid': 'uint32' },
+ 'returns': 'MCDQryStateResult' }
@@ -316,5 +316,64 @@ MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts,
UNMARSHAL_RESULT(MCDQryRegMapResult);
+ 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 = 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 = 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 = qtest_qmp(qts, "{'execute': 'mcd-qry-state',"
+ "'arguments': %p}", arg);
+
+ UNMARSHAL_RESULT(MCDQryStateResult);
+
return unmarshal;
}
@@ -56,4 +56,13 @@ MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(QTestState *qts,
MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts,
q_obj_mcd_qry_reg_map_arg *args);
+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 */
@@ -18,7 +18,7 @@
#include "qapi/compat-policy.h"
#include "libmcd-test.h"
-#define QEMU_EXTRA_ARGS ""
+#define QEMU_EXTRA_ARGS "-accel tcg"
static bool verbose;
@@ -87,6 +87,45 @@ static MCDQryCoresResult *open_server_query_cores(QTestState *qts)
return qry_cores_result;
}
+static mcd_core_state_et check_core_state(QTestState *qts, uint32_t core_uid)
+{
+ mcd_core_state_et state;
+
+ q_obj_mcd_qry_state_arg qry_state_args = {
+ .core_uid = core_uid,
+ };
+
+ MCDQryStateResult *qry_state_result = qtest_mcd_qry_state(qts,
+ &qry_state_args);
+
+ g_assert(qry_state_result->return_status == MCD_RET_ACT_NONE);
+ g_assert(qry_state_result->state);
+ state = 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 = qtest_init(QEMU_EXTRA_ARGS);
@@ -510,6 +549,84 @@ static void test_qry_core_info(void)
qtest_quit(qts);
}
+static void test_go_stop(void)
+{
+ QTestState *qts = qtest_init(QEMU_EXTRA_ARGS);
+ mcd_core_state_et core_state;
+ MCDQryCoresResult *cores_query = open_server_query_cores(qts);
+
+ MCDCoreConInfoList *core_head = cores_query->core_con_info;
+ for (uint32_t c = 0; c < cores_query->num_cores; c++) {
+ q_obj_mcd_stop_arg stop_args = {
+ .global = true, /* only global stops currently supported */
+ };
+
+ q_obj_mcd_run_arg run_args = {
+ .global = 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 = core_head->value;
+ q_obj_mcd_open_core_arg open_core_args = {
+ .core_con_info = 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 = qtest_mcd_open_core(qts, &open_core_args);
+ g_assert(open_core_result->return_status == 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 = open_core_result->core_uid;
+ stop_result = qtest_mcd_stop(qts, &stop_args);
+ g_assert(stop_result->return_status == MCD_RET_ACT_NONE);
+ qapi_free_MCDStopResult(stop_result);
+
+ core_state = check_core_state(qts, open_core_result->core_uid);
+ g_assert(core_state == MCD_CORE_STATE_DEBUG);
+
+ if (verbose) {
+ fprintf(stderr, "[INFO]\tResume core\n");
+ }
+
+ run_args.core_uid = open_core_result->core_uid;
+ run_result = qtest_mcd_run(qts, &run_args);
+ g_assert(run_result->return_status == MCD_RET_ACT_NONE);
+ qapi_free_MCDRunResult(run_result);
+
+ core_state = check_core_state(qts, open_core_result->core_uid);
+ g_assert(core_state == MCD_CORE_STATE_RUNNING);
+
+ close_core_args.core_uid = open_core_result->core_uid;
+ close_core_result = qtest_mcd_close_core(qts, &close_core_args);
+ g_assert(close_core_result->return_status == MCD_RET_ACT_NONE);
+
+ qapi_free_MCDCloseCoreResult(close_core_result);
+ qapi_free_MCDOpenCoreResult(open_core_result);
+ core_head = core_head->next;
+ }
+
+ qapi_free_MCDQryCoresResult(cores_query);
+ qtest_mcd_exit(qts);
+ qtest_quit(qts);
+}
+
int main(int argc, char *argv[])
{
char *v_env = 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();
}
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(-)