On Wed, 30 Apr 2025 08:27, Mario Fleischmann <mario.fleischm...@lauterbach.com> 
wrote:
>Support three main memory space types:
>
>* Physical memory
>* Logical memory (MMU)
>* GDB Registers
>
>Use custom memory type to mark memory spaces as secure
>
>V=1 QTEST_QEMU_BINARY="./qemu-system-arm -M virt,secure=on -cpu cortex-a15" 
>tests/qtest/mcd-test
>
>Signed-off-by: Mario Fleischmann <mario.fleischm...@lauterbach.com>
>---
> mcd/mcd_qapi.c         |  22 +++++
> mcd/mcd_qapi.h         |   2 +
> mcd/mcd_server.c       | 199 ++++++++++++++++++++++++++++++++++-------
> mcd/mcd_stub.c         |  44 +++++++++
> qapi/mcd.json          | 199 +++++++++++++++++++++++++++++++++++++++++
> tests/qtest/mcd-test.c |  79 ++++++++++++++++
> tests/qtest/mcd-util.c |  20 +++++
> tests/qtest/mcd-util.h |   3 +
> 8 files changed, 534 insertions(+), 34 deletions(-)
>
>diff --git a/mcd/mcd_qapi.c b/mcd/mcd_qapi.c
>index a1122f2..85428e2 100644
>--- a/mcd/mcd_qapi.c
>+++ b/mcd/mcd_qapi.c
>@@ -125,3 +125,25 @@ mcd_core_con_info_st 
>unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info)
> 
>     return unmarshal;
> }
>+
>+MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space)
>+{
>+    MCDMemspace *marshal = g_malloc0(sizeof(*marshal));
>+
>+    *marshal = (MCDMemspace) {
>+        .mem_space_id = mem_space->mem_space_id,
>+        .mem_space_name = g_strdup(mem_space->mem_space_name),
>+        .mem_type = mem_space->mem_type,
>+        .bits_per_mau = mem_space->bits_per_mau,
>+        .invariance = mem_space->invariance,
>+        .endian = mem_space->endian,
>+        .min_addr = mem_space->min_addr,
>+        .max_addr = mem_space->max_addr,
>+        .num_mem_blocks = mem_space->num_mem_blocks,
>+        .supported_access_options = mem_space->supported_access_options,
>+        .core_mode_mask_read = mem_space->core_mode_mask_read,
>+        .core_mode_mask_write = mem_space->core_mode_mask_write,
>+    };
>+
>+    return marshal;
>+}
>diff --git a/mcd/mcd_qapi.h b/mcd/mcd_qapi.h
>index 45b3ac4..822870c 100644
>--- a/mcd/mcd_qapi.h
>+++ b/mcd/mcd_qapi.h
>@@ -25,6 +25,8 @@ MCDServerInfo *marshal_mcd_server_info(const 
>mcd_server_info_st *server_info);
> 
> MCDCoreConInfo *marshal_mcd_core_con_info(const mcd_core_con_info_st 
> *con_info);
> 
>+MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space);
>+
> 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/mcd_server.c b/mcd/mcd_server.c
>index 83ffa4f..77b28cf 100644
>--- a/mcd/mcd_server.c
>+++ b/mcd/mcd_server.c
>@@ -12,6 +12,10 @@
> #include "qemu/cutils.h"
> #include "mcd_api.h"
> #include "hw/boards.h"
>+#include "exec/tswap.h"
>+
>+/* Custom memory space type */
>+static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000;
> 
> static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = {
>     .return_status = MCD_RET_ACT_HANDLE_ERROR,
>@@ -48,37 +52,45 @@ static const mcd_error_info_st MCD_ERROR_NONE = {
>     .error_str = "",
> };
> 
>-/* reserves memory for custom errors */
>-static mcd_error_info_st custom_mcd_error;
>-
> /**
>  * struct mcdcore_state - State of a core.
>  *
>- * @last_error: Error info of most recent executed function.
>- * @info:       Core connection information.
>- * @open_core:  Open core instance as allocated in mcd_open_core_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().
>  *
>  * MCD is mainly being used on the core level:
>  * After the initial query functions, a core connection is opened in
>  * mcd_open_core_f(). The allocated mcd_core_st instance is then the basis
>  * of subsequent operations.
>+ *
>+ * @cpu is the internal CPU handle through which core specific debug
>+ * functions are implemented.
>  */
> typedef struct mcdcore_state {
>     const mcd_error_info_st *last_error;
>+    mcd_error_info_st custom_error;

This patch LGTM overall (though I'm still not familiar with MCD itself, 
it's new to me) but this change feels unrelated to this patch. Maybe 
introduce custom_error field back in the patch that adds mcdcore_state 
and don't create the custom_mcd_error static in the first place? This'd 
also reduce the amount of diff lines in patches.

This is just a suggestion, I realise it means more work for you, so feel 
free to ignore it.

>     mcd_core_con_info_st info;
>     mcd_core_st *open_core;
>+    CPUState *cpu;
>+    GArray *memory_spaces;
> } mcdcore_state;
> 
> /**
>  * struct mcdserver_state - State of the MCD server
>  *
>- * @last_error:  Error info of most recent executed function.
>- * @open_server: Open server instance as allocated in mcd_open_server_f().
>- * @system_key:  System key as provided in mcd_open_server_f()
>- * @cores:       Internal core information database.
>+ * @last_error:   Error info of most recent executed function.
>+ * @custom_error: Reserves memory for custom MCD errors.
>+ * @open_server:  Open server instance as allocated in mcd_open_server_f().
>+ * @system_key:   System key as provided in mcd_open_server_f()
>+ * @cores:        Internal core information database.
>  */
> typedef struct mcdserver_state {
>     const mcd_error_info_st *last_error;
>+    mcd_error_info_st custom_error;
>     mcd_server_st *open_server;
>     char system_key[MCD_KEY_LEN];
>     GArray *cores;
>@@ -134,13 +146,13 @@ mcd_return_et mcd_initialize_f(const mcd_api_version_st 
>*version_req,
>         version_req->v_api_minor <= MCD_API_VER_MINOR) {
>         g_server_state.last_error = &MCD_ERROR_NONE;
>     } else {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_GENERAL,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "incompatible versions",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>     }
> 
>     return g_server_state.last_error->return_status;
>@@ -160,13 +172,13 @@ mcd_return_et mcd_qry_servers_f(const char *host, bool 
>running,
>                                 mcd_server_info_st *server_info)
> {
>     if (start_index >= 1) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_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 = "QEMU only has one MCD server",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -214,13 +226,13 @@ mcd_return_et mcd_open_server_f(const char *system_key,
>     CPUState *cpu;
> 
>     if (g_server_state.open_server) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_CONNECTION,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "server already open",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -253,6 +265,8 @@ mcd_return_et mcd_open_server_f(const char *system_key,
>             },
>             .last_error = &MCD_ERROR_NONE,
>             .open_core = NULL,
>+            .cpu = cpu,
>+            .memory_spaces = g_array_new(false, true, 
>sizeof(mcd_memspace_st)),
>         };
>         pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model);
>         g_array_append_val(g_server_state.cores, c);
>@@ -265,24 +279,24 @@ mcd_return_et mcd_open_server_f(const char *system_key,
> mcd_return_et mcd_close_server_f(const mcd_server_st *server)
> {
>     if (!g_server_state.open_server) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_CONNECTION,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "server not open",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>     if (server != g_server_state.open_server) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_CONNECTION,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "unknown server",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -333,13 +347,13 @@ mcd_return_et mcd_qry_systems_f(uint32_t start_index, 
>uint32_t *num_systems,
>     }
> 
>     if (start_index >= 1) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_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 = "QEMU only emulates one system",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -381,13 +395,13 @@ mcd_return_et mcd_qry_devices_f(const 
>mcd_core_con_info_st *system_con_info,
>     }
> 
>     if (start_index >= 1) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_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 = "QEMU only emulates one machine",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -431,13 +445,13 @@ mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st 
>*connection_info,
>     }
> 
>     if (start_index >= g_server_state.cores->len) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_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 cores",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -471,6 +485,59 @@ mcd_return_et mcd_qry_core_modes_f(const mcd_core_st 
>*core,
>     return g_server_state.last_error->return_status;
> }
> 
>+static mcd_return_et query_memspaces(mcdcore_state *core_state)
>+{
>+    g_array_set_size(core_state->memory_spaces, 0);
>+
>+    mcd_endian_et endian = target_big_endian() ? MCD_ENDIAN_BIG
>+                                               : MCD_ENDIAN_LITTLE;
>+
>+    for (uint32_t i = 0; i < core_state->cpu->num_ases; i++) {
>+        AddressSpace *as = cpu_get_address_space(core_state->cpu, i);
>+
>+        int secure_flag = 0;
>+        if (core_state->cpu->num_ases > 1) {
>+            int sid = cpu_asidx_from_attrs(core_state->cpu,
>+                                           (MemTxAttrs) { .secure = 1 });
>+            if (i == sid) {
>+                secure_flag = MCD_MEM_SPACE_IS_SECURE;
>+            }
>+        }
>+
>+        const char *as_name = as->name;
>+        const char *mr_name = as->root->name;
>+
>+        mcd_memspace_st physical = {
>+            /* mem space ID 0 is reserved */
>+            .mem_space_id = core_state->memory_spaces->len + 1,
>+            .mem_type = MCD_MEM_SPACE_IS_PHYSICAL | secure_flag,
>+            .endian = endian,
>+        };
>+        strncpy(physical.mem_space_name, mr_name, MCD_MEM_SPACE_NAME_LEN - 1);
>+
>+        g_array_append_val(core_state->memory_spaces, physical);
>+
>+        mcd_memspace_st logical = {
>+            .mem_space_id = core_state->memory_spaces->len + 1,
>+            .mem_type = MCD_MEM_SPACE_IS_LOGICAL | secure_flag,
>+            .endian = endian,
>+        };
>+        strncpy(logical.mem_space_name, as_name, MCD_MEM_SPACE_NAME_LEN - 1);
>+
>+        g_array_append_val(core_state->memory_spaces, logical);
>+    }
>+
>+    mcd_memspace_st gdb_registers = {
>+        .mem_space_id = core_state->memory_spaces->len + 1,
>+        .mem_space_name = "GDB Registers",
>+        .mem_type = MCD_MEM_SPACE_IS_REGISTERS,
>+        .endian = endian,
>+    };
>+    g_array_append_val(core_state->memory_spaces, gdb_registers);
>+
>+    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)
> {
>@@ -490,25 +557,29 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st 
>*core_con_info,
> 
>     core_id = core_con_info->core_id;
>     if (core_id > g_server_state.cores->len) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_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 = "specified core index exceeds the number of cores",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>     core_state = &g_array_index(g_server_state.cores, mcdcore_state, core_id);
>     if (core_state->open_core) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_CONNECTION,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "core already open",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>+        return g_server_state.last_error->return_status;
>+    }
>+
>+    if (query_memspaces(core_state) != MCD_RET_ACT_NONE) {
>         return g_server_state.last_error->return_status;
>     }
> 
>@@ -540,19 +611,21 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core)
>     }
> 
>     if (core_state->open_core != core) {
>-        custom_mcd_error = (mcd_error_info_st) {
>+        g_server_state.custom_error = (mcd_error_info_st) {
>             .return_status = MCD_RET_ACT_HANDLE_ERROR,
>             .error_code = MCD_ERR_CONNECTION,
>             .error_events = MCD_ERR_EVT_NONE,
>             .error_str = "core not open",
>         };
>-        g_server_state.last_error = &custom_mcd_error;
>+        g_server_state.last_error = &g_server_state.custom_error;
>         return g_server_state.last_error->return_status;
>     }
> 
>     g_free((void *)core->core_con_info);
>     g_free((void *)core);
>     core_state->open_core = NULL;
>+    core_state->cpu = NULL;
>+    g_array_set_size(core_state->memory_spaces, 0);
> 
>     g_server_state.last_error = &MCD_ERROR_NONE;
>     return g_server_state.last_error->return_status;
>@@ -613,8 +686,66 @@ mcd_return_et mcd_qry_mem_spaces_f(const mcd_core_st 
>*core,
>                                    uint32_t *num_mem_spaces,
>                                    mcd_memspace_st *mem_spaces)
> {
>-    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_mem_spaces) {
>+        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->memory_spaces);
>+
>+    if (core_state->memory_spaces->len == 0) {
>+        core_state->custom_error = (mcd_error_info_st) {
>+            .return_status = MCD_RET_ACT_HANDLE_ERROR,
>+            .error_code = MCD_ERR_NO_MEM_SPACES,
>+            .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_mem_spaces == 0) {
>+        *num_mem_spaces = core_state->memory_spaces->len;
>+        core_state->last_error = &MCD_ERROR_NONE;
>+        return core_state->last_error->return_status;
>+    }
>+
>+    if (start_index >= core_state->memory_spaces->len) {

The first memory space gets an index of len + 1 == 1, since it's 
mentioned earlier that 0 is reserved, so if start_index is 1 should we 
not be failing here? Or am I misunderstanding something? Is start_index 
0-based and mem_space_id 1-based?

>+        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 memory spaces",
>+        };
>+        core_state->last_error = &core_state->custom_error;
>+        return core_state->last_error->return_status;
>+    }
>+
>+    if (!mem_spaces) {
>+        core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM;
>+        return core_state->last_error->return_status;
>+    }
>+
>+    for (i = 0; i < *num_mem_spaces &&
>+         start_index + i < core_state->memory_spaces->len; i++) {
>+
>+        mem_spaces[i] = g_array_index(core_state->memory_spaces,
>+                                      mcd_memspace_st, start_index + i);
>+    }
>+
>+    *num_mem_spaces = i;
>+
>+    core_state->last_error = &MCD_ERROR_NONE;
>+    return core_state->last_error->return_status;
> }
> 
> mcd_return_et mcd_qry_mem_blocks_f(const mcd_core_st *core,
>diff --git a/mcd/mcd_stub.c b/mcd/mcd_stub.c
>index c49fcb4..5d749c4 100644
>--- a/mcd/mcd_stub.c
>+++ b/mcd/mcd_stub.c
>@@ -379,3 +379,47 @@ MCDErrorInfo *qmp_mcd_qry_error_info(uint32_t core_uid, 
>Error **errp)
>     result = marshal_mcd_error_info(&error_info);
>     return result;
> }
>+
>+MCDQryMemSpacesResult *qmp_mcd_qry_mem_spaces(uint32_t core_uid,
>+                                              uint32_t start_index,
>+                                              uint32_t num_mem_spaces,
>+                                              Error **errp)
>+{
>+    MCDMemspaceList **tailp;
>+    MCDMemspace *ms;
>+    mcd_memspace_st *memspaces = NULL;
>+    bool query_num_only = num_mem_spaces == 0;
>+    MCDQryMemSpacesResult *result = g_malloc0(sizeof(*result));
>+    mcd_core_st *core = NULL;
>+
>+    if (retrieve_open_core(core_uid, &core) != MCD_RET_ACT_NONE) {
>+        g_stub_state.on_error_ask_server = false;
>+    }
>+
>+    if (!query_num_only) {
>+        memspaces = g_malloc0(num_mem_spaces * sizeof(*memspaces));
>+    }
>+
>+    result->return_status = mcd_qry_mem_spaces_f(core, start_index,
>+                                                 &num_mem_spaces, memspaces);
>+
>+    if (result->return_status == MCD_RET_ACT_NONE) {
>+        result->has_num_mem_spaces = true;
>+        result->num_mem_spaces = num_mem_spaces;
>+        if (!query_num_only) {
>+            result->has_mem_spaces = true;
>+            tailp = &(result->mem_spaces);
>+            for (uint32_t i = 0; i < num_mem_spaces; i++) {
>+                ms = marshal_mcd_memspace(memspaces + i);
>+                QAPI_LIST_APPEND(tailp, ms);
>+            }
>+        }
>+    }
>+
>+    if (!query_num_only) {
>+        g_free(memspaces);

Who is responsible for freeing result and memspaces (if 
(query_num_only)) in this function? Could you accompany every g_malloc* 
with a comment that explains the resource's lifetime?


>+    }
>+
>+    g_stub_state.on_error_ask_server = true;
>+    return result;
>+}
>diff --git a/qapi/mcd.json b/qapi/mcd.json
>index 7219056..214933e 100644
>--- a/qapi/mcd.json
>+++ b/qapi/mcd.json
>@@ -147,6 +147,74 @@
>     'core-id'        : 'uint32' } }
> 
> 
>+##
>+# @MCDMemspace:
>+#
>+# Structure type containing information about a memory space.
>+#
>+# @mem-space-id:             ID of this memory space, ID 0 is reserved.
>+# @mem-space-name:           Unique name of the memory space.
>+# @mem-type:                 Type of the memory space.
>+# @bits-per-mau:             Bits per minimum addressable unit (MAU). The
>+#                            minimum addressable unit of a memory is defined 
>as
>+#                            the size in bits of its basic block that may have
>+#                            a unique address. For example for a byte
>+#                            addressable memory this value would be set to '8'
>+#                            according to the 8 bits of a byte block.
>+# @invariance:               The total number of bytes in a memory word, which
>+#                            is @bits-per-mau divided by 8, consists of groups
>+#                            of "invariant" bytes. These groups can be 
>arranged
>+#                            in Big Endian or Little Endian order.
>+#                            For example an @invariance of '2' and '64'
>+#                            @bits-per-mau, a Little Endian word are
>+#                            represented as b0 b1 b2 b3 b4 b5 b6 b7.
>+#                            In contrast to this, a Big Endian word is
>+#                            represented as b6 b7 b4 b5 b2 b3 b0 b1.
>+# @endian:                   Endianness of this memory space. Can be overriden
>+#                            by @endian of a MCDMemblock.
>+# @min-addr:                 Minimum address of this memory space.
>+# @max-addr:                 Maximum address of this memory space.
>+# @num-mem-blocks:           Number of memory blocks in this memory space. 
>Each
>+#                            memory space may have a certain number of memory
>+#                            blocks. Memory blocks contain additional
>+#                            information pertaining to the intended purpose of
>+#                            the memory. This information may be used as a 
>hint
>+#                            for memory data representation within a tool's
>+#                            memory view. This field specifies the number of
>+#                            memory blocks present in this memory space.
>+# @supported-access-options: Supported memory access options (OR'ed bitmask).
>+#                            Can be overriden by @supported-access-options of 
>a
>+#                            MCDMemblock.
>+# @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'. Can 
>be
>+#                            overriden by @core-mode-mask-read of a 
>MCDMemblock.
>+# @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'.
>+#                            Can be overriden by
>+#                            @core-mode-mask-write of a MCDMemblock.
>+#
>+# Since: 9.1
>+##
>+{ 'struct': 'MCDMemspace',
>+  'data': {
>+    'mem-space-id'            : 'uint32',
>+    'mem-space-name'          : 'str',
>+    'mem-type'                : 'uint32',
>+    'bits-per-mau'            : 'uint32',
>+    'invariance'              : 'uint8',
>+    'endian'                  : 'uint32',
>+    'min-addr'                : 'uint64',
>+    'max-addr'                : 'uint64',
>+    'num-mem-blocks'          : 'uint32',
>+    'supported-access-options': 'uint32',
>+    'core-mode-mask-read'     : 'uint32',
>+    'core-mode-mask-write'    : 'uint32' } }
>+
>+
> ##
> # == Target Initialization API
> ##
>@@ -878,3 +946,134 @@
> { 'command': 'mcd-qry-error-info',
>   'data': { 'core-uid': 'uint32' },
>   'returns': 'MCDErrorInfo' }
>+
>+
>+##
>+# @MCDQryMemSpacesResult:
>+#
>+# Return value of @mcd-qry-mem-spaces.
>+#
>+# @return-status:  Return code.
>+# @num-mem-spaces: The number of returned memory spaces. In case the input 
>value
>+#                  of @num-mem-spaces is '0', this is the number of all
>+#                  available memory spaces for the selected core.
>+# @mem-spaces:     Memory space information.
>+#
>+# Since: 9.1
>+##
>+{ 'struct': 'MCDQryMemSpacesResult',
>+  'data': {
>+    'return-status'  : 'uint32',
>+    '*num-mem-spaces': 'uint32',
>+    '*mem-spaces'    : [ 'MCDMemspace' ] }}
>+
>+##
>+# @mcd-qry-mem-spaces:
>+#
>+# Function querying the available memory spaces for a particular component.
>+#
>+# @core-uid:       Unique identifier of the open core as returned by
>+#                  @mcd-open-core.
>+# @start-index:    Start index of the requested memory spaces. This refers to
>+#                  an internal list of the target side implementation.
>+# @num-mem-spaces: Number of memory spaces, information is requested of. If it
>+#                  is set to '0', no memory space information is returned but
>+#                  the number of all available memory spaces for the selected
>+#                  core.
>+#
>+# Returns: @MCDQryMemSpacesResult
>+#
>+# Since: 9.1
>+#
>+# .. qmp-example::
>+#    :title: Arm TrustZone
>+#
>+#     -> { "execute": "mcd-qry-mem-spaces",
>+#          "arguments": { "core-uid": 1,
>+#                         "start-index": 0,
>+#                         "num-mem-spaces": 20 } }
>+#     <- {
>+#          "return": {
>+#              "mem-spaces": [
>+#                  {
>+#                      "mem-space-id": 1,
>+#                      "bits-per-mau": 0,
>+#                      "mem-space-name": "system",
>+#                      "endian": 0,
>+#                      "max-addr": 0,
>+#                      "mem-type": 16,
>+#                      "core-mode-mask-write": 0,
>+#                      "core-mode-mask-read": 0,
>+#                      "supported-access-options": 0,
>+#                      "invariance": 0,
>+#                      "num-mem-blocks": 0,
>+#                      "min-addr": 0
>+#                  },
>+#                  {
>+#                      "mem-space-id": 2,
>+#                      "bits-per-mau": 0,
>+#                      "mem-space-name": "cpu-memory-0",
>+#                      "endian": 0,
>+#                      "max-addr": 0,
>+#                      "mem-type": 32,
>+#                      "core-mode-mask-write": 0,
>+#                      "core-mode-mask-read": 0,
>+#                      "supported-access-options": 0,
>+#                      "invariance": 0,
>+#                      "num-mem-blocks": 0,
>+#                      "min-addr": 0
>+#                  },
>+#                  {
>+#                      "mem-space-id": 3,
>+#                      "bits-per-mau": 0,
>+#                      "mem-space-name": "secure-memory",
>+#                      "endian": 0,
>+#                      "max-addr": 0,
>+#                      "mem-type": 65552,
>+#                      "core-mode-mask-write": 0,
>+#                      "core-mode-mask-read": 0,
>+#                      "supported-access-options": 0,
>+#                      "invariance": 0,
>+#                      "num-mem-blocks": 0,
>+#                      "min-addr": 0
>+#                  },
>+#                  {
>+#                      "mem-space-id": 4,
>+#                      "bits-per-mau": 0,
>+#                      "mem-space-name": "cpu-secure-memory-0",
>+#                      "endian": 0,
>+#                      "max-addr": 0,
>+#                      "mem-type": 65568,
>+#                      "core-mode-mask-write": 0,
>+#                      "core-mode-mask-read": 0,
>+#                      "supported-access-options": 0,
>+#                      "invariance": 0,
>+#                      "num-mem-blocks": 0,
>+#                      "min-addr": 0
>+#                  },
>+#                  {
>+#                      "mem-space-id": 5,
>+#                      "bits-per-mau": 0,
>+#                      "mem-space-name": "GDB Registers",
>+#                      "endian": 0,
>+#                      "max-addr": 0,
>+#                      "mem-type": 1,
>+#                      "core-mode-mask-write": 0,
>+#                      "core-mode-mask-read": 0,
>+#                      "supported-access-options": 0,
>+#                      "invariance": 0,
>+#                      "num-mem-blocks": 0,
>+#                      "min-addr": 0
>+#                  }
>+#              ],
>+#              "return-status": 0,
>+#              "num-mem-spaces": 5
>+#          }
>+#        }
>+##
>+{ 'command': 'mcd-qry-mem-spaces',
>+  'data': {
>+     'core-uid'      : 'uint32',
>+     'start-index'   : 'uint32',
>+     'num-mem-spaces': 'uint32' },
>+  'returns': 'MCDQryMemSpacesResult' }
>diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c
>index 9596309..b63a905 100644
>--- a/tests/qtest/mcd-test.c
>+++ b/tests/qtest/mcd-test.c
>@@ -399,6 +399,84 @@ static void test_open_core(void)
>     mcdtest_quit(&qts);
> }
> 
>+static void test_qry_core_info(void)
>+{
>+    QTestStateMCD qts = mcdtest_init(QEMU_EXTRA_ARGS);
>+    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_qry_mem_spaces_arg qry_mem_spaces_args;
>+        q_obj_mcd_close_core_arg close_core_args;
>+        MCDQryMemSpacesResult *qry_mem_spaces_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,
>+        };
>+        MCDOpenCoreResult *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);
>+
>+        if (verbose) {
>+            fprintf(stderr, "[INFO]\tCore %s #%d\n",
>+                                core_con_info->core,
>+                                core_con_info->core_id);
>+        }
>+
>+        qry_mem_spaces_args = (q_obj_mcd_qry_mem_spaces_arg) {
>+            .core_uid = open_core_result->core_uid,
>+            .start_index = 0,
>+            .num_mem_spaces = 0,
>+        };
>+
>+        qry_mem_spaces_result = qtest_mcd_qry_mem_spaces(&qts,
>+                                                         
>&qry_mem_spaces_args);
>+        g_assert(qry_mem_spaces_result->return_status == MCD_RET_ACT_NONE);
>+        g_assert(qry_mem_spaces_result->has_num_mem_spaces);
>+        g_assert(qry_mem_spaces_result->num_mem_spaces > 0);
>+
>+        qry_mem_spaces_args.num_mem_spaces =
>+            qry_mem_spaces_result->num_mem_spaces;
>+        qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_result);
>+        qry_mem_spaces_result = qtest_mcd_qry_mem_spaces(&qts,
>+                                                         
>&qry_mem_spaces_args);
>+        g_assert(qry_mem_spaces_result->return_status == MCD_RET_ACT_NONE);
>+        g_assert(qry_mem_spaces_result->has_num_mem_spaces);
>+
>+        if (verbose) {
>+            MCDMemspaceList *ms_head = qry_mem_spaces_result->mem_spaces;
>+            for (uint32_t i = 0;
>+                 i < qry_mem_spaces_result->num_mem_spaces; i++) {
>+                MCDMemspace *ms = ms_head->value;
>+                if (verbose) {
>+                    fprintf(stderr, "\tMemory Space: %s (#%d)\n"
>+                                    "\t              Type: 0x%x\n",
>+                                    ms->mem_space_name,
>+                                    ms->mem_space_id,
>+                                    ms->mem_type);
>+                }
>+                ms_head = ms_head->next;
>+            }
>+        }
>+
>+        qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_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);
>+
>+        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);
>+    mcdtest_quit(&qts);
>+}
>+
> int main(int argc, char *argv[])
> {
>     char *v_env = getenv("V");
>@@ -411,5 +489,6 @@ int main(int argc, char *argv[])
>     qtest_add_func("mcd/open-server", test_open_server);
>     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);
>     return g_test_run();
> }
>diff --git a/tests/qtest/mcd-util.c b/tests/qtest/mcd-util.c
>index 53694d9..225cbad 100644
>--- a/tests/qtest/mcd-util.c
>+++ b/tests/qtest/mcd-util.c
>@@ -269,3 +269,23 @@ MCDCloseCoreResult *qtest_mcd_close_core(QTestStateMCD 
>*qts,
> 
>     return unmarshal;
> }
>+
>+MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(
>+    QTestStateMCD *qts, q_obj_mcd_qry_mem_spaces_arg *args)
>+{
>+    Visitor *v;
>+    QObject *marshal;
>+    QDict *arg, *resp;
>+    QObject *ret;
>+    bool ok;
>+    MCDQryMemSpacesResult *unmarshal;
>+
>+    MARSHAL_ARGS(q_obj_mcd_qry_mem_spaces_arg);
>+
>+    resp = qtest_mcd(qts, "{'execute': 'mcd-qry-mem-spaces',"
>+                          "'arguments': %p}", arg);
>+
>+    UNMARSHAL_RESULT(MCDQryMemSpacesResult);
>+
>+    return unmarshal;
>+}
>diff --git a/tests/qtest/mcd-util.h b/tests/qtest/mcd-util.h
>index 5e7c3ca..bff9600 100644
>--- a/tests/qtest/mcd-util.h
>+++ b/tests/qtest/mcd-util.h
>@@ -51,4 +51,7 @@ MCDOpenCoreResult *qtest_mcd_open_core(QTestStateMCD *qts,
> MCDCloseCoreResult *qtest_mcd_close_core(QTestStateMCD *qts,
>                                          q_obj_mcd_close_core_arg *args);
> 
>+MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(QTestStateMCD *qts,
>+    q_obj_mcd_qry_mem_spaces_arg *args);
>+
> #endif /* TEST_MCD_UTILS_H */
>-- 
>2.34.1
>
>

--
Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd

Reply via email to