Implement the AArch64 view of the generic timer system registers. Signed-off-by: Peter Maydell <peter.maydell@xxxxxxxxxx> --- target-arm/cpu.h | 6 +-- target-arm/helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7138882..2aeb0c2 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -104,7 +104,7 @@ struct arm_boot_info; /* CPU state for each instance of a generic timer (in cp15 c14) */ typedef struct ARMGenericTimer { uint64_t cval; /* Timer CompareValue register */ - uint32_t ctl; /* Timer Control register */ + uint64_t ctl; /* Timer Control register */ } ARMGenericTimer; #define GTIMER_PHYS 0 @@ -204,8 +204,8 @@ typedef struct CPUARMState { uint64_t tpidr_el0; /* User RW Thread register. */ uint64_t tpidrro_el0; /* User RO Thread register. */ uint64_t tpidr_el1; /* Privileged Thread register. */ - uint32_t c14_cntfrq; /* Counter Frequency register */ - uint32_t c14_cntkctl; /* Timer Control register */ + uint64_t c14_cntfrq; /* Counter Frequency register */ + uint64_t c14_cntkctl; /* Timer Control register */ ARMGenericTimer c14_timer[NUM_GTIMERS]; uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_ticonfig; /* TI925T configuration byte. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index ef74d10..d7f2a82 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -845,7 +845,7 @@ static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri, static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = arm_env_get_cpu(env); - int timeridx = ri->opc1 & 1; + int timeridx = ri->opc2 - 1; timer_del(cpu->gt_timer[timeridx]); } @@ -863,6 +863,19 @@ static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int gt_cnt_read64(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->opc2 - 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, timeridx, 1)) { + return EXCP_UDEF; + } + *value = gt_get_countervalue(env); + return 0; +} + static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { @@ -876,6 +889,19 @@ static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri, return 0; } +static int gt_cval_read64(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) +{ + int timeridx = ri->crm & 1; + + if (arm_current_pl(env) == 0 && + !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { + return EXCP_UDEF; + } + *value = env->cp15.c14_timer[timeridx].cval; + return 0; +} + static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -885,6 +911,17 @@ static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, gt_recalc_timer(arm_env_get_cpu(env), timeridx); return 0; } + +static int gt_cval_write64(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + int timeridx = ri->crm & 1; + + env->cp15.c14_timer[timeridx].cval = value; + gt_recalc_timer(arm_env_get_cpu(env), timeridx); + return 0; +} + static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { @@ -964,19 +1001,36 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { * Our reset value matches the fixed frequency we implement the timer at. */ { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW | PL0_R, .type = ARM_CP_NO_MIGRATE, + .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_cntfrq), + .resetfn = arm_cp_reset_ignore, + .readfn = gt_cntfrq_read, .raw_readfn = raw_read, + }, + { .name = "CNTFRQ_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 0, .access = PL1_RW | PL0_R, .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq), .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE, .readfn = gt_cntfrq_read, .raw_readfn = raw_read, }, /* overall control: mostly access permissions */ - { .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0, + { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl), .resetvalue = 0, }, /* per-timer control */ { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, + .type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R, + .fieldoffset = offsetoflow32(CPUARMState, + cp15.c14_timer[GTIMER_PHYS].ctl), + .resetfn = arm_cp_reset_ignore, + .readfn = gt_ctl_read, .writefn = gt_ctl_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + { .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1, .type = ARM_CP_IO, .access = PL1_RW | PL0_R, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), .resetvalue = 0, @@ -984,6 +1038,15 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .raw_readfn = raw_read, .raw_writefn = raw_write, }, { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, + .type = ARM_CP_IO | ARM_CP_NO_MIGRATE, .access = PL1_RW | PL0_R, + .fieldoffset = offsetoflow32(CPUARMState, + cp15.c14_timer[GTIMER_VIRT].ctl), + .resetfn = arm_cp_reset_ignore, + .readfn = gt_ctl_read, .writefn = gt_ctl_write, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, + { .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1, .type = ARM_CP_IO, .access = PL1_RW | PL0_R, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), .resetvalue = 0, @@ -995,36 +1058,74 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, .readfn = gt_tval_read, .writefn = gt_tval_write, }, + { .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0, + .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, + .readfn = gt_tval_read, .writefn = gt_tval_write, + }, { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, .readfn = gt_tval_read, .writefn = gt_tval_write, }, + { .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0, + .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R, + .readfn = gt_tval_read, .writefn = gt_tval_write, + }, /* The counter itself */ { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, - .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + .readfn = gt_cnt_read, + }, + { .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1, + .access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, + .readfn = gt_cnt_read64, .resetfn = gt_cnt_reset, }, { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO, - .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + .readfn = gt_cnt_read, + }, + { .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2, + .access = PL0_R, .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, + .readfn = gt_cnt_read64, .resetfn = gt_cnt_reset, }, /* Comparison value, indicating when the timer goes off */ { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, .access = PL1_RW | PL0_R, - .type = ARM_CP_64BIT | ARM_CP_IO, + .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), - .resetvalue = 0, + .resetfn = arm_cp_reset_ignore, .readfn = gt_cval_read, .writefn = gt_cval_write, .raw_readfn = raw_read, .raw_writefn = raw_write, }, + { .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2, + .access = PL1_RW | PL0_R, + .type = ARM_CP_IO, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), + .resetvalue = 0, + .readfn = gt_cval_read64, .writefn = gt_cval_write64, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, .access = PL1_RW | PL0_R, - .type = ARM_CP_64BIT | ARM_CP_IO, + .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_MIGRATE, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .resetvalue = 0, .readfn = gt_cval_read, .writefn = gt_cval_write, .raw_readfn = raw_read, .raw_writefn = raw_write, }, + { .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2, + .access = PL1_RW | PL0_R, + .type = ARM_CP_IO, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), + .resetvalue = 0, + .readfn = gt_cval_read64, .writefn = gt_cval_write64, + .raw_readfn = raw_read, .raw_writefn = raw_write, + }, REGINFO_SENTINEL }; -- 1.8.5 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm