On Sun, 23 Oct 2022 at 16:37, <tobias.roeh...@rwth-aachen.de> wrote: > > From: Tobias Röhmel <tobias.roeh...@rwth-aachen.de> > > Signed-off-by: Tobias Röhmel <tobias.roeh...@rwth-aachen.de>
This patch is basically the right shape, but there's a big simplification you can make and then a bunch of minor tweaks. > --- > target/arm/cpu.c | 26 +++- > target/arm/cpu.h | 12 ++ > target/arm/helper.c | 290 +++++++++++++++++++++++++++++++++++++++++++ > target/arm/machine.c | 28 +++++ > target/arm/ptw.c | 9 +- > 5 files changed, 363 insertions(+), 2 deletions(-) > > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > index b642749d6d..468150ad6c 100644 > --- a/target/arm/cpu.c > +++ b/target/arm/cpu.c > @@ -463,6 +463,16 @@ static void arm_cpu_reset(DeviceState *dev) > sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion); > } > } > + > + if (cpu->pmsav8r_hdregion > 0) { > + memset(env->pmsav8.hprbar[M_REG_NS], 0, > + sizeof(*env->pmsav8.hprbar[M_REG_NS]) > + * cpu->pmsav8r_hdregion); > + memset(env->pmsav8.hprlar[M_REG_NS], 0, > + sizeof(*env->pmsav8.hprlar[M_REG_NS]) > + * cpu->pmsav8r_hdregion); > + } > + > env->pmsav7.rnr[M_REG_NS] = 0; > env->pmsav7.rnr[M_REG_S] = 0; > env->pmsav8.mair0[M_REG_NS] = 0; > @@ -1965,8 +1975,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error > **errp) > */ > if (!cpu->has_mpu) { > cpu->pmsav7_dregion = 0; > + cpu->pmsav8r_hdregion = 0; > } > - if (cpu->pmsav7_dregion == 0) { > + if ((cpu->pmsav7_dregion == 0) && (cpu->pmsav8r_hdregion == 0)) { > cpu->has_mpu = false; > } > > @@ -1994,6 +2005,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error > **errp) > env->pmsav7.dracr = g_new0(uint32_t, nr); > } > } > + > + if (cpu->pmsav8r_hdregion > 0xFF) { > + error_setg(errp, "PMSAv8 MPU EL2 #regions invalid %" PRIu32, > + cpu->pmsav8r_hdregion); > + return; > + } > + > + if (cpu->pmsav8r_hdregion) { > + env->pmsav8.hprbar[M_REG_NS] = g_new0(uint32_t, > + cpu->pmsav8r_hdregion); > + env->pmsav8.hprlar[M_REG_NS] = g_new0(uint32_t, > + cpu->pmsav8r_hdregion); > + } > } > > if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > index 429ed42eec..1bb3c24db1 100644 > --- a/target/arm/cpu.h > +++ b/target/arm/cpu.h > @@ -307,6 +307,13 @@ typedef struct CPUArchState { > }; > uint64_t sctlr_el[4]; > }; > + union { /* Virtualization System control register. */ > + struct { > + uint32_t vsctlr_ns; > + uint32_t vsctlr_s; > + }; > + uint32_t vsctlr_el[2]; > + }; v8R only has a single security state, so you don't need to make this a union or have _ns and _s versions, you can just have a single field. We should make the field a uint64_t because this register in PMSAv8-64 is 64 bits, and having the field be 64 bits to start with will make life slightly easier if we need to implement that in future. So uint64_t vsctlr; > uint64_t cpacr_el1; /* Architectural feature access control register > */ > uint64_t cptr_el[4]; /* ARMv8 feature trap registers */ > uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ > @@ -740,8 +747,11 @@ typedef struct CPUArchState { > */ > uint32_t *rbar[M_REG_NUM_BANKS]; > uint32_t *rlar[M_REG_NUM_BANKS]; > + uint32_t *hprbar[M_REG_NUM_BANKS]; > + uint32_t *hprlar[M_REG_NUM_BANKS]; These don't need to be arrays, so just uint32_t *hprbar; uint32_t *hprlar; (PMSAv8-64 also has these as 64-bit registers, but that is also true of the existing rbar/rlar. So I think on balance it's better to keep hprbar/hprlar the same length as rbar/rlar, and if we ever implement PMSAv8-64 we'll have to sort out extending the length of both sets of registers at the same time.) > uint32_t mair0[M_REG_NUM_BANKS]; > uint32_t mair1[M_REG_NUM_BANKS]; > + uint32_t hprselr[M_REG_NUM_BANKS]; Similarly this can just be uint32_t hprselr; > } pmsav8; > > /* v8M SAU */ > @@ -901,6 +911,8 @@ struct ArchCPU { > bool has_mpu; > /* PMSAv7 MPU number of supported regions */ > uint32_t pmsav7_dregion; > + /* PMSAv8 MPU number of supported hyp regions */ > + uint32_t pmsav8r_hdregion; > /* v8M SAU number of supported regions */ > uint32_t sau_sregion; > > diff --git a/target/arm/helper.c b/target/arm/helper.c > index 2e9e420d4e..6a27a618bc 100644 > --- a/target/arm/helper.c > +++ b/target/arm/helper.c > @@ -3607,6 +3607,215 @@ static void pmsav7_rgnr_write(CPUARMState *env, const > ARMCPRegInfo *ri, > raw_write(env, ri, value); > } > > +static void prbar_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + env->pmsav8.rbar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]] = value; > +} > + > +static uint64_t prbar_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + return env->pmsav8.rbar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]]; > +} > + > +static void prlar_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + env->pmsav8.rlar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]] = value; > +} > + > +static uint64_t prlar_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + return env->pmsav8.rlar[M_REG_NS][env->pmsav7.rnr[M_REG_NS]]; > +} > + > +static void prselr_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + /* Ignore writes that would select not implemented region */ It's worth mentioning that this is architecturally UNPREDICTABLE. > + if (value >= cpu->pmsav7_dregion) { > + return; > + } > + > + env->pmsav7.rnr[M_REG_NS] = value; > +} > + > +static void hprbar_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + env->pmsav8.hprbar[M_REG_NS][env->pmsav8.hprselr[M_REG_NS]] = value; > +} > + > +static uint64_t hprbar_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + return env->pmsav8.hprbar[M_REG_NS][env->pmsav8.hprselr[M_REG_NS]]; > +} > + > +static void hprlar_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + env->pmsav8.hprlar[M_REG_NS][env->pmsav8.hprselr[M_REG_NS]] = value; > +} > + > +static uint64_t hprlar_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + return env->pmsav8.hprlar[M_REG_NS][env->pmsav8.hprselr[M_REG_NS]]; > +} > + > +static void hprenr_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + uint32_t n; > + uint32_t bit; > + ARMCPU *cpu = env_archcpu(env); > + > + /* Ignore writes to unimplemented regions */ > + value &= (1 << cpu->pmsav8r_hdregion) - 1; This is undefined behaviour if cpu->pmsav8r_hdregion is greater than 31. I suggest defining a local variable int rmax = MIN(cpu->pmsav8r_hdregion, 32); Then you can do value &= MAKE_64BIT_MASK(0, rmax); > + > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + > + /* Register alias is only valid for first 32 indexes */ > + for (n = 0; n < (cpu->pmsav8r_hdregion & 0x1F); ++n) { This isn't the right boundary -- for instance if pmsav8r_hdregion is 33 then this will only set bit 0. If you take my suggestion above then you can just use 'rmax' as the upper bound. > + bit = extract32(value, n, 1); > + env->pmsav8.hprlar[M_REG_NS][n] = deposit32( > + env->pmsav8.hprlar[M_REG_NS][n], 0, 1, bit); > + } > +} > + > +static uint64_t hprenr_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + uint32_t n; > + uint32_t result = 0x0; > + ARMCPU *cpu = env_archcpu(env); > + > + /* Register alias is only valid for first 32 indexes */ > + for (n = 0; n < (cpu->pmsav8r_hdregion & 0x1F); ++n) { Same remark as above about the upper bound. > + if (env->pmsav8.hprlar[M_REG_NS][n] & 0x1) { > + result |= (0x1 << n); > + } > + } > + return result; > +} > + > +static void hprselr_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + > + /* Ignore writes that would select not implemented region */ > + if (value >= cpu->pmsav8r_hdregion) { > + return; > + } > + > + env->pmsav8.hprselr[M_REG_NS] = value; > +} > + > +static void pmsav8r_regn_write(CPUARMState *env, const ARMCPRegInfo *ri, > + uint64_t value) > +{ > + ARMCPU *cpu = env_archcpu(env); > + uint8_t index = (ri->crm & 0b111) << 1; > + index |= (ri->opc2 & 1 << 2) >> 2; This is missing the 5th bit of index, which is in opc0 bit 0. I would suggest index = (extract32(ri->opc0, 0, 1) << 4) | (extract32(ri->crm, 0, 3) << 1) | extract32(ri->opc2, 2, 1); > + tlb_flush(CPU(cpu)); /* Mappings may have changed - purge! */ > + > + if (ri->opc1 == 4) { This should be checking (ri->opc1 & 2). > + if (index >= cpu->pmsav8r_hdregion) { > + return; > + } > + if (ri->opc2 & 0x1) { > + env->pmsav8.hprlar[M_REG_NS][index] = value; > + } else { > + env->pmsav8.hprbar[M_REG_NS][index] = value; > + } > + } else { > + if (index >= cpu->pmsav7_dregion) { > + return; > + } > + if (ri->opc2 & 0x1) { > + env->pmsav8.rlar[M_REG_NS][index] = value; > + } else { > + env->pmsav8.rbar[M_REG_NS][index] = value; > + } > + } > +} > + > +static uint64_t pmsav8r_regn_read(CPUARMState *env, const ARMCPRegInfo *ri) > +{ > + ARMCPU *cpu = env_archcpu(env); > + uint8_t index = (ri->crm & 0b111) << 1; > + index |= (ri->opc2 & 1 << 2) >> 2; Same remarks apply to this function as above. > + > + if (ri->opc1 == 4) { > + if (index >= cpu->pmsav8r_hdregion) { > + return 0x0; > + } > + if (ri->opc2 & 0x1) { > + return env->pmsav8.hprlar[M_REG_NS][index]; > + } else { > + return env->pmsav8.hprbar[M_REG_NS][index]; > + } > + } else { > + if (index >= cpu->pmsav7_dregion) { > + return 0x0; > + } > + if (ri->opc2 & 0x1) { > + return env->pmsav8.rlar[M_REG_NS][index]; > + } else { > + return env->pmsav8.rbar[M_REG_NS][index]; > + } > + } > +} > + > +static const ARMCPRegInfo pmsav8r_cp_reginfo[] = { > + { .name = "PRBAR", > + .cp = 15, .opc1 = 0, .crn = 6, .crm = 3, .opc2 = 0, Indent here seems odd (even by the ad-hoc standards we apply to cpreginfo array declarations): generally we make all the '.'s line up. > + .access = PL1_RW, .type = ARM_CP_ALIAS, > + .accessfn = access_tvm_trvm, > + .readfn = prbar_read, .writefn = prbar_write}, We generally put a space before the closing } on this kind of line. > + { .name = "PRLAR", > + .cp = 15, .opc1 = 0, .crn = 6, .crm = 3, .opc2 = 1, > + .access = PL1_RW, .type = ARM_CP_ALIAS, > + .accessfn = access_tvm_trvm, > + .readfn = prlar_read, .writefn = prlar_write}, These two should be .type = ARM_CP_NO_RAW > + { .name = "PRSELR", .resetvalue = 0, > + .cp = 15, .opc1 = 0, .crn = 6, .crm = 2, .opc2 = 1, > + .access = PL1_RW, .accessfn = access_tvm_trvm, > + .writefn = prselr_write, > + .fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS])}, > + { .name = "HPRBAR", .resetvalue = 0, > + .cp = 15, .opc1 = 4, .crn = 6, .crm = 3, .opc2 = 0, > + .access = PL2_RW, .type = ARM_CP_ALIAS, > + .readfn = hprbar_read, .writefn = hprbar_write}, > + { .name = "HPRLAR", > + .cp = 15, .opc1 = 4, .crn = 6, .crm = 3, .opc2 = 1, > + .access = PL2_RW, .type = ARM_CP_ALIAS, > + .readfn = hprlar_read, .writefn = hprlar_write}, These two also should be ARM_CP_NO_RAW > + { .name = "HPRSELR", .resetvalue = 0, > + .cp = 15, .opc1 = 4, .crn = 6, .crm = 2, .opc2 = 1, > + .access = PL2_RW, > + .writefn = hprselr_write, > + .fieldoffset = offsetof(CPUARMState, pmsav8.hprselr[M_REG_NS])}, > + { .name = "HPRENR", > + .cp = 15, .opc1 = 4, .crn = 6, .crm = 1, .opc2 = 1, > + .access = PL2_RW, .type = ARM_CP_ALIAS, > + .readfn = hprenr_read, .writefn = hprenr_write}, > +}; > + > static const ARMCPRegInfo pmsav7_cp_reginfo[] = { > /* Reset for all these registers is handled in arm_cpu_reset(), > * because the PMSAv7 is also used by M-profile CPUs, which do > @@ -8079,6 +8288,13 @@ void register_cp_regs_for_features(ARMCPU *cpu) > .access = PL1_R, .type = ARM_CP_CONST, > .resetvalue = cpu->pmsav7_dregion << 8 > }; > + /* HMPUIR is specific to PMSA V8 */ > + ARMCPRegInfo id_hmpuir_reginfo = { > + .name = "HMPUIR", > + .cp = 15, .crn = 0, .crm = 0, .opc1 = 4, .opc2 = 4, Prefer the order cp, opc1, crn, crm, opc2 > + .access = PL2_R, .type = ARM_CP_CONST, > + .resetvalue = cpu->pmsav8r_hdregion > + }; > static const ARMCPRegInfo crn0_wi_reginfo = { > .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY, > .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, > @@ -8122,6 +8338,67 @@ void register_cp_regs_for_features(ARMCPU *cpu) > define_arm_cp_regs(cpu, id_cp_reginfo); > if (!arm_feature(env, ARM_FEATURE_PMSA)) { > define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo); > + } else if (arm_feature(env, ARM_FEATURE_PMSA) > + && !arm_feature(env, ARM_FEATURE_M) M-profile is checked for at the top of the function and it returns early and never gets to this code, so you can skip this test. > + && arm_feature(env, ARM_FEATURE_V8)) { > + uint32_t i = 0; > + g_autofree char *tmp_string; > + > + define_one_arm_cp_reg(cpu, &id_mpuir_reginfo); > + define_one_arm_cp_reg(cpu, &id_hmpuir_reginfo); > + define_arm_cp_regs(cpu, pmsav8r_cp_reginfo); > + > + /* Register alias is only valid for first 32 indexes */ > + for (i = 0; i < (cpu->pmsav7_dregion & 0x1F); ++i) { Bad upper index again. > + uint8_t crm = 0b1000 | ((i & 0b1110) >> 1); > + uint8_t opc2 = (i & 0x1) << 2; Doesn't handle the 5th bit in the index (the one that ends up in opc1). > + > + tmp_string = g_strdup_printf("PRBAR%u", i); > + ARMCPRegInfo tmp_prbarn_reginfo = { > + .name = tmp_string, .type = ARM_CP_ALIAS, ARM_CP_NO_RAW > + .cp = 15, .opc1 = 0, .crn = 6, .crm = crm, .opc2 = opc2, > + .access = PL1_RW, .resetvalue = 0, > + .accessfn = access_tvm_trvm, > + .writefn = pmsav8r_regn_write, .readfn = > pmsav8r_regn_read > + }; > + define_one_arm_cp_reg(cpu, &tmp_prbarn_reginfo); > + > + opc2 = (i & 0x1) << 2 | 0x1; > + tmp_string = g_strdup_printf("PRLAR%u", i); If you're going to use g_autofree, you can't reuse the same variable for a new string allocation -- this leaks the first string when we assign to tmp_string again. You need to use separate variables so that both allocations are auto-freed when they go out of scope. > + ARMCPRegInfo tmp_prlarn_reginfo = { > + .name = tmp_string, .type = ARM_CP_ALIAS, ARM_CP_NO_RAW > + .cp = 15, .opc1 = 0, .crn = 6, .crm = crm, .opc2 = opc2, > + .access = PL1_RW, .resetvalue = 0, > + .accessfn = access_tvm_trvm, > + .writefn = pmsav8r_regn_write, .readfn = > pmsav8r_regn_read > + }; > + define_one_arm_cp_reg(cpu, &tmp_prlarn_reginfo); > + } > + > + /* Register alias is only valid for first 32 indexes */ > + for (i = 0; i < (cpu->pmsav8r_hdregion & 0x1F); ++i) { > + uint8_t crm = 0b1000 | ((i & 0b1110) >> 1); > + uint8_t opc2 = (i & 0x1) << 2; Same comments for the first loop all apply to this loop. > + > + tmp_string = g_strdup_printf("HPRBAR%u", i); > + ARMCPRegInfo tmp_hprbarn_reginfo = { > + .name = tmp_string, .type = ARM_CP_ALIAS, > + .cp = 15, .opc1 = 4, .crn = 6, .crm = crm, .opc2 = opc2, > + .access = PL2_RW, .resetvalue = 0, > + .writefn = pmsav8r_regn_write, .readfn = > pmsav8r_regn_read > + }; > + define_one_arm_cp_reg(cpu, &tmp_hprbarn_reginfo); > + > + opc2 = (i & 0x1) << 2 | 0x1; > + tmp_string = g_strdup_printf("HPRLAR%u", i); > + ARMCPRegInfo tmp_hprlarn_reginfo = { > + .name = tmp_string, .type = ARM_CP_ALIAS, > + .cp = 15, .opc1 = 4, .crn = 6, .crm = crm, .opc2 = opc2, > + .access = PL2_RW, .resetvalue = 0, > + .writefn = pmsav8r_regn_write, .readfn = > pmsav8r_regn_read > + }; > + define_one_arm_cp_reg(cpu, &tmp_hprlarn_reginfo); > + } > } else if (arm_feature(env, ARM_FEATURE_V7)) { > define_one_arm_cp_reg(cpu, &id_mpuir_reginfo); > } > @@ -8243,6 +8520,19 @@ void register_cp_regs_for_features(ARMCPU *cpu) > sctlr.type |= ARM_CP_SUPPRESS_TB_END; > } > define_one_arm_cp_reg(cpu, &sctlr); > + > + if (arm_feature(env, ARM_FEATURE_PMSA) > + && !arm_feature(env, ARM_FEATURE_M) Don't need to check for not-M. > + && arm_feature(env, ARM_FEATURE_V8)) { > + ARMCPRegInfo vsctlr = { > + .name = "VSCTLR", .state = ARM_CP_STATE_AA32, > + .cp = 15, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0, > + .access = PL2_RW, .resetvalue = 0x0, > + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vsctlr_s), > + offsetof(CPUARMState, cp15.vsctlr_ns) }, This will get simpler when you aren't trying to describe it as a banked register. Note that if you make the field a uint64_t as I suggest above then you will want to use offsetoflow32() rather than plain offsetof() (so that on a big-endian host the field offset is pointed to the high half of the uint64_t.) > + }; > + define_one_arm_cp_reg(cpu, &vsctlr); > + } > } > > if (cpu_isar_feature(aa64_lor, cpu)) { > diff --git a/target/arm/machine.c b/target/arm/machine.c > index 54c5c62433..923da8d0bc 100644 > --- a/target/arm/machine.c > +++ b/target/arm/machine.c > @@ -487,6 +487,30 @@ static bool pmsav8_needed(void *opaque) > arm_feature(env, ARM_FEATURE_V8); > } > > +static bool pmsav8r_needed(void *opaque) > +{ > + ARMCPU *cpu = opaque; > + CPUARMState *env = &cpu->env; > + > + return arm_feature(env, ARM_FEATURE_PMSA) && > + arm_feature(env, ARM_FEATURE_V8) && > + !arm_feature(env, ARM_FEATURE_M); > +} > + > +static const VMStateDescription vmstate_pmsav8r = { > + .name = "cpu/pmsav8/pmsav8r", > + .version_id = 1, > + .minimum_version_id = 1, > + .needed = pmsav8r_needed, > + .fields = (VMStateField[]) { > + VMSTATE_VARRAY_UINT32(env.pmsav8.hprbar[M_REG_NS], ARMCPU, > + pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t), > + VMSTATE_VARRAY_UINT32(env.pmsav8.hprlar[M_REG_NS], ARMCPU, > + pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t), > + VMSTATE_END_OF_LIST() > + }, > +}; > + > static const VMStateDescription vmstate_pmsav8 = { > .name = "cpu/pmsav8", > .version_id = 1, > @@ -500,6 +524,10 @@ static const VMStateDescription vmstate_pmsav8 = { > VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU), > VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU), > VMSTATE_END_OF_LIST() > + }, > + .subsections = (const VMStateDescription * []) { > + &vmstate_pmsav8r, > + NULL > } > }; You'll need to adjust the vmstate field array a bit to allow for hprbar and hprlar not being arrays, but otherwise the vmstate changes look good. > diff --git a/target/arm/ptw.c b/target/arm/ptw.c > index db50715fa7..4bd7389fa9 100644 > --- a/target/arm/ptw.c > +++ b/target/arm/ptw.c > @@ -1718,6 +1718,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t > address, > bool hit = false; > uint32_t addr_page_base = address & TARGET_PAGE_MASK; > uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); > + int region_counter; > + > + if (regime_el(env, mmu_idx) == 2) { > + region_counter = cpu->pmsav8r_hdregion; > + } else { > + region_counter = cpu->pmsav7_dregion; > + } > > result->page_size = TARGET_PAGE_SIZE; > result->phys = address; > @@ -1742,7 +1749,7 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t > address, > hit = true; > } > > - for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { > + for (n = region_counter - 1; n >= 0; n--) { > /* region search */ > /* > * Note that the base address is bits [31:5] from the register The changes to ptw.c here should be moved to the following patch. thanks -- PMM