From: "Alex Bennée" <alex.bennee@linaro.org>
To: Nicolas Eder <nicolas.eder@lauterbach.com>
Cc: qemu-devel@nongnu.org,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Christian Boenig" <christian.boenig@lauterbach.com>
Subject: Re: [PATCH v5 11/18] mcdstub: system and core queries added
Date: Thu, 29 Feb 2024 15:11:29 +0000 [thread overview]
Message-ID: <87plwf8fvi.fsf@draig.linaro.org> (raw)
In-Reply-To: <20231220162555.19545-12-nicolas.eder@lauterbach.com> (Nicolas Eder's message of "Wed, 20 Dec 2023 17:25:48 +0100")
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> ---
> debug/mcdstub/arm_mcdstub.c | 243 ++++++++++++++++++++
> debug/mcdstub/mcdstub.c | 370 ++++++++++++++++++++++++++++++-
> 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, 717 insertions(+), 7 deletions(-)
>
> diff --git a/debug/mcdstub/arm_mcdstub.c b/debug/mcdstub/arm_mcdstub.c
> index c24aaf1202..ce5264a617 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;
> + }
I guess this will need re-writing to use the new GDBFeature builder
which has been merged:
cc -m64 -mcx16 -Idebug/mcdstub/libmcd_system.fa.p -Idebug/mcdstub -I../../debug/mcdstub -I. -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/alex/lsrc/qemu.git/linux-headers -isystem linux-headers -iquote . -iquote /home/alex/lsrc/qemu.git -iquote /home/alex/lsrc/qemu.git/include -iquote /home/alex/lsrc/qemu.git/host/include/x86_64 -iquote /home/alex/lsrc/qemu.git/host/include/generic -iquote /home/alex/lsrc/qemu.git/tcg/i386 -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fzero-call-used-regs=used-gpr -ftrivial-auto-var-init=zero -fPIE -MD -MQ debug/mcdstub/libmcd_system.fa.p/arm_mcdstub.c.o -MF debug/mcdstub/libmcd_system.fa.p/arm_mcdstub.c.o.d -o debug/mcdstub/libmcd_system.fa.p/arm_mcdstub.c.o -c ../../debug/mcdstub/arm_mcdstub.c
../../debug/mcdstub/arm_mcdstub.c: In function ‘arm_mcd_parse_general_xml_files’:
../../debug/mcdstub/arm_mcdstub.c:171:25: error: ‘GDBRegisterState’ has no member named ‘xml’
171 | xml_filename = r->xml;
| ^~
../../debug/mcdstub/arm_mcdstub.c:175:15: error: ‘CPUClass’ has no member named ‘gdb_get_dynamic_xml’
175 | if (cc->gdb_get_dynamic_xml) {
| ^~
../../debug/mcdstub/arm_mcdstub.c:176:29: error: ‘CPUClass’ has no member named ‘gdb_get_dynamic_xml’
176 | xml_content = cc->gdb_get_dynamic_xml(cpu, xml_filename);
| ^~
Hopefully the code can be more generic now and avoid having to re-parse
generated xml.
> + /* 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 = 0;
> + 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 45daa38689..4095b3f8ce 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.
> @@ -516,6 +673,36 @@ 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,
> + .cmd = {TCP_CHAR_QUERY, '\0'},
> + .schema = {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,
> + .cmd = {TCP_CHAR_OPEN_CORE, '\0'},
> + .schema = {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,
> + .cmd = {TCP_CHAR_CLOSE_CORE, '\0'},
> + .schema = {ARG_SCHEMA_CORENUM, '\0'},
> + };
> + cmd_parser = &close_core_cmd_desc;
> + }
> + break;
> default:
> /* command not supported */
> mcd_put_packet("");
> @@ -663,6 +850,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.
> *
> @@ -671,7 +901,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.
> @@ -924,3 +1171,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 = 0;
> + 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 = NULL;
> +
> + 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 26aa33c0e3..ac14b2cda8 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 */
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
next prev parent reply other threads:[~2024-02-29 15:11 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-20 16:25 [PATCH v5 00/18] first version of mcdstub Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 01/18] gdbstub, mcdstub: file and build structure adapted to accomodate for the mcdstub Nicolas Eder
2024-02-29 15:33 ` Alex Bennée
2023-12-20 16:25 ` [PATCH v5 02/18] gdbstub: hex conversion functions moved to cutils.h Nicolas Eder
2024-02-29 15:33 ` Alex Bennée
2023-12-20 16:25 ` [PATCH v5 03/18] gdbstub: GDBRegisterState moved to gdbstub.h so it can be used outside of the gdbstub Nicolas Eder
2024-02-29 15:23 ` Alex Bennée
2023-12-20 16:25 ` [PATCH v5 04/18] gdbstub: DebugClass added to system mode Nicolas Eder
2024-02-29 16:35 ` Alex Bennée
2024-03-05 11:27 ` nicolas.eder
2023-12-20 16:25 ` [PATCH v5 05/18] mcdstub: memory helper functions added Nicolas Eder
2024-02-29 16:56 ` Alex Bennée
2024-03-05 11:03 ` nicolas.eder
2023-12-20 16:25 ` [PATCH v5 06/18] mcdstub: -mcd start option added, mcd specific defines added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 07/18] mcdstub: mcdserver initialization functions added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 08/18] cutils: qemu_strtou32 function added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 09/18] mcdstub: TCP packet plumbing added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 10/18] mcdstub: open and close server functions added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 11/18] mcdstub: system and core queries added Nicolas Eder
2024-02-29 15:11 ` Alex Bennée [this message]
2024-03-05 11:08 ` nicolas.eder
2023-12-20 16:25 ` [PATCH v5 12/18] mcdstub: all core specific " Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 13/18] mcdstub: go, step and break added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 14/18] mcdstub: state query added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 15/18] mcdstub: skeleton for reset handling added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 16/18] mcdstub: register access added Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 17/18] mcdstub: memory " Nicolas Eder
2023-12-20 16:25 ` [PATCH v5 18/18] mcdstub: break/watchpoints added Nicolas Eder
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87plwf8fvi.fsf@draig.linaro.org \
--to=alex.bennee@linaro.org \
--cc=christian.boenig@lauterbach.com \
--cc=nicolas.eder@lauterbach.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.