diff options
Diffstat (limited to 'target-arm/helper.c')
-rw-r--r-- | target-arm/helper.c | 74 |
1 files changed, 70 insertions, 4 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c index 25f612d493..cb83ee2008 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "trace.h" #include "cpu.h" #include "internals.h" #include "exec/gdbstub.h" @@ -1560,10 +1561,13 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) /* Note that this must be unsigned 64 bit arithmetic: */ int istatus = count - offset >= gt->cval; uint64_t nexttick; + int irqstate; gt->ctl = deposit32(gt->ctl, 2, 1, istatus); - qemu_set_irq(cpu->gt_timer_outputs[timeridx], - (istatus && !(gt->ctl & 2))); + + irqstate = (istatus && !(gt->ctl & 2)); + qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate); + if (istatus) { /* Next transition is when count rolls back over to zero */ nexttick = UINT64_MAX; @@ -1580,11 +1584,13 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) nexttick = INT64_MAX / GTIMER_SCALE; } timer_mod(cpu->gt_timer[timeridx], nexttick); + trace_arm_gt_recalc(timeridx, irqstate, nexttick); } else { /* Timer disabled: ISTATUS and timer output always clear */ gt->ctl &= ~4; qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0); timer_del(cpu->gt_timer[timeridx]); + trace_arm_gt_recalc_disabled(timeridx); } } @@ -1610,6 +1616,7 @@ static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, int timeridx, uint64_t value) { + trace_arm_gt_cval_write(timeridx, value); env->cp15.c14_timer[timeridx].cval = value; gt_recalc_timer(arm_env_get_cpu(env), timeridx); } @@ -1629,6 +1636,7 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, { uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0; + trace_arm_gt_tval_write(timeridx, value); env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset + sextract64(value, 0, 32); gt_recalc_timer(arm_env_get_cpu(env), timeridx); @@ -1641,6 +1649,7 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, ARMCPU *cpu = arm_env_get_cpu(env); uint32_t oldval = env->cp15.c14_timer[timeridx].ctl; + trace_arm_gt_ctl_write(timeridx, value); env->cp15.c14_timer[timeridx].ctl = deposit64(oldval, 0, 2, value); if ((oldval ^ value) & 1) { /* Enable toggled */ @@ -1649,8 +1658,10 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, /* IMASK toggled: don't need to recalculate, * just set the interrupt line based on ISTATUS */ - qemu_set_irq(cpu->gt_timer_outputs[timeridx], - (oldval & 4) && !(value & 2)); + int irqstate = (oldval & 4) && !(value & 2); + + trace_arm_gt_imask_toggle(timeridx, irqstate); + qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate); } } @@ -1715,6 +1726,7 @@ static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = arm_env_get_cpu(env); + trace_arm_gt_cntvoff_write(value); raw_write(env, ri, value); gt_recalc_timer(cpu, GTIMER_VIRT); } @@ -4060,6 +4072,14 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, .access = PL1_RW, .accessfn = access_tda, .type = ARM_CP_NOP }, + /* Dummy MDCCINT_EL1, since we don't implement the Debug Communications + * Channel but Linux may try to access this register. The 32-bit + * alias is DBGDCCINT. + */ + { .name = "MDCCINT_EL1", .state = ARM_CP_STATE_BOTH, + .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_RW, .accessfn = access_tda, + .type = ARM_CP_NOP }, REGINFO_SENTINEL }; @@ -6720,6 +6740,52 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } +/* Returns TBI0 value for current regime el */ +uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return extract64(tcr->raw_tcr, 20, 1); + } else { + return extract64(tcr->raw_tcr, 37, 1); + } +} + +/* Returns TBI1 value for current regime el */ +uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return 0; + } else { + return extract64(tcr->raw_tcr, 38, 1); + } +} + /* Return the TTBR associated with this translation regime */ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) |