---
debug/mcdstub/arm_mcdstub.c | 243 ++++++++++++++++++++
debug/mcdstub/mcdstub.c | 373 ++++++++++++++++++++++++++++++-
debug/mcdstub/meson.build | 2 +-
include/mcdstub/arm_mcdstub.h | 85 +++++++
include/mcdstub/mcdstub.h | 5 -
include/mcdstub/mcdstub_common.h | 19 ++
6 files changed, 720 insertions(+), 7 deletions(-)
diff --git a/debug/mcdstub/arm_mcdstub.c b/debug/mcdstub/arm_mcdstub.c
index c24aaf1202..f14e677480 100644
--- a/debug/mcdstub/arm_mcdstub.c
+++ b/debug/mcdstub/arm_mcdstub.c
@@ -16,3 +16,246 @@
*
* SPDX-License-Identifier: LGPL-2.0+
*/
+
+#include "qemu/osdep.h"
+#include "mcdstub/arm_mcdstub.h"
+
+int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
+{
+ int nr_address_spaces = cpu->num_ases;
+ uint32_t mem_space_id = 0;
+
+ mem_space_id++;
+ mcd_mem_space_st non_secure = {
+ .name = "Non Secure",
+ .id = mem_space_id,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = false,
+ .is_physical = false,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&non_secure, 1);
+ mem_space_id++;
+ mcd_mem_space_st phys_non_secure = {
+ .name = "Physical (Non Secure)",
+ .id = mem_space_id,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = false,
+ .is_physical = true,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_non_secure, 1);
+ if (nr_address_spaces > 1) {
+ mem_space_id++;
+ mcd_mem_space_st secure = {
+ .name = "Secure",
+ .id = mem_space_id,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = true,
+ .is_physical = false,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&secure, 1);
+ mem_space_id++;
+ mcd_mem_space_st phys_secure = {
+ .name = "Physical (Secure)",
+ .id = mem_space_id,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = true,
+ .is_physical = true,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
+ }
+ mem_space_id++;
+ mcd_mem_space_st gpr = {
+ .name = "GPR Registers",
+ .id = mem_space_id,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&gpr, 1);
+ mem_space_id++;
+ mcd_mem_space_st cpr = {
+ .name = "CP15 Registers",
+ .id = mem_space_id,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&cpr, 1);
+ return 0;
+}
+
+int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id)
+{
+ const char *xml_filename = NULL;
+ const char *current_xml_filename = NULL;
+ const char *xml_content = NULL;
+ int i = 0;
+
+ /* 1. get correct file */
+ xml_filename = cc->gdb_core_xml_file;
+ for (i = 0; ; i++) {
+ current_xml_filename = gdb_static_features[i].xmlname;
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
+ && strlen(current_xml_filename) == strlen(xml_filename)))
+ break;
+ }
+ /* without gpr registers we can do nothing */
+ if (!current_xml_filename) {
+ return -1;
+ }
+
+ /* 2. add group for gpr registers */
+ mcd_reg_group_st gprregs = {
+ .name = "GPR Registers",
+ .id = *current_group_id
+ };
+ g_array_append_vals(reggroups, (gconstpointer)&gprregs, 1);
+ *current_group_id = *current_group_id + 1;
+
+ /* 3. parse xml */
+ /* the offset for gpr is always zero */
+ xml_content = gdb_static_features[i].xml;
+ parse_reg_xml(xml_content, strlen(xml_content), registers,
+ MCD_ARM_REG_TYPE_GPR, 0);
+ return 0;
+}
+
+int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray *reggroups,
+ GArray *registers, int *current_group_id) {
+ const char *xml_filename = NULL;
+ const char *current_xml_filename = NULL;
+ const char *xml_content = NULL;
+ uint8_t reg_type;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ /* iterate over all gdb xml files*/
+ GDBRegisterState *r;
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+
+ xml_filename = r->xml;
+ xml_content = NULL;
+
+ /* 1. get xml content */
+ if (cc->gdb_get_dynamic_xml) {
+ xml_content = cc->gdb_get_dynamic_xml(cpu, xml_filename);
+ }
+ if (xml_content) {
+ if (strcmp(xml_filename, "system-registers.xml") == 0) {
+ /* these are the coprocessor register */
+ mcd_reg_group_st corprocessorregs = {
+ .name = "CP15 Registers",
+ .id = *current_group_id
+ };
+ g_array_append_vals(reggroups,
+ (gconstpointer)&corprocessorregs, 1);
+ *current_group_id = *current_group_id + 1;
+ reg_type = MCD_ARM_REG_TYPE_CPR;
+ }
+ } else {
+ /* its not a coprocessor xml -> it is a static xml file */
+ int j = 0;
+ for (j = 0; ; j++) {
+ current_xml_filename = gdb_static_features[j].xmlname;
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
+ && strlen(current_xml_filename) == strlen(xml_filename)))
+ break;
+ }
+ if (current_xml_filename) {
+ xml_content = gdb_static_features[j].xml;
+ /* select correct reg_type */
+ if (strcmp(current_xml_filename, "arm-vfp.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename, "arm-vfp3.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename,
+ "arm-vfp-sysregs.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP_SYS;
+ } else if (strcmp(current_xml_filename,
+ "arm-neon.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename,
+ "arm-m-profile-mve.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_MVE;
+ }
+ } else {
+ continue;
+ }
+ }
+ /* 2. parse xml */
+ parse_reg_xml(xml_content, strlen(xml_content), registers, reg_type,
+ r->base_reg);
+ }
+ return 0;
+}
+
+int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu)
+{
+ mcd_reg_st *current_register;
+ uint32_t i = 0;
+
+ /* iterate over all registers */
+ for (i = 0; i < registers->len; i++) {
+ current_register = &(g_array_index(registers, mcd_reg_st, i));
+ /* add mcd_reg_group_id and mcd_mem_space_id */
+ if (strcmp(current_register->group, "cp_regs") == 0) {
+ /* coprocessor registers */
+ current_register->mcd_reg_group_id = 2;
+ current_register->mcd_mem_space_id = 6;
+ /*
+ * get info for opcode
+ * for 32bit the opcode is only 16 bit long
+ * for 64bit it is 32 bit long
+ */
+ current_register->opcode |=
+ arm_mcd_get_opcode(cpu, current_register->internal_id);
+ } else {
+ /* gpr register */
+ current_register->mcd_reg_group_id = 1;
+ current_register->mcd_mem_space_id = 5;
+ }
+ }
+ return 0;
+}
+
+uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n)
+{
+ /* TODO: not working with current build structure */
+ return 0;
+}
diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c
index d59c4ac078..48da2e043c 100644
--- a/debug/mcdstub/mcdstub.c
+++ b/debug/mcdstub/mcdstub.c
@@ -34,6 +34,7 @@
#include "mcdstub/mcd_shared_defines.h"
#include "mcdstub/mcdstub.h"
+#include "mcdstub/arm_mcdstub.h"
typedef struct {
CharBackend chr;
@@ -150,6 +151,25 @@ static CPUState *mcd_first_attached_cpu(void)
return cpu;
}
+/**
+ * mcd_get_cpu() - Returns the CPU the index i_cpu_index.
+ *
+ * @cpu_index: Index of the desired CPU.
+ */
+static CPUState *mcd_get_cpu(uint32_t cpu_index)
+{
+ CPUState *cpu = first_cpu;
+
+ while (cpu) {
+ if (cpu->cpu_index == cpu_index) {
+ return cpu;
+ }
+ cpu = mcd_next_attached_cpu(cpu);
+ }
+
+ return cpu;
+}
+
/**
* mcd_vm_state_change() - Handles a state change of the QEMU VM.
*
@@ -221,6 +241,15 @@ static int mcd_put_packet(const char *buf)
return mcd_put_packet_binary(buf, strlen(buf));
}
+/**
+ * mcd_put_strbuf() - Calls :c:func:`mcd_put_packet` with the str_buf of the
+ * mcdserver_state.
+ */
+static void mcd_put_strbuf(void)
+{
+ mcd_put_packet(mcdserver_state.str_buf->str);
+}
+
/**
* cmd_parse_params() - Extracts all parameters from a TCP packet.
*
@@ -480,6 +509,134 @@ static void handle_close_server(GArray *params, void *user_ctx)
}
}
+/**
+ * handle_gen_query() - Handler for all TCP query packets.
+ *
+ * Calls :c:func:`process_string_cmd` with all query functions in the
+ * mcd_query_cmds_table. :c:func:`process_string_cmd` then selects the correct
+ * one. This function just passes on the TCP packet data string from the
+ * parameters.
+ * @params: GArray with all TCP packet parameters.
+ */
+static void handle_gen_query(GArray *params, void *user_ctx)
+{
+ if (!params->len) {
+ return;
+ }
+ /* iterate over all possible query functions and execute the right one */
+ if (process_string_cmd(NULL, get_param(params, 0)->data,
+ mcdserver_state.mcd_query_cmds_table,
+ ARRAY_SIZE(mcdserver_state.mcd_query_cmds_table))) {
+ mcd_put_packet("");
+ }
+}
+
+/**
+ * handle_open_core() - Handler for opening a core.
+ *
+ * This function initializes all data for the core with the ID provided in
+ * the first parameter. In has a swtich case for different architectures.
+ * Currently only 32-Bit ARM is supported. The data includes memory spaces,
+ * register groups and registers themselves. They get stored into GLists where
+ * every entry in the list corresponds to one opened core.
+ * @params: GArray with all TCP packet parameters.
+ */
+static void handle_open_core(GArray *params, void *user_ctx)
+{
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcdserver_state.c_cpu = cpu;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+ int return_value = 0;
+
+ /* prepare data strucutures */
+ GArray *memspaces = g_array_new(false, true, sizeof(mcd_mem_space_st));
+ GArray *reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
+ GArray *registers = g_array_new(false, true, sizeof(mcd_reg_st));
+
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
+ /* TODO: make group and memspace ids dynamic */
+ int current_group_id = 1;
+ /* 1. store mem spaces */
+ return_value = arm_mcd_store_mem_spaces(cpu, memspaces);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 2. parse core xml */
+ return_value = arm_mcd_parse_core_xml_file(cc, reggroups,
+ registers, ¤t_group_id);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 3. parse other xmls */
+ return_value = arm_mcd_parse_general_xml_files(cpu, reggroups,
+ registers, ¤t_group_id);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 4. add additional data the the regs from the xmls */
+ return_value = arm_mcd_get_additional_register_info(reggroups,
+ registers, cpu);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 5. store all found data */
+ if (g_list_nth(mcdserver_state.all_memspaces, cpu_id)) {
+ GList *memspaces_ptr =
+ g_list_nth(mcdserver_state.all_memspaces, cpu_id);
+ memspaces_ptr->data = memspaces;
+ } else {
+ mcdserver_state.all_memspaces =
+ g_list_insert(mcdserver_state.all_memspaces, memspaces, cpu_id);
+ }
+ if (g_list_nth(mcdserver_state.all_reggroups, cpu_id)) {
+ GList *reggroups_ptr =
+ g_list_nth(mcdserver_state.all_reggroups, cpu_id);
+ reggroups_ptr->data = reggroups;
+ } else {
+ mcdserver_state.all_reggroups =
+ g_list_insert(mcdserver_state.all_reggroups, reggroups, cpu_id);
+ }
+ if (g_list_nth(mcdserver_state.all_registers, cpu_id)) {
+ GList *registers_ptr =
+ g_list_nth(mcdserver_state.all_registers, cpu_id);
+ registers_ptr->data = registers;
+ } else {
+ mcdserver_state.all_registers =
+ g_list_insert(mcdserver_state.all_registers, registers, cpu_id);
+ }
+ } else {
+ /* we don't support other architectures */
+ g_assert_not_reached();
+ }
+}
+
+/**
+ * handle_close_core() - Handler for closing a core.
+ *
+ * Frees all memory allocated for core specific information. This includes
+ * memory spaces, register groups and registers.
+ * @params: GArray with all TCP packet parameters.
+ */
+static void handle_close_core(GArray *params, void *user_ctx)
+{
+ /* free memory for correct core */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+ mcdserver_state.all_memspaces =
+ g_list_remove(mcdserver_state.all_memspaces, memspaces);
+ g_array_free(memspaces, TRUE);
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
+ mcdserver_state.all_reggroups =
+ g_list_remove(mcdserver_state.all_reggroups, reggroups);
+ g_array_free(reggroups, TRUE);
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
+ mcdserver_state.all_registers =
+ g_list_remove(mcdserver_state.all_registers, registers);
+ g_array_free(registers, TRUE);
+}
+
/**
* mcd_handle_packet() - Evaluates the type of received packet and chooses the
* correct handler.
@@ -517,6 +674,39 @@ static int mcd_handle_packet(const char *line_buf)
cmd_parser = &close_server_cmd_desc;
}
break;
+ case TCP_CHAR_QUERY:
+ {
+ static MCDCmdParseEntry query_cmd_desc = {
+ .handler = handle_gen_query,
+ };
+ query_cmd_desc.cmd = (char[2]) { TCP_CHAR_QUERY, '\0' };
+ strcpy(query_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_STRING, '\0' });
+ cmd_parser = &query_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_OPEN_CORE:
+ {
+ static MCDCmdParseEntry open_core_cmd_desc = {
+ .handler = handle_open_core,
+ };
+ open_core_cmd_desc.cmd = (char[2]) { TCP_CHAR_OPEN_CORE, '\0' };
+ strcpy(open_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &open_core_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_CLOSE_CORE:
+ {
+ static MCDCmdParseEntry close_core_cmd_desc = {
+ .handler = handle_close_core,
+ };
+ close_core_cmd_desc.cmd = (char[2]) { TCP_CHAR_CLOSE_CORE, '\0' };
+ strcpy(close_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &close_core_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -664,6 +854,49 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event)
}
}
+/**
+ * handle_query_system() - Handler for the system query.
+ *
+ * Sends the system name, which is "qemu-system".
+ * @params: GArray with all TCP packet parameters.
+ */
+static void handle_query_system(GArray *params, void *user_ctx)
+{
+ mcd_put_packet(MCD_SYSTEM_NAME);
+}
+
+/**
+ * handle_query_cores() - Handler for the core query.
+ *
+ * This function sends the type of core and number of cores currently
+ * simulated by QEMU. It also sends a device name for the MCD data structure.
+ * @params: GArray with all TCP packet parameters.
+ */
+static void handle_query_cores(GArray *params, void *user_ctx)
+{
+ /* get first cpu */
+ CPUState *cpu = mcd_first_attached_cpu();
+ if (!cpu) {
+ return;
+ }
+
+ ObjectClass *oc = object_get_class(OBJECT(cpu));
+ const char *cpu_model = object_class_get_name(oc);
+
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+
+ uint32_t nr_cores = cpu->nr_cores;
+ char device_name[ARGUMENT_STRING_LENGTH] = {0};
+ if (arch) {
+ snprintf(device_name, sizeof(device_name), "qemu-%s-device", arch);
+ }
+ g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%u.",
+ TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model,
+ TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
+ mcd_put_strbuf();
+}
+
/**
* init_query_cmds_table() - Initializes all query functions.
*
@@ -672,7 +905,24 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event)
* @mcd_query_cmds_table: Lookup table with all query commands.
*/
static void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
-{}
+{
+ /* initalizes a list of all query commands */
+ int cmd_number = 0;
+
+ MCDCmdParseEntry query_system = {
+ .handler = handle_query_system,
+ .cmd = QUERY_ARG_SYSTEM,
+ };
+ mcd_query_cmds_table[cmd_number] = query_system;
+ cmd_number++;
+
+ MCDCmdParseEntry query_cores = {
+ .handler = handle_query_cores,
+ .cmd = QUERY_ARG_CORES,
+ };
+ mcd_query_cmds_table[cmd_number] = query_cores;
+ cmd_number++;
+}
/**
* mcd_set_stop_cpu() - Sets c_cpu to the just stopped CPU.
@@ -923,3 +1173,124 @@ int mcdserver_start(const char *device)
return 0;
}
+
+void parse_reg_xml(const char *xml, int size, GArray* registers,
+ uint8_t reg_type, uint32_t reg_id_offset)
+{
+ /* iterates over the complete xml file */
+ int i, j;
+ uint32_t current_reg_id = reg_id_offset;
+ uint32_t internal_id;
+ int still_to_skip = 0;
+ char argument[64] = {0};
+ char value[64] = {0};
+ bool is_reg = false;
+ bool is_argument = false;
+ bool is_value = false;
+ GArray *reg_data;
+
+ char c;
+ char *c_ptr;
+
+ xml_attrib attribute_j;
+ const char *argument_j;
+ const char *value_j;
+
+ for (i = 0; i < size; i++) {
+ c = xml[i];
+ c_ptr = &c;
+
+ if (still_to_skip > 0) {
+ /* skip unwanted chars */
+ still_to_skip--;
+ continue;
+ }
+
+ if (strncmp(&xml[i], "<reg", 4) == 0) {
+ /* start of a register */
+ still_to_skip = 3;
+ is_reg = true;
+ reg_data = g_array_new(false, true, sizeof(xml_attrib));
+ } else if (is_reg) {
+ if (strncmp(&xml[i], "/>", 2) == 0) {
+ /* end of register info */
+ still_to_skip = 1;
+ is_reg = false;
+
+ /* create empty register */
+ mcd_reg_st my_register = (const struct mcd_reg_st){ 0 };
+
+ /* add found attribtues */
+ for (j = 0; j < reg_data->len; j++) {
+ attribute_j = g_array_index(reg_data, xml_attrib, j);
+
+ argument_j = attribute_j.argument;
+ value_j = attribute_j.value;
+
+ if (strcmp(argument_j, "name") == 0) {
+ strcpy(my_register.name, value_j);
+ } else if (strcmp(argument_j, "regnum") == 0) {
+ my_register.id = atoi(value_j);
+ } else if (strcmp(argument_j, "bitsize") == 0) {
+ my_register.bitsize = atoi(value_j);
+ } else if (strcmp(argument_j, "type") == 0) {
+ strcpy(my_register.type, value_j);
+ } else if (strcmp(argument_j, "group") == 0) {
+ strcpy(my_register.group, value_j);
+ }
+ }
+ /* add reg_type, internal_id and id*/
+ my_register.reg_type = reg_type;
+ my_register.internal_id = internal_id;
+ internal_id++;
+ if (!my_register.id) {
+ my_register.id = current_reg_id;
+ current_reg_id++;
+ } else {
+ /* set correct ID for the next register */
+ current_reg_id = my_register.id + 1;
+ }
+ /* store register */
+ g_array_append_vals(registers, (gconstpointer)&my_register, 1);
+ /* free memory */
+ g_array_free(reg_data, false);
+ } else {
+ /* store info for register */
+ switch (c) {
+ case ' ':
+ break;
+ case '=':
+ is_argument = false;
+ break;
+ case '"':
+ if (is_value) {
+ /* end of value reached */
+ is_value = false;
+ /* store arg-val combo */
+ xml_attrib current_attribute;
+ strcpy(current_attribute.argument, argument);
+ strcpy(current_attribute.value, value);
+ g_array_append_vals(reg_data,
+ (gconstpointer)¤t_attribute, 1);
+ memset(argument, 0, sizeof(argument));
+ memset(value, 0, sizeof(value));
+ } else {
+ /*start of value */
+ is_value = true;
+ }
+ break;
+ default:
+ if (is_argument) {
+ strncat(argument, c_ptr, 1);
+ } else if (is_value) {
+ strncat(value, c_ptr, 1);
+ } else {
+ is_argument = true;
+ strncat(argument, c_ptr, 1);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/debug/mcdstub/meson.build b/debug/mcdstub/meson.build
index 7e5ae878b0..3051a4e731 100644
--- a/debug/mcdstub/meson.build
+++ b/debug/mcdstub/meson.build
@@ -1,6 +1,6 @@
# only system emulation is supported over mcd
mcd_system_ss = ss.source_set()
-mcd_system_ss.add(files('mcdstub.c'))
+mcd_system_ss.add(files('mcdstub.c', 'arm_mcdstub.c'))
mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
libmcd_system = static_library('mcd_system',
diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h
index c24aaf1202..9961145f07 100644
--- a/include/mcdstub/arm_mcdstub.h
+++ b/include/mcdstub/arm_mcdstub.h
@@ -16,3 +16,88 @@
*
* SPDX-License-Identifier: LGPL-2.0+
*/
+
+#ifndef ARM_MCDSTUB_H
+#define ARM_MCDSTUB_H
+
+#include "hw/core/cpu.h"
+#include "mcdstub_common.h"
+/* just used for the register xml files */
+#include "exec/gdbstub.h"
+
+/* ids for each different type of register */
+enum {
+ MCD_ARM_REG_TYPE_GPR,
+ MCD_ARM_REG_TYPE_VFP,
+ MCD_ARM_REG_TYPE_VFP_SYS,
+ MCD_ARM_REG_TYPE_MVE,
+ MCD_ARM_REG_TYPE_CPR,
+};
+
+/**
+ * arm_mcd_store_mem_spaces() - Stores all 32-Bit ARM specific memory spaces.
+ *
+ * This function stores the memory spaces into the memspaces GArray.
+ * It only stores secure memory spaces if the CPU has more than one address
+ * space. It also stores a GPR and a CP15 register memory space.
+ * @memspaces: GArray of memory spaces.
+ * @cpu: CPU state.
+ */
+int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces);
+
+/**
+ * arm_mcd_parse_core_xml_file() - Parses the GPR registers.
+ *
+ * This function parses the core XML file, which includes the GPR registers.
+ * The regsters get stored in a GArray and a GPR register group is stored in a
+ * second GArray.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cc: The CPU class.
+ * @current_group_id: The current group ID. It increases after
+ * each group.
+ */
+int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id);
+
+/**
+ * arm_mcd_parse_general_xml_files() - Parses all but the GPR registers.
+ *
+ * This function parses all XML files except for the core XML file.
+ * The regsters get stored in a GArray and if the system-registers.xml file is
+ * parsed, it also adds a CP15 register group.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cpu: The CPU state.
+ * @current_group_id: The current group ID. It increases after
+ * each added group.
+ */
+int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
+ GArray *registers, int *current_group_id);
+
+/**
+ * arm_mcd_get_additional_register_info() - Adds additional data to parsed
+ * registers.
+ *
+ * This function is called, after :c:func:`arm_mcd_parse_core_xml_file` and
+ * :c:func:`arm_mcd_parse_general_xml_files`. It adds additional data for all
+ * already parsed registers. The registers get a correct ID, group, memory
+ * space and opcode, if they are CP15 registers.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cpu: The CPU state.
+ */
+int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu);
+
+/**
+ * arm_mcd_get_opcode() - Returns the opcode for a coprocessor register.
+ *
+ * This function uses the opc1, opc2, crm and crn members of the register to
+ * create the opcode. The formular for creating the opcode is determined by ARM.
+ * @n: The register ID of the CP register.
+ * @cs: CPU state.
+ */
+uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
+
+#endif /* ARM_MCDSTUB_H */
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 9ec9b427bd..52aa9ee18b 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -151,11 +151,6 @@ typedef struct MCDState {
/* lives in mcdstub.c */
extern MCDState mcdserver_state;
-typedef struct xml_attrib {
- char argument[ARGUMENT_STRING_LENGTH];
- char value[ARGUMENT_STRING_LENGTH];
-} xml_attrib;
-
typedef struct mcd_reset_st {
const char *name;
uint8_t id;
diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h
index b64748c080..d6ff55005e 100644
--- a/include/mcdstub/mcdstub_common.h
+++ b/include/mcdstub/mcdstub_common.h
@@ -61,4 +61,23 @@ typedef struct mcd_reg_group_st {
uint32_t id;
} mcd_reg_group_st;
+typedef struct xml_attrib {
+ char argument[ARGUMENT_STRING_LENGTH];
+ char value[ARGUMENT_STRING_LENGTH];
+} xml_attrib;
+
+/**
+ * parse_reg_xml() - Parses a GDB register XML file
+ *
+ * This fuction extracts all registers from the provided xml file and stores
+ * them into the registers GArray. It extracts the register name, bitsize, type
+ * and group if they are set.
+ * @xml: String with contents of the XML file.
+ * @registers: GArray with stored registers.
+ * @reg_type: Register type (depending on file).
+ * @size: Number of characters in the xml string.
+ */
+void parse_reg_xml(const char *xml, int size, GArray* registers,
+ uint8_t reg_type, uint32_t reg_id_offset);
+
#endif /* MCDSTUB_COMMON_H */
--
2.34.1
© 2016 - 2024 Red Hat, Inc.