Just found out that in the call stack of address_space_rw, the len
argument eventually becomes the access width, if applicable. I wasn't
aware of that because GDB's 'm' and 'M' packets don't pose any
requirements on the access width ("the stub is free to use byte
accesses, or not") and therefore the gdbstub couldn't make advantage of
that.
MCD does have the field tx->access_width, so a v2 of this patch will
call the memory access functions repeatedly, with
len = tx->access_width (if set)
On 10.03.2025 16:11, Mario Fleischmann wrote:
> In MCD, all accesses to register or memory are issued over transaction lists.
> This commit implements three types of transactions:
>
> * register access
> * logical memory access (with MMU)
> * physical memory access (no MMU)
>
> Signed-off-by: Mario Fleischmann <mario.fleischm...@lauterbach.com>
> ---
> mcd/libmcd_qapi.c | 128 +++++++++++++++++++++++++++++++++
> mcd/libmcd_qapi.h | 14 ++++
> mcd/mcdserver.c | 176 ++++++++++++++++++++++++++++++++++++++++++++-
> mcd/mcdstub_qapi.c | 26 +++++++
> qapi/mcd.json | 83 +++++++++++++++++++++
> 5 files changed, 425 insertions(+), 2 deletions(-)
>
> [...]
>
> diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c
> index 116fbfaa30..837c0276e7 100644
> --- a/mcd/mcdserver.c
> +++ b/mcd/mcdserver.c
> @@ -1081,11 +1081,183 @@ mcd_return_et mcd_qry_trig_set_state_f(const
> mcd_core_st *core,
> return g_server_state.last_error->return_status;
> }
>
> +static mcd_return_et execute_memory_tx(mcdcore_state *core_state, mcd_tx_st
> *tx,
> + mcd_mem_type_et type)
> +{
> + MemTxResult result;
> +
> + /* each address space has one physical and one virtual memory */
> + int address_space_id = (tx->addr.mem_space_id - 1) / 2;
> + AddressSpace *as = cpu_get_address_space(core_state->cpu,
> address_space_id);
> +
> + hwaddr addr = tx->addr.address;
> + hwaddr len = tx->num_bytes;
> + void *buf = tx->data;
> + bool is_write;
> +
> + if (tx->access_type == MCD_TX_AT_R) {
> + is_write = false;
> + } else if (tx->access_type == MCD_TX_AT_W) {
> + is_write = true;
> + } else {
> + core_state->custom_error = (mcd_error_info_st) {
> + .return_status = MCD_RET_ACT_HANDLE_ERROR,
> + .error_code = MCD_ERR_TXLIST_TX,
> + .error_events = MCD_ERR_EVT_NONE,
> + .error_str = "tx access type not supported",
> + };
> + core_state->last_error = &core_state->custom_error;
> + return core_state->last_error->return_status;
> + }
> +
> + if (type & MCD_MEM_SPACE_IS_PHYSICAL) {
> + MemTxAttrs attrs = {
> + .secure = !!(type & MCD_MEM_SPACE_IS_SECURE),
> + .space = address_space_id,
> + };
> + result = address_space_rw(as, addr, attrs, buf, len, is_write);
> + } else if (type & MCD_MEM_SPACE_IS_LOGICAL) {
> + int ret = cpu_memory_rw_debug(core_state->cpu, addr, buf, len,
> + is_write);
> + result = (ret == 0) ? MEMTX_OK : MEMTX_ERROR;
> + } else {
> + core_state->custom_error = (mcd_error_info_st) {
> + .return_status = MCD_RET_ACT_HANDLE_ERROR,
> + .error_code = MCD_ERR_TXLIST_TX,
> + .error_events = MCD_ERR_EVT_NONE,
> + .error_str = "unknown mem space type",
> + };
> + core_state->last_error = &core_state->custom_error;
> + return core_state->last_error->return_status;
> + }
> +
> + if (result != MEMTX_OK) {
> + core_state->custom_error = (mcd_error_info_st) {
> + .return_status = MCD_RET_ACT_HANDLE_ERROR,
> + .error_code = is_write ? MCD_ERR_TXLIST_WRITE :
> MCD_ERR_TXLIST_READ,
> + .error_events = MCD_ERR_EVT_NONE,
> + .error_str = "",
> + };
> + snprintf(core_state->custom_error.error_str, MCD_INFO_STR_LEN,
> + "Memory tx failed with error code %d", result);
> + core_state->last_error = &core_state->custom_error;
> + return core_state->last_error->return_status;
> + }
> +
> + tx->num_bytes_ok = tx->num_bytes;
> + core_state->last_error = &MCD_ERROR_NONE;
> + return core_state->last_error->return_status;
> +}