On Tue, 14 Oct 2025 at 21:10, Richard Henderson
<[email protected]> wrote:
>
> Create a function define_ttbr_register which handles the 3
> distinct cases for TTBR[01] registers.
>
> Signed-off-by: Richard Henderson <[email protected]>

> +static void define_ttbr_registers(ARMCPU *cpu)
> +{
> +    /*
> +     * For v8:
> +     * The aarch64 regs are primary, since they might be 128-bit.
> +     * The aarch32 64-bit non-secure regs are secondary to aa64 el1.
> +     * The aarch32 64-bit httbr is secondary to aa64 el2.
> +     * The aarch32 64-bit secure ttbr0 is secondary to aa64 el3.
> +     * The aarch32 64-bit secure ttbr1 is primary.
> +     *
> +     * For v7:
> +     * The aarch32 64-bit s+ns regs are primary.
> +     *
> +     * The aarch32 32-bit regs are secondary to one of the above,
> +     * and we also don't expose them to gdb.
> +     */
> +    static const ARMCPRegInfo ttbrv8_reginfo[] = {
> +        { .name = "TTBR0_EL1", .state = ARM_CP_STATE_AA64,
> +          .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
> +          .access = PL1_RW, .accessfn = access_tvm_trvm,
> +          .fgt = FGT_TTBR0_EL1,
> +          .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
> +          .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0),
> +          .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0),
> +          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
> +          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[1]) },
> +        { .name = "TTBR1_EL1", .state = ARM_CP_STATE_AA64,
> +          .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
> +          .access = PL1_RW, .accessfn = access_tvm_trvm,
> +          .fgt = FGT_TTBR1_EL1,
> +          .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1,
> +          .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1),
> +          .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1),
> +          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
> +          .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el[1]) },
> +        { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
> +          .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
> +          .access = PL2_RW, .resetvalue = 0,
> +          .writefn = vmsa_tcr_ttbr_el2_write, .raw_writefn = raw_write,
> +          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
> +        { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64,
> +          .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0,
> +          .access = PL3_RW, .resetvalue = 0,
> +          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
> +    };
> +
> +    static ARMCPRegInfo ttbr64_reginfo[] = {
> +        [0 ... 3] = {
> +            .cp = 15, .crm = 2, .type = ARM_CP_64BIT,

I think I would prefer it if we listed the full encoding
fields in each array element, rather than factoring out the
common parts like this. I think it's easier to read and
confirm what register encoding is being dealt with when
it's all on one line in the standard order rather than split
up into multiple lines.

> +            .access = PL1_RW, .accessfn = access_tvm_trvm,

This applies the accessfn to the HTTBR, which is harmless
because the accessfn doesn't trap unless at EL1, but also
means we'll do an unnecessary function call out to C code
for every access to it.

> +            .writefn = vmsa_ttbr_write, .raw_writefn = raw_write
> +        },
> +        [0 ... 1].opc1 = 0,
> +        [0].name = "TTBR0",
> +        [0].secure = ARM_CP_SECSTATE_NS,
> +        [0].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_ns),
> +        [1].name = "TTBR0_S",
> +        [1].secure = ARM_CP_SECSTATE_S,
> +        [1].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_s),
> +
> +        [2 ... 3].opc1 = 1,
> +        [2].name = "TTBR1",
> +        [2].secure = ARM_CP_SECSTATE_NS,
> +        [2].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_ns),
> +        [3].name = "TTBR1_S",
> +        [3].secure = ARM_CP_SECSTATE_S,
> +        [3].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_s),
> +
> +        [4] = {
> +            .name = "HTTBR", .cp = 15, .crm = 2, .opc1 = 4,
> +            .access = PL2_RW, .type = ARM_CP_64BIT,
> +            .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2])
> +        },
> +    };
> +
> +    static ARMCPRegInfo ttbr32_reginfo[] = {
> +        { .name = "TTBR0", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 
> 0,
> +          .access = PL1_RW, .accessfn = access_tvm_trvm,
> +          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
> +          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
> +                                 offsetof(CPUARMState, cp15.ttbr0_ns) } },
> +        { .name = "TTBR1", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 
> 1,
> +          .access = PL1_RW, .accessfn = access_tvm_trvm,
> +          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
> +          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
> +                                 offsetof(CPUARMState, cp15.ttbr1_ns) } },
> +    };
> +
> +    CPUARMState *env = &cpu->env;
> +
> +    /* With only VMSA, define a 32-bit reg that filters bits from write. */

What do you mean by "filters bits from write" here ?

> +    if (!arm_feature(env, ARM_FEATURE_LPAE)) {
> +        define_arm_cp_regs(cpu, ttbr32_reginfo);
> +        return;
> +    }
> +
> +    /* With LPAE, the 32-bit regs are aliases of 64-bit regs. */
> +    for (int i = 0; i < ARRAY_SIZE(ttbr32_reginfo); ++i) {
> +        ttbr32_reginfo[i].type = ARM_CP_ALIAS | ARM_CP_NO_GDB;
> +    }
> +    define_arm_cp_regs(cpu, ttbr32_reginfo);
> +
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        define_arm_cp_regs(cpu, ttbrv8_reginfo);
> +
> +        ttbr64_reginfo[0].type |= ARM_CP_ALIAS;
> +        ttbr64_reginfo[1].type |= ARM_CP_ALIAS;
> +        ttbr64_reginfo[2].type |= ARM_CP_ALIAS;
> +        /* Index 3, TTBR1_S, is not an alias. */
> +        ttbr64_reginfo[4].type |= ARM_CP_ALIAS;
> +    }
> +
> +    define_arm_cp_regs(cpu, ttbr64_reginfo);
> +}

thanks
-- PMM

Reply via email to