mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 00:03:54 -06:00
target/arm: Implement FEAT WFxT and enable for '-cpu max'
FEAT_WFxT introduces new instructions WFIT and WFET, which are like the existing WFI and WFE but allow the guest to pass a timeout value in a register. The instructions will wait for an interrupt/event as usual, but will also stop waiting when the value of CNTVCT_EL0 is greater than or equal to the specified timeout value. We implement WFIT by setting up a timer to expire at the right point; when the timer expires it sets the EXITTB interrupt, which will cause the CPU to leave the halted state. If we come out of halt for some other reason, we unset the pending timer. We implement WFET as a nop, which is architecturally permitted and matches the way we currently make WFE a nop. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20240430140035.3889879-3-peter.maydell@linaro.org
This commit is contained in:
parent
408b2b3d9d
commit
a96edb687e
12 changed files with 180 additions and 2 deletions
|
@ -1132,6 +1132,35 @@ static bool arm_cpu_virtio_is_big_endian(CPUState *cs)
|
|||
return arm_cpu_data_is_big_endian(env);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCG
|
||||
static bool arm_cpu_exec_halt(CPUState *cs)
|
||||
{
|
||||
bool leave_halt = cpu_has_work(cs);
|
||||
|
||||
if (leave_halt) {
|
||||
/* We're about to come out of WFI/WFE: disable the WFxT timer */
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
if (cpu->wfxt_timer) {
|
||||
timer_del(cpu->wfxt_timer);
|
||||
}
|
||||
}
|
||||
return leave_halt;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void arm_wfxt_timer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
/*
|
||||
* We expect the CPU to be halted; this will cause arm_cpu_is_work()
|
||||
* to return true (so we will come out of halt even with no other
|
||||
* pending interrupt), and the TCG accelerator's cpu_exec_interrupt()
|
||||
* function auto-clears the CPU_INTERRUPT_EXITTB flag for us.
|
||||
*/
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
|
@ -1877,6 +1906,9 @@ static void arm_cpu_finalizefn(Object *obj)
|
|||
if (cpu->pmu_timer) {
|
||||
timer_free(cpu->pmu_timer);
|
||||
}
|
||||
if (cpu->wfxt_timer) {
|
||||
timer_free(cpu->wfxt_timer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2369,6 +2401,13 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (tcg_enabled() && cpu_isar_feature(aa64_wfxt, cpu)) {
|
||||
cpu->wfxt_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
arm_wfxt_timer_cb, cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tcg_enabled()) {
|
||||
/*
|
||||
* Don't report some architectural features in the ID registers
|
||||
|
@ -2625,6 +2664,7 @@ static const TCGCPUOps arm_tcg_ops = {
|
|||
#else
|
||||
.tlb_fill = arm_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
|
||||
.cpu_exec_halt = arm_cpu_exec_halt,
|
||||
.do_interrupt = arm_cpu_do_interrupt,
|
||||
.do_transaction_failed = arm_cpu_do_transaction_failed,
|
||||
.do_unaligned_access = arm_cpu_do_unaligned_access,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue