qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH qemu 2/3] target/arm/gdbstub: Support reading M system regist


From: Peter Maydell
Subject: Re: [PATCH qemu 2/3] target/arm/gdbstub: Support reading M system registers from GDB
Date: Tue, 17 Jan 2023 13:44:48 +0000

On Mon, 9 Jan 2023 at 23:18, ~dreiss-meta <dreiss-meta@git.sr.ht> wrote:
>
> From: David Reiss <dreiss@meta.com>
>
> Follows a fairly similar pattern to the existing special register debug
> support.  Only reading is implemented, but it should be possible to
> implement writes.
>
> `v7m_mrs_control` was renamed `arm_v7m_mrs_control` and made
> non-static so this logic could be shared between the MRS instruction and
> the GDB stub.
>
> Signed-off-by: David Reiss <dreiss@meta.com>
> ---
>  target/arm/cpu.h      |  11 +++-
>  target/arm/gdbstub.c  | 125 ++++++++++++++++++++++++++++++++++++++++++
>  target/arm/m_helper.c |   6 +-
>  3 files changed, 137 insertions(+), 5 deletions(-)
>
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 2b4bd20f9d..5cf86cf2d7 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -852,6 +852,7 @@ struct ArchCPU {
>
>      DynamicGDBXMLInfo dyn_sysreg_xml;
>      DynamicGDBXMLInfo dyn_svereg_xml;
> +    DynamicGDBXMLInfo dyn_m_systemreg_xml;
>
>      /* Timers used by the generic (architected) timer */
>      QEMUTimer *gt_timer[NUM_GTIMERS];
> @@ -1094,11 +1095,13 @@ int arm_cpu_gdb_read_register(CPUState *cpu, 
> GByteArray *buf, int reg);
>  int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>
>  /*
> - * Helpers to dynamically generates XML descriptions of the sysregs
> - * and SVE registers. Returns the number of registers in each set.
> + * Helpers to dynamically generates XML descriptions of the sysregs,

we can fix the typo while we're changing this line: "dynamically generate"

> + * SVE registers, and M-profile system registers.
> + * Returns the number of registers in each set.
>   */
>  int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
>  int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
> +int arm_gen_dynamic_m_systemreg_xml(CPUState *cpu, int base_reg);
>
>  /* Returns the dynamically generated XML for the gdb stub.
>   * Returns a pointer to the XML contents for the specified XML file or NULL
> @@ -1490,6 +1493,10 @@ FIELD(SVCR, ZA, 1, 1)
>  FIELD(SMCR, LEN, 0, 4)
>  FIELD(SMCR, FA64, 31, 1)
>
> +/* Read the CONTROL register as the MRS instruction would.
> + */

QEMU comment style is either
/* one line comment */
or
/*
 * multiline comment, with the opening and closing
 * slash-star and star-slash on lines of their own
 */

We do still have some older parts of the codebase with different
styles, but new code should follow the coding style.
scripts/checkpatch.pl usually but doesn't always catch this.

> +uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure);
> +
>  /* Write a new value to v7m.exception, thus transitioning into or out
>   * of Handler mode; this may result in a change of active stack pointer.
>   */
> diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
> index 2f806512d0..4456892e91 100644
> --- a/target/arm/gdbstub.c
> +++ b/target/arm/gdbstub.c
> @@ -322,6 +322,121 @@ int arm_gen_dynamic_sysreg_xml(CPUState *cs, int 
> base_reg)
>      return cpu->dyn_sysreg_xml.num;
>  }
>
> +/*
> + * Helper required because g_array_append_val is a macro
> + * that cannot handle string literals.
> + */
> +static inline void g_array_append_str_literal(GArray *array, const char *str)
> +{
> +    g_array_append_val(array, str);
> +}
> +
> +static int arm_gdb_get_m_systemreg(CPUARMState *env, GByteArray *buf, int 
> reg)
> +{
> +    /* NOTE: This implementation shares a lot of logic with v7m_mrs. */
> +    switch (reg) {
> +
> +    /*
> +     * NOTE: MSP and PSP technically don't exist if the secure extension
> +     * is present (replaced by MSP_S, MSP_NS, PSP_S, PSP_NS).  Similar for
> +     * MSPLIM and PSPLIM.
> +     * However, the MRS instruction is still allowed to read from MSP and 
> PSP,
> +     * and will return the value associated with the current security state.
> +     * We replicate this behavior for the convenience of users, who will see
> +     * GDB behave similarly to their assembly code, even if they are 
> oblivious
> +     * to the security extension.
> +     */
> +    case 0: /* MSP */
> +        return gdb_get_reg32(buf,
> +            v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13]);
> +    case 1: /* PSP */
> +        return gdb_get_reg32(buf,
> +            v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp);
> +    case 6: /* MSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            return 0;
> +        }
> +        return gdb_get_reg32(buf, env->v7m.msplim[env->v7m.secure]);
> +    case 7: /* PSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            return 0;
> +        }
> +        return gdb_get_reg32(buf, env->v7m.psplim[env->v7m.secure]);
> +
> +    /*
> +     * NOTE: PRIMAKS, BASEPRI, and FAULTMASK are defined a bit differently
> +     * from the SP family, but have similar banking behavior.
> +     */
> +    case 2: /* PRIMASK */
> +        return gdb_get_reg32(buf, env->v7m.primask[env->v7m.secure]);
> +    case 3: /* BASEPRI */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            return 0;
> +        }
> +        return gdb_get_reg32(buf, env->v7m.basepri[env->v7m.secure]);
> +    case 4: /* FAULTMASK */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            return 0;
> +        }
> +        return gdb_get_reg32(buf, env->v7m.faultmask[env->v7m.secure]);
> +
> +    /*
> +     * NOTE: CONTROL has a mix of banked and non-banked bits.  We continue
> +     * to emulate the MRS instruction.  Unfortunately, this gives GDB no way
> +     * to read the SFPA bit when the CPU is in a non-secure state.
> +     */

