diff --git a/target-arm/cpu.c b/target-arm/cpu.c index a04d5c38973ec2f369c80197e5aaf1126731005f..eb10f59ab3a54844323b32b46c15197565c96eaf 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -596,6 +596,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) error_setg(errp, "PMSAv7 MPU #regions invalid %" PRIu32 "\n", nr); return; } + + if (nr) { + env->pmsav7.drbar = g_new0(uint32_t, nr); + env->pmsav7.drsr = g_new0(uint32_t, nr); + env->pmsav7.dracr = g_new0(uint32_t, nr); + } } register_cp_regs_for_features(cpu); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2f59058e6470db8dfb5854c92ec3b5b06ab3589c..0c320ea2da92eec4f25df2caaa3b9ff49edb20e1 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -284,6 +284,9 @@ typedef struct CPUARMState { }; uint64_t par_el[4]; }; + + uint32_t c6_rgnr; + uint32_t c9_insn; /* Cache lockdown registers. */ uint32_t c9_data; uint64_t c9_pmcr; /* performance monitor control register */ @@ -482,6 +485,13 @@ typedef struct CPUARMState { /* Internal CPU feature flags. */ uint64_t features; + /* PMSAv7 MPU */ + struct { + uint32_t *drbar; + uint32_t *drsr; + uint32_t *dracr; + } pmsav7; + void *nvic; const struct arm_boot_info *boot_info; } CPUARMState; diff --git a/target-arm/helper.c b/target-arm/helper.c index 1cb881226a924d17c28ba9c82348532b797be402..b6442a6474e7da8410c5fb382a2468c2542e2720 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1707,6 +1707,81 @@ static uint64_t pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) return simple_mpu_ap_bits(env->cp15.pmsav5_insn_ap); } +static uint64_t pmsav7_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri); + + if (!u32p) { + return 0; + } + + u32p += env->cp15.c6_rgnr; + return *u32p; +} + +static void pmsav7_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri); + + if (!u32p) { + return; + } + + u32p += env->cp15.c6_rgnr; + tlb_flush(CPU(cpu), 1); /* Mappings may have changed - purge! */ + *u32p = value; +} + +static void pmsav7_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + uint32_t *u32p = *(uint32_t **)raw_ptr(env, ri); + + if (!u32p) { + return; + } + + memset(u32p, 0, sizeof(*u32p) * cpu->pmsav7_dregion); +} + +static void pmsav7_rgnr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + uint32_t nrgs = cpu->pmsav7_dregion; + + if (value >= nrgs) { + qemu_log_mask(LOG_GUEST_ERROR, + "PMSAv7 RGNR write >= # supported regions, %" PRIu32 + " > %" PRIu32 "\n", (uint32_t)value, nrgs); + return; + } + + raw_write(env, ri, value); +} + +static const ARMCPRegInfo pmsav7_cp_reginfo[] = { + { .name = "DRBAR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 0, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.drbar), + .readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset }, + { .name = "DRSR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 2, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.drsr), + .readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset }, + { .name = "DRACR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 1, .opc2 = 4, + .access = PL1_RW, .type = ARM_CP_NO_RAW, + .fieldoffset = offsetof(CPUARMState, pmsav7.dracr), + .readfn = pmsav7_read, .writefn = pmsav7_write, .resetfn = pmsav7_reset }, + { .name = "RGNR", .cp = 15, .crn = 6, .opc1 = 0, .crm = 2, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c6_rgnr), + .writefn = pmsav7_rgnr_write }, + REGINFO_SENTINEL +}; + static const ARMCPRegInfo pmsav5_cp_reginfo[] = { { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_ALIAS, @@ -3337,13 +3412,14 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_one_arm_cp_reg(cpu, &rvbar); } if (arm_feature(env, ARM_FEATURE_MPU)) { - /* These are the MPU registers prior to PMSAv6. Any new - * PMSA core later than the ARM946 will require that we - * implement the PMSAv6 or PMSAv7 registers, which are - * completely different. - */ - assert(!arm_feature(env, ARM_FEATURE_V6)); - define_arm_cp_regs(cpu, pmsav5_cp_reginfo); + if (arm_feature(env, ARM_FEATURE_V6)) { + /* PMSAv6 not implemented */ + assert(arm_feature(env, ARM_FEATURE_V7)); + define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); + define_arm_cp_regs(cpu, pmsav7_cp_reginfo); + } else { + define_arm_cp_regs(cpu, pmsav5_cp_reginfo); + } } else { define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); define_arm_cp_regs(cpu, vmsa_cp_reginfo); diff --git a/target-arm/machine.c b/target-arm/machine.c index 36365a57c779724c542fbedb869c69a244021aee..9eb51dfddd51fd5e588d27a0cd12d8b124a4a1ab 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -125,6 +125,39 @@ static const VMStateDescription vmstate_thumb2ee = { } }; +static bool pmsav7_needed(void *opaque) +{ + ARMCPU *cpu = opaque; + CPUARMState *env = &cpu->env; + + return arm_feature(env, ARM_FEATURE_MPU) && + arm_feature(env, ARM_FEATURE_V7); +} + +static bool pmsav7_rgnr_vmstate_validate(void *opaque, int version_id) +{ + ARMCPU *cpu = opaque; + + return cpu->env.cp15.c6_rgnr < cpu->pmsav7_dregion; +} + +static const VMStateDescription vmstate_pmsav7 = { + .name = "cpu/pmsav7", + .version_id = 1, + .minimum_version_id = 1, + .needed = pmsav7_needed, + .fields = (VMStateField[]) { + VMSTATE_VARRAY_UINT32(env.pmsav7.drbar, ARMCPU, pmsav7_dregion, 0, + vmstate_info_uint32, uint32_t), + VMSTATE_VARRAY_UINT32(env.pmsav7.drsr, ARMCPU, pmsav7_dregion, 0, + vmstate_info_uint32, uint32_t), + VMSTATE_VARRAY_UINT32(env.pmsav7.dracr, ARMCPU, pmsav7_dregion, 0, + vmstate_info_uint32, uint32_t), + VMSTATE_VALIDATE("rgnr is valid", pmsav7_rgnr_vmstate_validate), + VMSTATE_END_OF_LIST() + } +}; + static int get_cpsr(QEMUFile *f, void *opaque, size_t size) { ARMCPU *cpu = opaque; @@ -291,6 +324,7 @@ const VMStateDescription vmstate_arm_cpu = { &vmstate_iwmmxt, &vmstate_m, &vmstate_thumb2ee, + &vmstate_pmsav7, NULL } };