target-arm: Add CNTVOFF_EL2

Adds support for the virtual timer offset controlled by EL2.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 1436791864-4582-2-git-send-email-edgar.iglesias@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Edgar E. Iglesias 2015-08-13 11:26:17 +01:00 committed by Peter Maydell
parent ca0e5d8b0d
commit edac4d8a16
2 changed files with 42 additions and 6 deletions
target-arm

View File

@ -358,6 +358,7 @@ typedef struct CPUARMState {
}; };
uint64_t c14_cntfrq; /* Counter Frequency register */ uint64_t c14_cntfrq; /* Counter Frequency register */
uint64_t c14_cntkctl; /* Timer Control register */ uint64_t c14_cntkctl; /* Timer Control register */
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
ARMGenericTimer c14_timer[NUM_GTIMERS]; ARMGenericTimer c14_timer[NUM_GTIMERS];
uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_cpar; /* XScale Coprocessor Access Register */
uint32_t c15_ticonfig; /* TI925T configuration byte. */ uint32_t c15_ticonfig; /* TI925T configuration byte. */

View File

@ -1209,9 +1209,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
/* Timer enabled: calculate and set current ISTATUS, irq, and /* Timer enabled: calculate and set current ISTATUS, irq, and
* reset timer to when ISTATUS next has to change * reset timer to when ISTATUS next has to change
*/ */
uint64_t offset = timeridx == GTIMER_VIRT ?
cpu->env.cp15.cntvoff_el2 : 0;
uint64_t count = gt_get_countervalue(&cpu->env); uint64_t count = gt_get_countervalue(&cpu->env);
/* Note that this must be unsigned 64 bit arithmetic: */ /* Note that this must be unsigned 64 bit arithmetic: */
int istatus = count >= gt->cval; int istatus = count - offset >= gt->cval;
uint64_t nexttick; uint64_t nexttick;
gt->ctl = deposit32(gt->ctl, 2, 1, istatus); gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
@ -1222,7 +1224,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
nexttick = UINT64_MAX; nexttick = UINT64_MAX;
} else { } else {
/* Next transition is when we hit cval */ /* Next transition is when we hit cval */
nexttick = gt->cval; nexttick = gt->cval + offset;
} }
/* Note that the desired next expiry time might be beyond the /* Note that the desired next expiry time might be beyond the
* signed-64-bit range of a QEMUTimer -- in this case we just * signed-64-bit range of a QEMUTimer -- in this case we just
@ -1254,6 +1256,11 @@ static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
return gt_get_countervalue(env); return gt_get_countervalue(env);
} }
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
return gt_get_countervalue(env) - env->cp15.cntvoff_el2;
}
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
@ -1266,17 +1273,19 @@ static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
{ {
int timeridx = ri->crm & 1; int timeridx = ri->crm & 1;
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
return (uint32_t)(env->cp15.c14_timer[timeridx].cval - return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
gt_get_countervalue(env)); (gt_get_countervalue(env) - offset));
} }
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value) uint64_t value)
{ {
int timeridx = ri->crm & 1; int timeridx = ri->crm & 1;
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) + env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
sextract64(value, 0, 32); sextract64(value, 0, 32);
gt_recalc_timer(arm_env_get_cpu(env), timeridx); gt_recalc_timer(arm_env_get_cpu(env), timeridx);
} }
@ -1301,6 +1310,15 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
} }
} }
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
raw_write(env, ri, value);
gt_recalc_timer(cpu, GTIMER_VIRT);
}
void arm_gt_ptimer_cb(void *opaque) void arm_gt_ptimer_cb(void *opaque)
{ {
ARMCPU *cpu = opaque; ARMCPU *cpu = opaque;
@ -1407,13 +1425,13 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access, .accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore, .readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
}, },
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64, { .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access, .accessfn = gt_vct_access,
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset, .readfn = gt_virt_cnt_read, .resetfn = gt_cnt_reset,
}, },
/* Comparison value, indicating when the timer goes off */ /* Comparison value, indicating when the timer goes off */
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
@ -2613,6 +2631,12 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2, { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 }, .resetvalue = 0 },
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 },
REGINFO_SENTINEL REGINFO_SENTINEL
}; };
@ -2724,6 +2748,17 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W, .type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbi_aa64_vaa_write }, .writefn = tlbi_aa64_vaa_write },
#ifndef CONFIG_USER_ONLY
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
.access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
.writefn = gt_cntvoff_write,
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO,
.writefn = gt_cntvoff_write,
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
#endif
REGINFO_SENTINEL REGINFO_SENTINEL
}; };