Indent on this comment seems odd.

> +    case 5: /* CONTROL */
> +        return gdb_get_reg32(buf, arm_v7m_mrs_control(env, env->v7m.secure));
> +    }
> +
> +    return 0;
> +}
> +
> +static int arm_gdb_set_m_systemreg(CPUARMState *env, uint8_t *buf, int reg)
> +{
> +    /* TODO: Implement. */
> +    return 0;
> +}
> +
> +int arm_gen_dynamic_m_systemreg_xml(CPUState *cs, int base_reg)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    GString *s = g_string_new(NULL);
> +    DynamicGDBXMLInfo *info = &cpu->dyn_m_systemreg_xml;
> +    g_string_printf(s, "<?xml version=\"1.0\"?>");
> +    g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
> +    g_string_append_printf(s, "<feature 
> name=\"org.gnu.gdb.arm.m-system\">\n");
> +
> +    int is_v8 = arm_feature(env, ARM_FEATURE_V8);
> +    int is_main = arm_feature(env, ARM_FEATURE_M_MAIN);

Use bool for these, please. Also, coding style says don't declare
variables in the middle of a block.

> +
> +    g_autoptr(GArray) regs = g_array_new(false, true, sizeof(const char *));
> +    /* 0 */ g_array_append_str_literal(regs, "msp");
> +    /* 1 */ g_array_append_str_literal(regs, "psp");
> +    /* 2 */ g_array_append_str_literal(regs, "primask");
> +    /* 3 */ g_array_append_str_literal(regs, is_main ? "basepri" : "");
> +    /* 4 */ g_array_append_str_literal(regs, is_main ? "faultmask" : "");
> +    /* 5 */ g_array_append_str_literal(regs, "control");
> +    /* 6 */ g_array_append_str_literal(regs, is_v8 ? "msplim" : "");
> +    /* 7 */ g_array_append_str_literal(regs, is_v8 ? "psplim" : "");
> +
> +    for (int idx = 0; idx < regs->len; idx++) {
> +        const char *name = g_array_index(regs, const char *, idx);
> +        if (*name != '\0') {
> +            g_string_append_printf(s,
> +                        "<reg name=\"%s\" bitsize=\"32\" regnum=\"%d\"/>\n",
> +                        name, base_reg);

Opinion seems to be divided on whether the registers here that
don't define all 32 bits should be reported as bitsize="32" or
not, eg OpenOCD reports primask etc as bitsize="1". But I found
at least one other generator of this XML which uses bitsize=32
throughout, so I guess we're good to do so also.

> +        }
> +        base_reg++;
> +    }
> +    info->num = regs->len;
> +
> +    g_string_append_printf(s, "</feature>");
> +    info->desc = g_string_free(s, false);
> +    return info->num;
> +}

thanks
-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]