diff options
Diffstat (limited to 'target/arm/hvf/hvf.c')
-rw-r--r-- | target/arm/hvf/hvf.c | 302 |
1 files changed, 154 insertions, 148 deletions
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index eb090e67a2..c1496ad5be 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -1199,57 +1199,61 @@ static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val) return false; } -static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) +static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; - uint64_t val = 0; + + if (arm_feature(env, ARM_FEATURE_PMU)) { + switch (reg) { + case SYSREG_PMCR_EL0: + *val = env->cp15.c9_pmcr; + return 0; + case SYSREG_PMCCNTR_EL0: + pmu_op_start(env); + *val = env->cp15.c15_ccnt; + pmu_op_finish(env); + return 0; + case SYSREG_PMCNTENCLR_EL0: + *val = env->cp15.c9_pmcnten; + return 0; + case SYSREG_PMOVSCLR_EL0: + *val = env->cp15.c9_pmovsr; + return 0; + case SYSREG_PMSELR_EL0: + *val = env->cp15.c9_pmselr; + return 0; + case SYSREG_PMINTENCLR_EL1: + *val = env->cp15.c9_pminten; + return 0; + case SYSREG_PMCCFILTR_EL0: + *val = env->cp15.pmccfiltr_el0; + return 0; + case SYSREG_PMCNTENSET_EL0: + *val = env->cp15.c9_pmcnten; + return 0; + case SYSREG_PMUSERENR_EL0: + *val = env->cp15.c9_pmuserenr; + return 0; + case SYSREG_PMCEID0_EL0: + case SYSREG_PMCEID1_EL0: + /* We can't really count anything yet, declare all events invalid */ + *val = 0; + return 0; + } + } switch (reg) { case SYSREG_CNTPCT_EL0: - val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / + *val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(arm_cpu); - break; - case SYSREG_PMCR_EL0: - val = env->cp15.c9_pmcr; - break; - case SYSREG_PMCCNTR_EL0: - pmu_op_start(env); - val = env->cp15.c15_ccnt; - pmu_op_finish(env); - break; - case SYSREG_PMCNTENCLR_EL0: - val = env->cp15.c9_pmcnten; - break; - case SYSREG_PMOVSCLR_EL0: - val = env->cp15.c9_pmovsr; - break; - case SYSREG_PMSELR_EL0: - val = env->cp15.c9_pmselr; - break; - case SYSREG_PMINTENCLR_EL1: - val = env->cp15.c9_pminten; - break; - case SYSREG_PMCCFILTR_EL0: - val = env->cp15.pmccfiltr_el0; - break; - case SYSREG_PMCNTENSET_EL0: - val = env->cp15.c9_pmcnten; - break; - case SYSREG_PMUSERENR_EL0: - val = env->cp15.c9_pmuserenr; - break; - case SYSREG_PMCEID0_EL0: - case SYSREG_PMCEID1_EL0: - /* We can't really count anything yet, declare all events invalid */ - val = 0; - break; + return 0; case SYSREG_OSLSR_EL1: - val = env->cp15.oslsr_el1; - break; + *val = env->cp15.oslsr_el1; + return 0; case SYSREG_OSDLR_EL1: /* Dummy register */ - break; + return 0; case SYSREG_ICC_AP0R0_EL1: case SYSREG_ICC_AP0R1_EL1: case SYSREG_ICC_AP0R2_EL1: @@ -1276,9 +1280,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_ICC_SRE_EL1: case SYSREG_ICC_CTLR_EL1: /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ - if (!hvf_sysreg_read_cp(cpu, reg, &val)) { - hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); - return 1; + if (hvf_sysreg_read_cp(cpu, reg, &val)) { + return 0; } break; case SYSREG_DBGBVR0_EL1: @@ -1297,8 +1300,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_DBGBVR13_EL1: case SYSREG_DBGBVR14_EL1: case SYSREG_DBGBVR15_EL1: - val = env->cp15.dbgbvr[SYSREG_CRM(reg)]; - break; + *val = env->cp15.dbgbvr[SYSREG_CRM(reg)]; + return 0; case SYSREG_DBGBCR0_EL1: case SYSREG_DBGBCR1_EL1: case SYSREG_DBGBCR2_EL1: @@ -1315,8 +1318,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_DBGBCR13_EL1: case SYSREG_DBGBCR14_EL1: case SYSREG_DBGBCR15_EL1: - val = env->cp15.dbgbcr[SYSREG_CRM(reg)]; - break; + *val = env->cp15.dbgbcr[SYSREG_CRM(reg)]; + return 0; case SYSREG_DBGWVR0_EL1: case SYSREG_DBGWVR1_EL1: case SYSREG_DBGWVR2_EL1: @@ -1333,8 +1336,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_DBGWVR13_EL1: case SYSREG_DBGWVR14_EL1: case SYSREG_DBGWVR15_EL1: - val = env->cp15.dbgwvr[SYSREG_CRM(reg)]; - break; + *val = env->cp15.dbgwvr[SYSREG_CRM(reg)]; + return 0; case SYSREG_DBGWCR0_EL1: case SYSREG_DBGWCR1_EL1: case SYSREG_DBGWCR2_EL1: @@ -1351,35 +1354,25 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt) case SYSREG_DBGWCR13_EL1: case SYSREG_DBGWCR14_EL1: case SYSREG_DBGWCR15_EL1: - val = env->cp15.dbgwcr[SYSREG_CRM(reg)]; - break; + *val = env->cp15.dbgwcr[SYSREG_CRM(reg)]; + return 0; default: if (is_id_sysreg(reg)) { /* ID system registers read as RES0 */ - val = 0; - break; + *val = 0; + return 0; } - cpu_synchronize_state(cpu); - trace_hvf_unhandled_sysreg_read(env->pc, reg, - SYSREG_OP0(reg), - SYSREG_OP1(reg), - SYSREG_CRN(reg), - SYSREG_CRM(reg), - SYSREG_OP2(reg)); - hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); - return 1; } - trace_hvf_sysreg_read(reg, - SYSREG_OP0(reg), - SYSREG_OP1(reg), - SYSREG_CRN(reg), - SYSREG_CRM(reg), - SYSREG_OP2(reg), - val); - hvf_set_reg(cpu, rt, val); - - return 0; + cpu_synchronize_state(cpu); + trace_hvf_unhandled_sysreg_read(env->pc, reg, + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg)); + hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); + return 1; } static void pmu_update_irq(CPUARMState *env) @@ -1498,70 +1491,75 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) SYSREG_OP2(reg), val); - switch (reg) { - case SYSREG_PMCCNTR_EL0: - pmu_op_start(env); - env->cp15.c15_ccnt = val; - pmu_op_finish(env); - break; - case SYSREG_PMCR_EL0: - pmu_op_start(env); - - if (val & PMCRC) { - /* The counter has been reset */ - env->cp15.c15_ccnt = 0; - } + if (arm_feature(env, ARM_FEATURE_PMU)) { + switch (reg) { + case SYSREG_PMCCNTR_EL0: + pmu_op_start(env); + env->cp15.c15_ccnt = val; + pmu_op_finish(env); + return 0; + case SYSREG_PMCR_EL0: + pmu_op_start(env); + + if (val & PMCRC) { + /* The counter has been reset */ + env->cp15.c15_ccnt = 0; + } - if (val & PMCRP) { - unsigned int i; - for (i = 0; i < pmu_num_counters(env); i++) { - env->cp15.c14_pmevcntr[i] = 0; + if (val & PMCRP) { + unsigned int i; + for (i = 0; i < pmu_num_counters(env); i++) { + env->cp15.c14_pmevcntr[i] = 0; + } } - } - env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; - env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK); + env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK); + + pmu_op_finish(env); + return 0; + case SYSREG_PMUSERENR_EL0: + env->cp15.c9_pmuserenr = val & 0xf; + return 0; + case SYSREG_PMCNTENSET_EL0: + env->cp15.c9_pmcnten |= (val & pmu_counter_mask(env)); + return 0; + case SYSREG_PMCNTENCLR_EL0: + env->cp15.c9_pmcnten &= ~(val & pmu_counter_mask(env)); + return 0; + case SYSREG_PMINTENCLR_EL1: + pmu_op_start(env); + env->cp15.c9_pminten |= val; + pmu_op_finish(env); + return 0; + case SYSREG_PMOVSCLR_EL0: + pmu_op_start(env); + env->cp15.c9_pmovsr &= ~val; + pmu_op_finish(env); + return 0; + case SYSREG_PMSWINC_EL0: + pmu_op_start(env); + pmswinc_write(env, val); + pmu_op_finish(env); + return 0; + case SYSREG_PMSELR_EL0: + env->cp15.c9_pmselr = val & 0x1f; + return 0; + case SYSREG_PMCCFILTR_EL0: + pmu_op_start(env); + env->cp15.pmccfiltr_el0 = val & PMCCFILTR_EL0; + pmu_op_finish(env); + return 0; + } + } - pmu_op_finish(env); - break; - case SYSREG_PMUSERENR_EL0: - env->cp15.c9_pmuserenr = val & 0xf; - break; - case SYSREG_PMCNTENSET_EL0: - env->cp15.c9_pmcnten |= (val & pmu_counter_mask(env)); - break; - case SYSREG_PMCNTENCLR_EL0: - env->cp15.c9_pmcnten &= ~(val & pmu_counter_mask(env)); - break; - case SYSREG_PMINTENCLR_EL1: - pmu_op_start(env); - env->cp15.c9_pminten |= val; - pmu_op_finish(env); - break; - case SYSREG_PMOVSCLR_EL0: - pmu_op_start(env); - env->cp15.c9_pmovsr &= ~val; - pmu_op_finish(env); - break; - case SYSREG_PMSWINC_EL0: - pmu_op_start(env); - pmswinc_write(env, val); - pmu_op_finish(env); - break; - case SYSREG_PMSELR_EL0: - env->cp15.c9_pmselr = val & 0x1f; - break; - case SYSREG_PMCCFILTR_EL0: - pmu_op_start(env); - env->cp15.pmccfiltr_el0 = val & PMCCFILTR_EL0; - pmu_op_finish(env); - break; + switch (reg) { case SYSREG_OSLAR_EL1: env->cp15.oslsr_el1 = val & 1; - break; + return 0; case SYSREG_OSDLR_EL1: /* Dummy register */ - break; + return 0; case SYSREG_ICC_AP0R0_EL1: case SYSREG_ICC_AP0R1_EL1: case SYSREG_ICC_AP0R2_EL1: @@ -1588,13 +1586,13 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_ICC_SGI1R_EL1: case SYSREG_ICC_SRE_EL1: /* Call the TCG sysreg handler. This is only safe for GICv3 regs. */ - if (!hvf_sysreg_write_cp(cpu, reg, val)) { - hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); + if (hvf_sysreg_write_cp(cpu, reg, val)) { + return 0; } break; case SYSREG_MDSCR_EL1: env->cp15.mdscr_el1 = val; - break; + return 0; case SYSREG_DBGBVR0_EL1: case SYSREG_DBGBVR1_EL1: case SYSREG_DBGBVR2_EL1: @@ -1612,7 +1610,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_DBGBVR14_EL1: case SYSREG_DBGBVR15_EL1: env->cp15.dbgbvr[SYSREG_CRM(reg)] = val; - break; + return 0; case SYSREG_DBGBCR0_EL1: case SYSREG_DBGBCR1_EL1: case SYSREG_DBGBCR2_EL1: @@ -1630,7 +1628,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_DBGBCR14_EL1: case SYSREG_DBGBCR15_EL1: env->cp15.dbgbcr[SYSREG_CRM(reg)] = val; - break; + return 0; case SYSREG_DBGWVR0_EL1: case SYSREG_DBGWVR1_EL1: case SYSREG_DBGWVR2_EL1: @@ -1648,7 +1646,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_DBGWVR14_EL1: case SYSREG_DBGWVR15_EL1: env->cp15.dbgwvr[SYSREG_CRM(reg)] = val; - break; + return 0; case SYSREG_DBGWCR0_EL1: case SYSREG_DBGWCR1_EL1: case SYSREG_DBGWCR2_EL1: @@ -1666,20 +1664,18 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val) case SYSREG_DBGWCR14_EL1: case SYSREG_DBGWCR15_EL1: env->cp15.dbgwcr[SYSREG_CRM(reg)] = val; - break; - default: - cpu_synchronize_state(cpu); - trace_hvf_unhandled_sysreg_write(env->pc, reg, - SYSREG_OP0(reg), - SYSREG_OP1(reg), - SYSREG_CRN(reg), - SYSREG_CRM(reg), - SYSREG_OP2(reg)); - hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); - return 1; + return 0; } - return 0; + cpu_synchronize_state(cpu); + trace_hvf_unhandled_sysreg_write(env->pc, reg, + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg)); + hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized()); + return 1; } static int hvf_inject_interrupts(CPUState *cpu) @@ -1944,7 +1940,17 @@ int hvf_vcpu_exec(CPUState *cpu) int sysreg_ret = 0; if (isread) { - sysreg_ret = hvf_sysreg_read(cpu, reg, rt); + sysreg_ret = hvf_sysreg_read(cpu, reg, &val); + if (!sysreg_ret) { + trace_hvf_sysreg_read(reg, + SYSREG_OP0(reg), + SYSREG_OP1(reg), + SYSREG_CRN(reg), + SYSREG_CRM(reg), + SYSREG_OP2(reg), + val); + hvf_set_reg(cpu, rt, val); + } } else { val = hvf_get_reg(cpu, rt); sysreg_ret = hvf_sysreg_write(cpu, reg, val); |