|
@@ -2449,7 +2449,9 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
|
|
|
|
|
|
static uint64_t gt_get_countervalue(CPUARMState *env)
|
|
static uint64_t gt_get_countervalue(CPUARMState *env)
|
|
{
|
|
{
|
|
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE;
|
|
|
|
|
|
+ ARMCPU *cpu = env_archcpu(env);
|
|
|
|
+
|
|
|
|
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu);
|
|
}
|
|
}
|
|
|
|
|
|
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
|
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
|
@@ -2485,10 +2487,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
|
* set the timer for as far in the future as possible. When the
|
|
* set the timer for as far in the future as possible. When the
|
|
* timer expires we will reset the timer for any remaining period.
|
|
* timer expires we will reset the timer for any remaining period.
|
|
*/
|
|
*/
|
|
- if (nexttick > INT64_MAX / GTIMER_SCALE) {
|
|
|
|
- nexttick = INT64_MAX / GTIMER_SCALE;
|
|
|
|
|
|
+ if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
|
|
|
|
+ timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX);
|
|
|
|
+ } else {
|
|
|
|
+ timer_mod(cpu->gt_timer[timeridx], nexttick);
|
|
}
|
|
}
|
|
- timer_mod(cpu->gt_timer[timeridx], nexttick);
|
|
|
|
trace_arm_gt_recalc(timeridx, irqstate, nexttick);
|
|
trace_arm_gt_recalc(timeridx, irqstate, nexttick);
|
|
} else {
|
|
} else {
|
|
/* Timer disabled: ISTATUS and timer output always clear */
|
|
/* Timer disabled: ISTATUS and timer output always clear */
|
|
@@ -2720,6 +2723,13 @@ void arm_gt_stimer_cb(void *opaque)
|
|
gt_recalc_timer(cpu, GTIMER_SEC);
|
|
gt_recalc_timer(cpu, GTIMER_SEC);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
|
|
|
|
+{
|
|
|
|
+ ARMCPU *cpu = env_archcpu(env);
|
|
|
|
+
|
|
|
|
+ cpu->env.cp15.c14_cntfrq = cpu->gt_cntfrq_hz;
|
|
|
|
+}
|
|
|
|
+
|
|
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
/* Note that CNTFRQ is purely reads-as-written for the benefit
|
|
/* Note that CNTFRQ is purely reads-as-written for the benefit
|
|
* of software; writing it doesn't actually change the timer frequency.
|
|
* of software; writing it doesn't actually change the timer frequency.
|
|
@@ -2734,7 +2744,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
|
|
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0,
|
|
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
|
|
.access = PL1_RW | PL0_R, .accessfn = gt_cntfrq_access,
|
|
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
|
|
.fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
|
|
- .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
|
|
|
|
|
|
+ .resetfn = arm_gt_cntfrq_reset,
|
|
},
|
|
},
|
|
/* overall control: mostly access permissions */
|
|
/* overall control: mostly access permissions */
|
|
{ .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
|
|
{ .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
|
|
@@ -2913,11 +2923,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
|
|
|
|
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
{
|
|
{
|
|
|
|
+ ARMCPU *cpu = env_archcpu(env);
|
|
|
|
+
|
|
/* Currently we have no support for QEMUTimer in linux-user so we
|
|
/* Currently we have no support for QEMUTimer in linux-user so we
|
|
* can't call gt_get_countervalue(env), instead we directly
|
|
* can't call gt_get_countervalue(env), instead we directly
|
|
* call the lower level functions.
|
|
* call the lower level functions.
|
|
*/
|
|
*/
|
|
- return cpu_get_clock() / GTIMER_SCALE;
|
|
|
|
|
|
+ return cpu_get_clock() / gt_cntfrq_period_ns(cpu);
|
|
}
|
|
}
|
|
|
|
|
|
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
|
@@ -11500,6 +11512,20 @@ void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el)
|
|
env->hflags = rebuild_hflags_a64(env, el, fp_el, mmu_idx);
|
|
env->hflags = rebuild_hflags_a64(env, el, fp_el, mmu_idx);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
|
|
|
|
+{
|
|
|
|
+#ifdef CONFIG_DEBUG_TCG
|
|
|
|
+ uint32_t env_flags_current = env->hflags;
|
|
|
|
+ uint32_t env_flags_rebuilt = rebuild_hflags_internal(env);
|
|
|
|
+
|
|
|
|
+ if (unlikely(env_flags_current != env_flags_rebuilt)) {
|
|
|
|
+ fprintf(stderr, "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n",
|
|
|
|
+ env_flags_current, env_flags_rebuilt);
|
|
|
|
+ abort();
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
|
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
|
target_ulong *cs_base, uint32_t *pflags)
|
|
target_ulong *cs_base, uint32_t *pflags)
|
|
{
|
|
{
|
|
@@ -11507,9 +11533,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
|
uint32_t pstate_for_ss;
|
|
uint32_t pstate_for_ss;
|
|
|
|
|
|
*cs_base = 0;
|
|
*cs_base = 0;
|
|
-#ifdef CONFIG_DEBUG_TCG
|
|
|
|
- assert(flags == rebuild_hflags_internal(env));
|
|
|
|
-#endif
|
|
|
|
|
|
+ assert_hflags_rebuild_correctly(env);
|
|
|
|
|
|
if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) {
|
|
if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) {
|
|
*pc = env->pc;
|
|
*pc = env->pc;
|