target/ppc: introduce ppc_maybe_interrupt

This new method will check if any pending interrupt was unmasked and
then call cpu_interrupt/cpu_reset_interrupt accordingly. Code that
raises/lowers or masks/unmasks interrupts should call this method to
keep CPU_INTERRUPT_HARD coherent with env->pending_interrupts.

Signed-off-by: Matheus Ferst <matheus.ferst@eldorado.org.br>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Message-Id: <20221021142156.4134411-2-matheus.ferst@eldorado.org.br>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
This commit is contained in:
Matheus Ferst 2022-10-21 11:21:54 -03:00 committed by Daniel Henrique Barboza
parent 6a8e8188c3
commit 2fdedcbc69
10 changed files with 67 additions and 8 deletions

View file

@ -390,6 +390,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
env->nip = vector;
env->msr = msr;
hreg_compute_hflags(env);
ppc_maybe_interrupt(env);
powerpc_reset_excp_state(cpu);
@ -2044,6 +2045,40 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env)
}
}
/*
* Sets CPU_INTERRUPT_HARD if there is at least one unmasked interrupt to be
* delivered and clears CPU_INTERRUPT_HARD otherwise.
*
* This method is called by ppc_set_interrupt when an interrupt is raised or
* lowered, and should also be called whenever an interrupt masking condition
* is changed, e.g.:
* - When relevant bits of MSR are altered, like EE, HV, PR, etc.;
* - When relevant bits of LPCR are altered, like PECE, HDICE, HVICE, etc.;
* - When PSSCR[EC] or env->resume_as_sreset are changed;
* - When cs->halted is changed and the CPU has a different interrupt masking
* logic in power-saving mode (e.g., POWER7/8/9/10);
*/
void ppc_maybe_interrupt(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
bool locked = false;
if (!qemu_mutex_iothread_locked()) {
locked = true;
qemu_mutex_lock_iothread();
}
if (ppc_next_unmasked_interrupt(env)) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
if (locked) {
qemu_mutex_unlock_iothread();
}
}
#if defined(TARGET_PPC64)
static void p7_deliver_interrupt(CPUPPCState *env, int interrupt)
{
@ -2479,6 +2514,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
}
}
void helper_ppc_maybe_interrupt(CPUPPCState *env)
{
ppc_maybe_interrupt(env);
}
#if defined(TARGET_PPC64)
void helper_scv(CPUPPCState *env, uint32_t lev)
{
@ -2499,6 +2539,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
/* Condition for waking up at 0x100 */
env->resume_as_sreset = (insn != PPC_PM_STOP) ||
(env->spr[SPR_PSSCR] & PSSCR_EC);
ppc_maybe_interrupt(env);
}
#endif /* defined(TARGET_PPC64) */