Directly map MCD register groups to GDB features lists
Signed-off-by: Mario Fleischmann <[email protected]>
---
mcd/libmcd_qapi.c | 48 +++++++
mcd/libmcd_qapi.h | 8 ++
mcd/mcdserver.c | 237 ++++++++++++++++++++++++++++--
mcd/mcdstub_qapi.c | 93 ++++++++++++
qapi/mcd.json | 296 ++++++++++++++++++++++++++++++++++++++
tests/qtest/libmcd-test.c | 40 ++++++
tests/qtest/libmcd-test.h | 6 +
tests/qtest/mcd-test.c | 85 +++++++++++
8 files changed, 803 insertions(+), 10 deletions(-)
diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c
index 0421152705..99177b2fd2 100644
--- a/mcd/libmcd_qapi.c
+++ b/mcd/libmcd_qapi.c
@@ -147,3 +147,51 @@ MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st
*mem_space)
return marshal;
}
+
+MCDRegisterGroup *marshal_mcd_register_group(
+ const mcd_register_group_st *reg_group)
+{
+ MCDRegisterGroup *marshal = g_malloc0(sizeof(*marshal));
+
+ *marshal = (MCDRegisterGroup) {
+ .reg_group_id = reg_group->reg_group_id,
+ .reg_group_name = g_strdup(reg_group->reg_group_name),
+ .n_registers = reg_group->n_registers,
+ };
+
+ return marshal;
+}
+
+MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr)
+{
+ MCDAddr *marshal = g_malloc0(sizeof(*marshal));
+
+ *marshal = (MCDAddr) {
+ .address = addr->address,
+ .mem_space_id = addr->mem_space_id,
+ .addr_space_id = addr->addr_space_id,
+ .addr_space_type = addr->addr_space_type,
+ };
+
+ return marshal;
+}
+
+MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st
*reg_info)
+{
+ MCDRegisterInfo *marshal = g_malloc0(sizeof(*marshal));
+
+ *marshal = (MCDRegisterInfo) {
+ .addr = marshal_mcd_addr(®_info->addr),
+ .reg_group_id = reg_info->reg_group_id,
+ .regname = g_strdup(reg_info->regname),
+ .regsize = reg_info->regsize,
+ .core_mode_mask_read = reg_info->core_mode_mask_read,
+ .core_mode_mask_write = reg_info->core_mode_mask_write,
+ .side_effects_read = reg_info->has_side_effects_read,
+ .side_effects_write = reg_info->has_side_effects_write,
+ .reg_type = reg_info->reg_type,
+ .hw_thread_id = reg_info->hw_thread_id,
+ };
+
+ return marshal;
+}
diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h
index 7e874dec25..edcc6d0b7c 100644
--- a/mcd/libmcd_qapi.h
+++ b/mcd/libmcd_qapi.h
@@ -27,6 +27,14 @@ MCDCoreConInfo *marshal_mcd_core_con_info(const
mcd_core_con_info_st *con_info);
MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space);
+MCDRegisterGroup *marshal_mcd_register_group(
+ const mcd_register_group_st *reg_group);
+
+MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr);
+
+MCDRegisterInfo *marshal_mcd_register_info(
+ const mcd_register_info_st *reg_info);
+
mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version);
mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info);
diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c
index f924bf3799..f0cda23981 100644
--- a/mcd/mcdserver.c
+++ b/mcd/mcdserver.c
@@ -13,6 +13,7 @@
#include "mcd_api.h"
#include "hw/boards.h"
#include "exec/tswap.h"
+#include "exec/gdbstub.h"
/* Custom memory space type */
static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000;
@@ -55,12 +56,14 @@ static const mcd_error_info_st MCD_ERROR_NONE = {
/**
* struct mcdcore_state - State of a core.
*
- * @last_error: Error info of most recent executed core-related function.
- * @custom_error: Reserves memory for custom MCD errors.
- * @info: Core connection information.
- * @open_core: Open core instance as allocated in mcd_open_core_f().
- * @cpu: QEMU's internal CPU handle.
- * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f().
+ * @last_error: Error info of most recent executed core-related function.
+ * @custom_error: Reserves memory for custom MCD errors.
+ * @info: Core connection information.
+ * @open_core: Open core instance as allocated in mcd_open_core_f().
+ * @cpu: QEMU's internal CPU handle.
+ * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f().
+ * @register_groups: Register groups as queried by mcd_qry_reg_groups_f().
+ * @registers: Registers as queried by mcd_qry_reg_map_f().
*
* MCD is mainly being used on the core level:
* After the initial query functions, a core connection is opened in
@@ -77,6 +80,8 @@ typedef struct mcdcore_state {
mcd_core_st *open_core;
CPUState *cpu;
GArray *memory_spaces;
+ GArray *register_groups;
+ GArray *registers;
} mcdcore_state;
/**
@@ -267,6 +272,10 @@ mcd_return_et mcd_open_server_f(const char *system_key,
.open_core = NULL,
.cpu = cpu,
.memory_spaces = g_array_new(false, true, sizeof(mcd_memspace_st)),
+ .register_groups = g_array_new(false, true,
+ sizeof(mcd_register_group_st)),
+ .registers = g_array_new(false, true,
+ sizeof(mcd_register_info_st)),
};
pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model);
g_array_append_val(g_server_state.cores, c);
@@ -306,6 +315,10 @@ mcd_return_et mcd_close_server_f(const mcd_server_st
*server)
if (c->open_core) {
mcd_close_core_f(c->open_core);
}
+
+ g_array_free(c->memory_spaces, true);
+ g_array_free(c->register_groups, true);
+ g_array_free(c->registers, true);
}
g_array_free(g_server_state.cores, true);
@@ -538,6 +551,59 @@ static mcd_return_et query_memspaces(mcdcore_state
*core_state)
return MCD_RET_ACT_NONE;
}
+static mcd_return_et query_registers(mcdcore_state *core_state)
+{
+ GArray *gdb_regs = core_state->cpu->gdb_regs;
+ assert(gdb_regs);
+
+ g_array_set_size(core_state->register_groups, 0);
+ g_array_set_size(core_state->registers, 0);
+
+ for (int feature_id = 0; feature_id < gdb_regs->len; feature_id++) {
+ GDBRegisterState *f = &g_array_index(gdb_regs, GDBRegisterState,
+ feature_id);
+ /* register group ID 0 is reserved */
+ uint32_t group_id = feature_id + 1;
+ uint32_t num_regs = 0;
+
+ GByteArray *mem_buf = g_byte_array_new();
+ for (int i = 0; i < f->feature->num_regs; i++) {
+ const char *name = f->feature->regs[i];
+ if (name) {
+ int reg_id = f->base_reg + i;
+ int bitsize = gdb_read_register(core_state->cpu,
+ mem_buf, reg_id) * 8;
+ mcd_register_info_st r = {
+ .addr = {
+ .address = (uint64_t) reg_id,
+ /* memory space "GDB Registers" */
+ .mem_space_id = core_state->memory_spaces->len,
+ .addr_space_type = MCD_NOTUSED_ID,
+ },
+ .reg_group_id = group_id,
+ .regsize = (uint32_t) bitsize,
+ .reg_type = MCD_REG_TYPE_SIMPLE,
+ /* ID 0 reserved */
+ .hw_thread_id = core_state->info.core_id + 1,
+ };
+ strncpy(r.regname, name, MCD_REG_NAME_LEN - 1);
+ g_array_append_val(core_state->registers, r);
+ num_regs++;
+ }
+ }
+ g_byte_array_free(mem_buf, true);
+
+ mcd_register_group_st rg = {
+ .reg_group_id = group_id,
+ .n_registers = num_regs,
+ };
+ strncpy(rg.reg_group_name, f->feature->name, MCD_REG_NAME_LEN - 1);
+ g_array_append_val(core_state->register_groups, rg);
+ }
+
+ return MCD_RET_ACT_NONE;
+}
+
mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info,
mcd_core_st **core)
{
@@ -583,6 +649,10 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st
*core_con_info,
return g_server_state.last_error->return_status;
}
+ if (query_registers(core_state) != MCD_RET_ACT_NONE) {
+ return g_server_state.last_error->return_status;
+ }
+
*core = g_malloc(sizeof(mcd_core_st));
info = g_malloc(sizeof(mcd_core_con_info_st));
*info = *core_con_info;
@@ -626,6 +696,8 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core)
core_state->open_core = NULL;
core_state->cpu = NULL;
g_array_set_size(core_state->memory_spaces, 0);
+ g_array_set_size(core_state->register_groups, 0);
+ g_array_set_size(core_state->registers, 0);
g_server_state.last_error = &MCD_ERROR_NONE;
return g_server_state.last_error->return_status;
@@ -771,16 +843,161 @@ mcd_return_et mcd_qry_reg_groups_f(const mcd_core_st
*core,
uint32_t *num_reg_groups,
mcd_register_group_st *reg_groups)
{
- g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED;
- return g_server_state.last_error->return_status;
+ uint32_t i;
+ mcdcore_state *core_state;
+
+ if (!core || !num_reg_groups) {
+ g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM;
+ return g_server_state.last_error->return_status;
+ }
+
+ 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;
+ }
+
+ g_assert(core_state->register_groups);
+
+ if (core_state->register_groups->len == 0) {
+ core_state->custom_error = (mcd_error_info_st) {
+ .return_status = MCD_RET_ACT_HANDLE_ERROR,
+ .error_code = MCD_ERR_NO_REG_GROUPS,
+ .error_events = MCD_ERR_EVT_NONE,
+ .error_str = "",
+ };
+ core_state->last_error = &core_state->custom_error;
+ return core_state->last_error->return_status;
+ }
+
+ if (*num_reg_groups == 0) {
+ *num_reg_groups = core_state->register_groups->len;
+ core_state->last_error = &MCD_ERROR_NONE;
+ return core_state->last_error->return_status;
+ }
+
+ if (start_index >= core_state->register_groups->len) {
+ core_state->custom_error = (mcd_error_info_st) {
+ .return_status = MCD_RET_ACT_HANDLE_ERROR,
+ .error_code = MCD_ERR_PARAM,
+ .error_events = MCD_ERR_EVT_NONE,
+ .error_str = "start_index exceeds the number of register groups",
+ };
+ core_state->last_error = &core_state->custom_error;
+ return core_state->last_error->return_status;
+ }
+
+ if (!reg_groups) {
+ core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM;
+ return core_state->last_error->return_status;
+ }
+
+ for (i = 0; i < *num_reg_groups &&
+ start_index + i < core_state->register_groups->len; i++) {
+
+ reg_groups[i] = g_array_index(core_state->register_groups,
+ mcd_register_group_st, start_index + i);
+ }
+
+ *num_reg_groups = i;
+
+ core_state->last_error = &MCD_ERROR_NONE;
+ return core_state->last_error->return_status;
}
mcd_return_et mcd_qry_reg_map_f(const mcd_core_st *core, uint32_t reg_group_id,
uint32_t start_index, uint32_t *num_regs,
mcd_register_info_st *reg_info)
{
- g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED;
- return g_server_state.last_error->return_status;
+ mcdcore_state *core_state;
+ bool query_all_regs = reg_group_id == 0;
+ bool query_num_only;
+
+ if (!core || !num_regs) {
+ g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM;
+ return g_server_state.last_error->return_status;
+ }
+
+ query_num_only = *num_regs == 0;
+
+ 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;
+ }
+
+ if (core_state->register_groups->len == 0 ||
+ reg_group_id > core_state->register_groups->len) {
+
+ core_state->custom_error = (mcd_error_info_st) {
+ .return_status = MCD_RET_ACT_HANDLE_ERROR,
+ .error_code = MCD_ERR_REG_GROUP_ID,
+ .error_events = MCD_ERR_EVT_NONE,
+ .error_str = "",
+ };
+ core_state->last_error = &core_state->custom_error;
+ return core_state->last_error->return_status;
+ }
+
+ /*
+ * Depending on reg_group_id, start_index refers either to the total list
of
+ * register or a single register group.
+ */
+
+ if (query_all_regs) {
+ if (start_index >= core_state->registers->len) {
+ core_state->custom_error = (mcd_error_info_st) {
+ .return_status = MCD_RET_ACT_HANDLE_ERROR,
+ .error_code = MCD_ERR_PARAM,
+ .error_events = MCD_ERR_EVT_NONE,
+ .error_str = "start_index exceeds the number of registers",
+ };
+ core_state->last_error = &core_state->custom_error;
+ return core_state->last_error->return_status;
+ };
+
+ if (*num_regs == 0) {
+ *num_regs = core_state->registers->len;
+ } else if (*num_regs > core_state->registers->len - start_index) {
+ *num_regs = core_state->registers->len - start_index;
+ }
+ } else {
+ mcd_register_group_st *rg = &g_array_index(core_state->register_groups,
+ mcd_register_group_st, reg_group_id - 1);
+
+ if (start_index > rg->n_registers) {
+ core_state->custom_error = (mcd_error_info_st) {
+ .return_status = MCD_RET_ACT_HANDLE_ERROR,
+ .error_code = MCD_ERR_PARAM,
+ .error_events = MCD_ERR_EVT_NONE,
+ .error_str = "start_index exceeds the number of registers",
+ };
+ core_state->last_error = &core_state->custom_error;
+ return core_state->last_error->return_status;
+ }
+
+ if (*num_regs == 0) {
+ *num_regs = rg->n_registers;
+ } else if (*num_regs > rg->n_registers - start_index) {
+ *num_regs = rg->n_registers - start_index;
+ }
+
+ for (uint32_t rg_id = 0; rg_id < reg_group_id - 1; rg_id++) {
+ mcd_register_group_st *prev_rg = &g_array_index(
+ core_state->register_groups, mcd_register_group_st, rg_id);
+ start_index += prev_rg->n_registers;
+ }
+ }
+
+ if (!query_num_only) {
+ for (uint32_t i = 0; i < *num_regs; i++) {
+ reg_info[i] = g_array_index(
+ core_state->registers, mcd_register_info_st, start_index + i);
+ }
+ }
+
+ core_state->last_error = &MCD_ERROR_NONE;
+ return core_state->last_error->return_status;
}
mcd_return_et mcd_qry_reg_compound_f(const mcd_core_st *core,
diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c
index 437d2c2e3e..6aa72b025c 100644
--- a/mcd/mcdstub_qapi.c
+++ b/mcd/mcdstub_qapi.c
@@ -412,3 +412,96 @@ MCDQryMemSpacesResult *qmp_mcd_qry_mem_spaces(uint32_t
core_uid,
g_stub_state.on_error_ask_server = true;
return result;
}
+
+MCDQryRegGroupsResult *qmp_mcd_qry_reg_groups(uint32_t core_uid,
+ uint32_t start_index,
+ uint32_t num_reg_groups,
+ Error **errp)
+{
+ MCDRegisterGroupList **tailp;
+ MCDRegisterGroup *rg;
+ mcd_register_group_st *reg_groups = NULL;
+ bool query_num_only = num_reg_groups == 0;
+ MCDQryRegGroupsResult *result = g_malloc0(sizeof(*result));
+ 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;
+ }
+
+ if (!query_num_only) {
+ reg_groups = g_malloc0(num_reg_groups * sizeof(*reg_groups));
+ }
+
+ result->return_status = mcd_qry_reg_groups_f(core, start_index,
+ &num_reg_groups, reg_groups);
+
+ if (result->return_status == MCD_RET_ACT_NONE) {
+ result->has_num_reg_groups = true;
+ result->num_reg_groups = num_reg_groups;
+ if (!query_num_only) {
+ result->has_reg_groups = true;
+ tailp = &(result->reg_groups);
+ for (uint32_t i = 0; i < num_reg_groups; i++) {
+ rg = marshal_mcd_register_group(reg_groups + i);
+ QAPI_LIST_APPEND(tailp, rg);
+ }
+ }
+ }
+
+ if (!query_num_only) {
+ g_free(reg_groups);
+ }
+
+ g_stub_state.on_error_ask_server = true;
+ return result;
+}
+
+MCDQryRegMapResult *qmp_mcd_qry_reg_map(uint32_t core_uid,
+ uint32_t reg_group_id,
+ uint32_t start_index, uint32_t
num_regs,
+ Error **errp)
+{
+ MCDRegisterInfoList **tailp;
+ MCDRegisterInfo *r;
+ mcd_register_info_st *regs = NULL;
+ bool query_num_only = num_regs == 0;
+ MCDQryRegMapResult *result = g_malloc0(sizeof(*result));
+ 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;
+ }
+
+ if (!query_num_only) {
+ regs = g_malloc0(num_regs * sizeof(*regs));
+ }
+
+ result->return_status = mcd_qry_reg_map_f(core, reg_group_id,
+ start_index, &num_regs,
+ regs);
+
+ if (result->return_status == MCD_RET_ACT_NONE) {
+ result->has_num_regs = true;
+ result->num_regs = num_regs;
+ if (!query_num_only) {
+ result->has_reg_info = true;
+ tailp = &(result->reg_info);
+ for (uint32_t i = 0; i < num_regs; i++) {
+ r = marshal_mcd_register_info(regs + i);
+ QAPI_LIST_APPEND(tailp, r);
+ }
+ }
+ }
+
+ if (!query_num_only) {
+ g_free(regs);
+ }
+
+ g_stub_state.on_error_ask_server = true;
+ return result;
+}
diff --git a/qapi/mcd.json b/qapi/mcd.json
index 214933e279..936016de45 100644
--- a/qapi/mcd.json
+++ b/qapi/mcd.json
@@ -215,6 +215,98 @@
'core-mode-mask-write' : 'uint32' } }
+##
+# @MCDRegisterGroup:
+#
+# Structure type containing register group information.
+#
+# @reg-group-id: Contains the ID of this register group. A register group ID
+# must be unique within the scope of a target core. ID '0' is
+# reserved.
+# @reg-group-name: The name of a register group. A register group name cannot
+# be longer than MCD_REG_NAME_LEN characters (use
+# representative names).
+# @n-registers: Number of registers part of this group.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDRegisterGroup',
+ 'data': {
+ 'reg-group-id' : 'uint32',
+ 'reg-group-name': 'str',
+ 'n-registers' : 'uint32' } }
+
+
+##
+# @MCDAddr:
+#
+# Structure type containing a completely resolved logical or physical memory
+# address.
+#
+# @address: Address value within a memory space, expressed in bytes.
+# @mem-space-id: ID of the memory space associated with this address, e.g. a
+# program memory, a data memory or registers .
+# @addr-space-id: ID of the address space in which this address is valid.
+# @addr-space-type: Type of the address space in which this address is valid.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDAddr',
+ 'data': {
+ 'address' : 'uint64',
+ 'mem-space-id' : 'uint32',
+ 'addr-space-id' : 'uint32',
+ 'addr-space-type': 'uint32' } }
+
+
+##
+# @MCDRegisterInfo:
+#
+# Structure type containing register information for a single register.
+#
+# @addr: Either the address of a memory mapped register or
+# the register address in a dedicated
+# "register memory space"
+# @reg-group-id: ID of the group this register belongs to.
+# @regname: The name of a register. A register name cannot be
+# longer than MCD_REG_NAME_LEN characters (use
+# representative names).
+# @regsize: Register size in bits.
+# @core-mode-mask-read: Mask of core modes for which read accesses are
+# impossible. A set bit indicates that read accesses
+# are denied in this mode. Bit 0 represents core mode
+# '1', bit 31 represents core mode 32. Overrides
+# @core-mode-mask-read of the corresponding
+# mcd_memspace_st.
+# @core-mode-mask-write: Mask of core modes for which write accesses are
+# impossible. A set bit indicates that write accesses
+# are denied in this mode. Bit 0 represents core mode
+# '1', bit 31 represents core mode '32'. Overrides
+# @core-mode-mask-write of the corresponding
+# mcd_memspace_st.
+# @side-effects-read: Reading this register can trigger side effects.
+# @side-effects-write: Writing this register can trigger side effects.
+# @reg-type: Register type (simple, compound or partial)
+# @hw-thread-id: Hardware thread ID this register belongs to. The ID
+# must be set to '0' if the register is not assigned
+# to a hardware thread.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDRegisterInfo',
+ 'data': {
+ 'addr' : 'MCDAddr',
+ 'reg-group-id' : 'uint32',
+ 'regname' : 'str',
+ 'regsize' : 'uint32',
+ 'core-mode-mask-read' : 'uint32',
+ 'core-mode-mask-write': 'uint32',
+ 'side-effects-read' : 'bool',
+ 'side-effects-write' : 'bool',
+ 'reg-type' : 'uint32',
+ 'hw-thread-id' : 'uint32' } }
+
+
##
# == Target Initialization API
##
@@ -1077,3 +1169,207 @@
'start-index' : 'uint32',
'num-mem-spaces': 'uint32' },
'returns': 'MCDQryMemSpacesResult' }
+
+
+##
+# @MCDQryRegGroupsResult:
+#
+# Return value of @mcd-qry-reg-groups.
+#
+# @return-status: Return code.
+# @num-reg-groups: Number of returned register groups. In case the input value
+# of @num-reg-groups is '0', this is the number of all
+# available register groups for the selected core.
+# @reg-groups: Register group information.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDQryRegGroupsResult',
+ 'data': {
+ 'return-status' : 'uint32',
+ '*num-reg-groups': 'uint32',
+ '*reg-groups' : [ 'MCDRegisterGroup' ] }}
+
+
+##
+# @mcd-qry-reg-groups:
+#
+# Function querying the register groups defined for a particular component.
+#
+# @core-uid: Unique ID of the core the calling function addresses.
+# @start-index: Start index of the requested register groups. This refers
+# to an internal list of the target side implementation.
+# @num-reg-groups: Number of register groups, information is requested of. If
+# it is set to '0', no register groups information is returned
+# but the number of all available register groups for the
+# selected core.
+#
+# Returns: @MCDQryRegGroupsResult
+#
+# Since: 9.1
+##
+{ 'command': 'mcd-qry-reg-groups',
+ 'data': {
+ 'core-uid' : 'uint32',
+ 'start-index' : 'uint32',
+ 'num-reg-groups': 'uint32' },
+ 'returns': 'MCDQryRegGroupsResult' }
+
+
+##
+# @MCDQryRegMapResult:
+#
+# Return value of @mcd-qry-reg-map.
+#
+# @return-status: Return code.
+# @num-regs: Number of returned registers. In case the input value of
+# @num-regs is '0', this is the number of all available
register
+# for the selected register group.
+# @reg-info: Register information.
+#
+# Since: 9.1
+##
+{ 'struct': 'MCDQryRegMapResult',
+ 'data': {
+ 'return-status': 'uint32',
+ '*num-regs' : 'uint32',
+ '*reg-info' : [ 'MCDRegisterInfo' ] }}
+
+##
+# @mcd-qry-reg-map:
+#
+# Function querying the register information of a particular register group.
+#
+# @core-uid: Unique ID of the core the calling function addresses.
+# @reg-group-id: ID of the register group detailed register information is
+# requested for.
+# @start-index: Start index of the requested registers. This refers to an
+# internal list of the target side implementation.
+# @num-regs: Number of registers, information is requested of. If it
+# is set to '0', no register information is returned but the
+# number of all available registers within for the selected
+# register group.
+#
+# Returns: @MCDQryRegMapResult
+#
+# Since: 9.1
+#
+# .. qmp-example::
+#
+# -> { "execute": "mcd-qry-reg-groups",
+# "arguments": { "core-uid": 1,
+# "start-index": 0,
+# "num-reg-groups": 3 } }
+# <- {
+# "return": {
+# "reg-groups": [
+# {
+# "reg-group-id": 1,
+# "reg-group-name": "org.gnu.gdb.aarch64.core",
+# "n-registers": 34
+# },
+# {
+# "reg-group-id": 2,
+# "reg-group-name": "org.gnu.gdb.aarch64.fpu",
+# "n-registers": 34
+# },
+# {
+# "reg-group-id": 3,
+# "reg-group-name": "org.qemu.gdb.arm.sys.regs",
+# "n-registers": 210
+# }
+# ],
+# "return-status": 0,
+# "num-reg-groups": 3
+# }
+# }
+# -> { "execute": "mcd-qry-reg-map",
+# "arguments": { "core-uid": 1,
+# "reg-group-id": 1,
+# "start-index": 0,
+# "num-regs": 34 } }
+# <- {
+# "return": {
+# "reg-info": [
+# {
+# "reg-group-id": 1,
+# "regname": "x0",
+# "side-effects-read": false,
+# "addr": {
+# "mem-space-id": 5,
+# "addr-space-id": 0,
+# "address": 0,
+# "addr-space-type": 0
+# },
+# "reg-type": 0,
+# "core-mode-mask-write": 0,
+# "core-mode-mask-read": 0,
+# "regsize": 64,
+# "hw-thread-id": 0,
+# "side-effects-write": false
+# },
+# {
+# "reg-group-id": 1,
+# "regname": "x1",
+# "side-effects-read": false,
+# "addr": {
+# "mem-space-id": 5,
+# "addr-space-id": 0,
+# "address": 1,
+# "addr-space-type": 0
+# },
+# "reg-type": 0,
+# "core-mode-mask-write": 0,
+# "core-mode-mask-read": 0,
+# "regsize": 64,
+# "hw-thread-id": 0,
+# "side-effects-write": false
+# },
+# {
+# "reg-group-id": 1,
+# "regname": "x2",
+# "side-effects-read": false,
+# "addr": {
+# "mem-space-id": 5,
+# "addr-space-id": 0,
+# "address": 2,
+# "addr-space-type": 0
+# },
+# "reg-type": 0,
+# "core-mode-mask-write": 0,
+# "core-mode-mask-read": 0,
+# "regsize": 64,
+# "hw-thread-id": 0,
+# "side-effects-write": false
+# },
+# {
+# "reg-group-id": 1,
+# "regname": "x3",
+# "side-effects-read": false,
+# "addr": {
+# "mem-space-id": 5,
+# "addr-space-id": 0,
+# "address": 3,
+# "addr-space-type": 0
+# },
+# "reg-type": 0,
+# "core-mode-mask-write": 0,
+# "core-mode-mask-read": 0,
+# "regsize": 64,
+# "hw-thread-id": 0,
+# "side-effects-write": false
+# },
+# ...
+# ],
+# "return-status": 0,
+# "num-regs": 34
+# }
+# }
+##
+{ 'command': 'mcd-qry-reg-map',
+ 'data': {
+ 'core-uid': 'uint32',
+ 'reg-group-id': 'uint32',
+ 'start-index': 'uint32',
+ 'num-regs': 'uint32' },
+ 'returns': 'MCDQryRegMapResult' }
diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c
index 9e41a0218f..82a39366b2 100644
--- a/tests/qtest/libmcd-test.c
+++ b/tests/qtest/libmcd-test.c
@@ -278,3 +278,43 @@ MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(
return unmarshal;
}
+
+MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(
+ QTestState *qts, q_obj_mcd_qry_reg_groups_arg *args)
+{
+ Visitor *v;
+ QObject *marshal;
+ QDict *arg, *resp;
+ QObject *ret;
+ bool ok;
+ MCDQryRegGroupsResult *unmarshal;
+
+ MARSHAL_ARGS(q_obj_mcd_qry_reg_groups_arg);
+
+ resp = qtest_qmp(qts, "{'execute': 'mcd-qry-reg-groups',"
+ "'arguments': %p}", arg);
+
+ UNMARSHAL_RESULT(MCDQryRegGroupsResult);
+
+ return unmarshal;
+}
+
+MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts,
+ q_obj_mcd_qry_reg_map_arg *args)
+{
+ Visitor *v;
+ QObject *marshal;
+ QDict *arg, *resp;
+ QObject *ret;
+ bool ok;
+ MCDQryRegMapResult *unmarshal;
+
+ MARSHAL_ARGS(q_obj_mcd_qry_reg_map_arg);
+
+ resp = qtest_qmp(qts, "{'execute': 'mcd-qry-reg-map',"
+ "'arguments': %p}", arg);
+
+ UNMARSHAL_RESULT(MCDQryRegMapResult);
+
+ return unmarshal;
+}
diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h
index 26f35b8931..266b6fe854 100644
--- a/tests/qtest/libmcd-test.h
+++ b/tests/qtest/libmcd-test.h
@@ -50,4 +50,10 @@ MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts,
MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(QTestState *qts,
q_obj_mcd_qry_mem_spaces_arg *args);
+MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(QTestState *qts,
+ q_obj_mcd_qry_reg_groups_arg *args);
+
+MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts,
+ q_obj_mcd_qry_reg_map_arg *args);
+
#endif /* LIBMCD_TEST_H */
diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c
index 7deca39f93..820408a9a9 100644
--- a/tests/qtest/mcd-test.c
+++ b/tests/qtest/mcd-test.c
@@ -355,8 +355,12 @@ static void test_qry_core_info(void)
MCDCoreConInfoList *core_head = cores_query->core_con_info;
for (uint32_t c = 0; c < cores_query->num_cores; c++) {
q_obj_mcd_qry_mem_spaces_arg qry_mem_spaces_args;
+ q_obj_mcd_qry_reg_groups_arg qry_reg_groups_args;
+ q_obj_mcd_qry_reg_map_arg qry_reg_map_args;
q_obj_mcd_close_core_arg close_core_args;
MCDQryMemSpacesResult *qry_mem_spaces_result;
+ MCDQryRegGroupsResult *qry_reg_groups_result;
+ MCDQryRegMapResult *qry_reg_map_result;
MCDCloseCoreResult *close_core_result;
MCDCoreConInfo *core_con_info = core_head->value;
@@ -374,6 +378,8 @@ static void test_qry_core_info(void)
core_con_info->core_id);
}
+ /* Memory Space Query */
+
qry_mem_spaces_args = (q_obj_mcd_qry_mem_spaces_arg) {
.core_uid = open_core_result->core_uid,
.start_index = 0,
@@ -411,6 +417,85 @@ static void test_qry_core_info(void)
}
qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_result);
+
+ /* Register Query */
+
+ qry_reg_groups_args = (q_obj_mcd_qry_reg_groups_arg) {
+ .core_uid = open_core_result->core_uid,
+ .start_index = 0,
+ .num_reg_groups = 0, /* query only number of register groups */
+ };
+
+ qry_reg_groups_result = qtest_mcd_qry_reg_groups(qts,
+ &qry_reg_groups_args);
+ g_assert(qry_reg_groups_result->return_status == MCD_RET_ACT_NONE);
+ g_assert(qry_reg_groups_result->has_num_reg_groups);
+
+ if (qry_reg_groups_result->num_reg_groups == 0) {
+ fprintf(stderr, "[WARN]\tTNo register groups!\n");
+ }
+
+ qry_reg_groups_args.num_reg_groups =
+ qry_reg_groups_result->num_reg_groups;
+
+ qapi_free_MCDQryRegGroupsResult(qry_reg_groups_result);
+ qry_reg_groups_result = qtest_mcd_qry_reg_groups(qts,
+ &qry_reg_groups_args);
+ g_assert(qry_reg_groups_result->return_status == MCD_RET_ACT_NONE);
+ g_assert(qry_reg_groups_result->has_num_reg_groups);
+
+ if (verbose) {
+ MCDRegisterGroupList *rg_head = qry_reg_groups_result->reg_groups;
+ for (uint32_t i = 0;
+ i < qry_reg_groups_result->num_reg_groups; i++) {
+ MCDRegisterGroup *rg = rg_head->value;
+ if (verbose) {
+ fprintf(stderr, "\tRegister Group: %s (#%d) with "
+ "%d registers\n",
+ rg->reg_group_name,
+ rg->reg_group_id,
+ rg->n_registers);
+ }
+ rg_head = rg_head->next;
+ }
+ }
+
+ qapi_free_MCDQryRegGroupsResult(qry_reg_groups_result);
+
+ qry_reg_map_args = (q_obj_mcd_qry_reg_map_arg) {
+ .core_uid = open_core_result->core_uid,
+ .reg_group_id = 0,
+ .start_index = 0,
+ .num_regs = 0, /* query only number of registers */
+ };
+
+ qry_reg_map_result = qtest_mcd_qry_reg_map(qts, &qry_reg_map_args);
+ g_assert(qry_reg_map_result->return_status == MCD_RET_ACT_NONE);
+ g_assert(qry_reg_map_result->has_num_regs);
+
+ if (verbose) {
+ fprintf(stderr, "\t%d registers found\n",
+ qry_reg_map_result->num_regs);
+ }
+
+ qry_reg_map_args.num_regs = qry_reg_map_result->num_regs;
+ qapi_free_MCDQryRegMapResult(qry_reg_map_result);
+
+ qry_reg_map_result = qtest_mcd_qry_reg_map(qts, &qry_reg_map_args);
+ g_assert(qry_reg_map_result->return_status == MCD_RET_ACT_NONE);
+ g_assert(qry_reg_map_result->has_num_regs);
+ if (verbose) {
+ MCDRegisterInfoList *r_head = qry_reg_map_result->reg_info;
+ for (uint32_t i = 0;
+ i < qry_reg_map_result->num_regs; i++) {
+ MCDRegisterInfo *r = r_head->value;
+ fprintf(stderr, "\tRegister: %s (#%lx)\n",
+ r->regname, r->addr->address);
+ r_head = r_head->next;
+ }
+ }
+ qapi_free_MCDQryRegMapResult(qry_reg_map_result);
+
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);
--
2.34.1