mirror of https://github.com/xemu-project/xemu.git
target/arm/helper: Implement CNTHCTL_EL2.CNT[VP]MASK
When FEAT_RME is implemented, these bits override the value of CNT[VP]_CTL_EL0.IMASK in Realm and Root state. Move the IRQ state update into a new gt_update_irq() function and test those bits every time we recompute the IRQ state. Since we're removing the IRQ state from some trace events, add a new trace event for gt_update_irq(). Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> Message-id: 20230809123706.1842548-7-jean-philippe@linaro.org [PMM: only register change hook if not USER_ONLY and if TCG] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
1acd00ef14
commit
f6fc36deef
|
@ -2169,6 +2169,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
set_feature(env, ARM_FEATURE_VBAR);
|
set_feature(env, ARM_FEATURE_VBAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
if (tcg_enabled() && cpu_isar_feature(aa64_rme, cpu)) {
|
||||||
|
arm_register_el_change_hook(cpu, >_rme_post_el_change, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
register_cp_regs_for_features(cpu);
|
register_cp_regs_for_features(cpu);
|
||||||
arm_cpu_register_gdb_regs_for_features(cpu);
|
arm_cpu_register_gdb_regs_for_features(cpu);
|
||||||
|
|
||||||
|
|
|
@ -1115,6 +1115,7 @@ struct ArchCPU {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
|
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
|
||||||
|
void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
|
||||||
|
|
||||||
void arm_cpu_post_init(Object *obj);
|
void arm_cpu_post_init(Object *obj);
|
||||||
|
|
||||||
|
@ -1743,6 +1744,9 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||||
#define HSTR_TTEE (1 << 16)
|
#define HSTR_TTEE (1 << 16)
|
||||||
#define HSTR_TJDBX (1 << 17)
|
#define HSTR_TJDBX (1 << 17)
|
||||||
|
|
||||||
|
#define CNTHCTL_CNTVMASK (1 << 18)
|
||||||
|
#define CNTHCTL_CNTPMASK (1 << 19)
|
||||||
|
|
||||||
/* Return the current FPSCR value. */
|
/* Return the current FPSCR value. */
|
||||||
uint32_t vfp_get_fpscr(CPUARMState *env);
|
uint32_t vfp_get_fpscr(CPUARMState *env);
|
||||||
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
|
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
|
||||||
|
|
|
@ -2608,6 +2608,39 @@ static uint64_t gt_get_countervalue(CPUARMState *env)
|
||||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu);
|
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gt_update_irq(ARMCPU *cpu, int timeridx)
|
||||||
|
{
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
|
uint64_t cnthctl = env->cp15.cnthctl_el2;
|
||||||
|
ARMSecuritySpace ss = arm_security_space(env);
|
||||||
|
/* ISTATUS && !IMASK */
|
||||||
|
int irqstate = (env->cp15.c14_timer[timeridx].ctl & 6) == 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If bit CNTHCTL_EL2.CNT[VP]MASK is set, it overrides IMASK.
|
||||||
|
* It is RES0 in Secure and NonSecure state.
|
||||||
|
*/
|
||||||
|
if ((ss == ARMSS_Root || ss == ARMSS_Realm) &&
|
||||||
|
((timeridx == GTIMER_VIRT && (cnthctl & CNTHCTL_CNTVMASK)) ||
|
||||||
|
(timeridx == GTIMER_PHYS && (cnthctl & CNTHCTL_CNTPMASK)))) {
|
||||||
|
irqstate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
|
||||||
|
trace_arm_gt_update_irq(timeridx, irqstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gt_rme_post_el_change(ARMCPU *cpu, void *ignored)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Changing security state between Root and Secure/NonSecure, which may
|
||||||
|
* happen when switching EL, can change the effective value of CNTHCTL_EL2
|
||||||
|
* mask bits. Update the IRQ state accordingly.
|
||||||
|
*/
|
||||||
|
gt_update_irq(cpu, GTIMER_VIRT);
|
||||||
|
gt_update_irq(cpu, GTIMER_PHYS);
|
||||||
|
}
|
||||||
|
|
||||||
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||||
{
|
{
|
||||||
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
|
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
|
||||||
|
@ -2623,13 +2656,9 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||||
/* Note that this must be unsigned 64 bit arithmetic: */
|
/* Note that this must be unsigned 64 bit arithmetic: */
|
||||||
int istatus = count - offset >= gt->cval;
|
int istatus = count - offset >= gt->cval;
|
||||||
uint64_t nexttick;
|
uint64_t nexttick;
|
||||||
int irqstate;
|
|
||||||
|
|
||||||
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
|
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
|
||||||
|
|
||||||
irqstate = (istatus && !(gt->ctl & 2));
|
|
||||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
|
|
||||||
|
|
||||||
if (istatus) {
|
if (istatus) {
|
||||||
/* Next transition is when count rolls back over to zero */
|
/* Next transition is when count rolls back over to zero */
|
||||||
nexttick = UINT64_MAX;
|
nexttick = UINT64_MAX;
|
||||||
|
@ -2648,14 +2677,14 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||||
} else {
|
} 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, nexttick);
|
||||||
} else {
|
} else {
|
||||||
/* Timer disabled: ISTATUS and timer output always clear */
|
/* Timer disabled: ISTATUS and timer output always clear */
|
||||||
gt->ctl &= ~4;
|
gt->ctl &= ~4;
|
||||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0);
|
|
||||||
timer_del(cpu->gt_timer[timeridx]);
|
timer_del(cpu->gt_timer[timeridx]);
|
||||||
trace_arm_gt_recalc_disabled(timeridx);
|
trace_arm_gt_recalc_disabled(timeridx);
|
||||||
}
|
}
|
||||||
|
gt_update_irq(cpu, timeridx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
@ -2759,10 +2788,8 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
* IMASK toggled: don't need to recalculate,
|
* IMASK toggled: don't need to recalculate,
|
||||||
* just set the interrupt line based on ISTATUS
|
* just set the interrupt line based on ISTATUS
|
||||||
*/
|
*/
|
||||||
int irqstate = (oldval & 4) && !(value & 2);
|
trace_arm_gt_imask_toggle(timeridx);
|
||||||
|
gt_update_irq(cpu, timeridx);
|
||||||
trace_arm_gt_imask_toggle(timeridx, irqstate);
|
|
||||||
qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2888,6 +2915,21 @@ static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
gt_ctl_write(env, ri, GTIMER_VIRT, value);
|
gt_ctl_write(env, ri, GTIMER_VIRT, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
uint32_t oldval = env->cp15.cnthctl_el2;
|
||||||
|
|
||||||
|
raw_write(env, ri, value);
|
||||||
|
|
||||||
|
if ((oldval ^ value) & CNTHCTL_CNTVMASK) {
|
||||||
|
gt_update_irq(cpu, GTIMER_VIRT);
|
||||||
|
} else if ((oldval ^ value) & CNTHCTL_CNTPMASK) {
|
||||||
|
gt_update_irq(cpu, GTIMER_PHYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
|
@ -6203,7 +6245,8 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
||||||
* reset values as IMPDEF. We choose to reset to 3 to comply with
|
* reset values as IMPDEF. We choose to reset to 3 to comply with
|
||||||
* both ARMv7 and ARMv8.
|
* both ARMv7 and ARMv8.
|
||||||
*/
|
*/
|
||||||
.access = PL2_RW, .resetvalue = 3,
|
.access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 3,
|
||||||
|
.writefn = gt_cnthctl_write, .raw_writefn = raw_write,
|
||||||
.fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) },
|
.fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) },
|
||||||
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
|
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
|
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
# See docs/devel/tracing.rst for syntax documentation.
|
# See docs/devel/tracing.rst for syntax documentation.
|
||||||
|
|
||||||
# helper.c
|
# helper.c
|
||||||
arm_gt_recalc(int timer, int irqstate, uint64_t nexttick) "gt recalc: timer %d irqstate %d next tick 0x%" PRIx64
|
arm_gt_recalc(int timer, uint64_t nexttick) "gt recalc: timer %d next tick 0x%" PRIx64
|
||||||
arm_gt_recalc_disabled(int timer) "gt recalc: timer %d irqstate 0 timer disabled"
|
arm_gt_recalc_disabled(int timer) "gt recalc: timer %d timer disabled"
|
||||||
arm_gt_cval_write(int timer, uint64_t value) "gt_cval_write: timer %d value 0x%" PRIx64
|
arm_gt_cval_write(int timer, uint64_t value) "gt_cval_write: timer %d value 0x%" PRIx64
|
||||||
arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write: timer %d value 0x%" PRIx64
|
arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write: timer %d value 0x%" PRIx64
|
||||||
arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value 0x%" PRIx64
|
arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value 0x%" PRIx64
|
||||||
arm_gt_imask_toggle(int timer, int irqstate) "gt_ctl_write: timer %d IMASK toggle, new irqstate %d"
|
arm_gt_imask_toggle(int timer) "gt_ctl_write: timer %d IMASK toggle"
|
||||||
arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64
|
arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64
|
||||||
|
arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
|
||||||
|
|
||||||
# kvm.c
|
# kvm.c
|
||||||
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
|
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
|
||||||
|
|
Loading…
Reference in New Issue