diff mbox series

[11/11] target/hppa: call eval_interrupt() after ssm

Message ID 20190311191602.25796-12-svens@stackframe.org (mailing list archive)
State New, archived
Headers show
Series target/hppa patches | expand

Commit Message

Sven Schnelle March 11, 2019, 7:16 p.m. UTC
HP-UX (all versions) is losing timer interrupts, which leads to
hangs. Pressing a key on the console fixes this, so it looks like
QEMU is just looping trough TBs without checking for interrupts.
Further investion showed that this happens when interrupts are
triggered, without PSW_I enabled. Calling eval_interrupt() after
PSW_I is set seems to fix this.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
---
 target/hppa/cpu.h        | 1 +
 target/hppa/int_helper.c | 2 +-
 target/hppa/op_helper.c  | 6 ++++++
 3 files changed, 8 insertions(+), 1 deletion(-)

Comments

Richard Henderson March 12, 2019, 3:28 a.m. UTC | #1
On 3/11/19 12:16 PM, Sven Schnelle wrote:
> HP-UX (all versions) is losing timer interrupts, which leads to
> hangs. Pressing a key on the console fixes this, so it looks like
> QEMU is just looping trough TBs without checking for interrupts.
> Further investion showed that this happens when interrupts are
> triggered, without PSW_I enabled. Calling eval_interrupt() after
> PSW_I is set seems to fix this.
> 
> Signed-off-by: Sven Schnelle <svens@stackframe.org>
> ---
>  target/hppa/cpu.h        | 1 +
>  target/hppa/int_helper.c | 2 +-
>  target/hppa/op_helper.c  | 6 ++++++
>  3 files changed, 8 insertions(+), 1 deletion(-)

The correct fix is to exit to the main loop.


r~
Richard Henderson March 12, 2019, 4:01 a.m. UTC | #2
On 3/11/19 8:28 PM, Richard Henderson wrote:
> On 3/11/19 12:16 PM, Sven Schnelle wrote:
>> HP-UX (all versions) is losing timer interrupts, which leads to
>> hangs. Pressing a key on the console fixes this, so it looks like
>> QEMU is just looping trough TBs without checking for interrupts.
>> Further investion showed that this happens when interrupts are
>> triggered, without PSW_I enabled. Calling eval_interrupt() after
>> PSW_I is set seems to fix this.
>>
>> Signed-off-by: Sven Schnelle <svens@stackframe.org>
>> ---
>>  target/hppa/cpu.h        | 1 +
>>  target/hppa/int_helper.c | 2 +-
>>  target/hppa/op_helper.c  | 6 ++++++
>>  3 files changed, 8 insertions(+), 1 deletion(-)
> 
> The correct fix is to exit to the main loop.

... except what we're already doing that.  So I don't see what
can be changed to help.  This doesn't seem to make a difference.


r~
Sven Schnelle March 12, 2019, 6:44 p.m. UTC | #3
Hi Richard,

On Mon, Mar 11, 2019 at 09:01:32PM -0700, Richard Henderson wrote:
> On 3/11/19 8:28 PM, Richard Henderson wrote:
> > On 3/11/19 12:16 PM, Sven Schnelle wrote:
> >> HP-UX (all versions) is losing timer interrupts, which leads to
> >> hangs. Pressing a key on the console fixes this, so it looks like
> >> QEMU is just looping trough TBs without checking for interrupts.
> >> Further investion showed that this happens when interrupts are
> >> triggered, without PSW_I enabled. Calling eval_interrupt() after
> >> PSW_I is set seems to fix this.
> >>
> >> Signed-off-by: Sven Schnelle <svens@stackframe.org>
> >> ---
> >>  target/hppa/cpu.h        | 1 +
> >>  target/hppa/int_helper.c | 2 +-
> >>  target/hppa/op_helper.c  | 6 ++++++
> >>  3 files changed, 8 insertions(+), 1 deletion(-)
> > 
> > The correct fix is to exit to the main loop.
> 
> ... except what we're already doing that.  So I don't see what
> can be changed to help.  This doesn't seem to make a difference.

I looked into this again, and with my limited TCG knowledge it looks like the
exit_tb is not happening because ssm is called in a branch delay slot:

This is the TB it's calling when it looses the timer interrupt:

IN: 
0x0000000000045758:  bv r0(rp)
0x000000000004575c:  ssm 1,r0

OP:
 ld_i32 tmp0,env,$0xffffffffffffffe0
 movi_i32 tmp1,$0x0
 brcond_i32 tmp0,tmp1,lt,$L0

 ---- 0000000000045758 000000000004575c
 mov_i32 tmp0,r2
 mov_i32 iaoq_b,tmp0

 ---- 000000000004575c 00000000ffffffff
 movi_i32 tmp1,$0x4
 add_i32 tmp0,iaoq_b,tmp1
 ld_i32 tmp1,env,$0x1c0
 movi_i32 tmp2,$0x1
 or_i32 tmp1,tmp1,tmp2
 call swap_system_mask,$0x1,$1,tmp1,env,tmp1

Everything above is ssm, and below this is the branch instruction, which skips
the exit_tb (i think):

 mov_i32 iaoq_f,iaoq_b
 mov_i32 iaoq_b,tmp0
 mov_i64 iasq_f,iasq_b
 call lookup_tb_ptr,$0x6,$1,tmp3,env
 goto_ptr tmp3
 set_label $L0
 exit_tb $0x7f373c33cb83

I might also be totally wrong, let me know if that's the case. ;-)

Regards
Sven
Richard Henderson March 12, 2019, 6:46 p.m. UTC | #4
On 3/12/19 11:44 AM, Sven Schnelle wrote:
>> ... except what we're already doing that.  So I don't see what
>> can be changed to help.  This doesn't seem to make a difference.
> 
> I looked into this again, and with my limited TCG knowledge it looks like the
> exit_tb is not happening because ssm is called in a branch delay slot:
> 
> This is the TB it's calling when it looses the timer interrupt:
> 
> IN: 
> 0x0000000000045758:  bv r0(rp)
> 0x000000000004575c:  ssm 1,r0
> 
> OP:
>  ld_i32 tmp0,env,$0xffffffffffffffe0
>  movi_i32 tmp1,$0x0
>  brcond_i32 tmp0,tmp1,lt,$L0
> 
>  ---- 0000000000045758 000000000004575c
>  mov_i32 tmp0,r2
>  mov_i32 iaoq_b,tmp0
> 
>  ---- 000000000004575c 00000000ffffffff
>  movi_i32 tmp1,$0x4
>  add_i32 tmp0,iaoq_b,tmp1
>  ld_i32 tmp1,env,$0x1c0
>  movi_i32 tmp2,$0x1
>  or_i32 tmp1,tmp1,tmp2
>  call swap_system_mask,$0x1,$1,tmp1,env,tmp1
> 
> Everything above is ssm, and below this is the branch instruction, which skips
> the exit_tb (i think):
> 
>  mov_i32 iaoq_f,iaoq_b
>  mov_i32 iaoq_b,tmp0
>  mov_i64 iasq_f,iasq_b
>  call lookup_tb_ptr,$0x6,$1,tmp3,env
>  goto_ptr tmp3
>  set_label $L0
>  exit_tb $0x7f373c33cb83
> 
> I might also be totally wrong, let me know if that's the case. ;-)

You are absolutely correct.  Thanks for the failing code sequence; now I know
where to look.


r~
diff mbox series

Patch

diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index d808796ee3..3440ccad28 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -366,5 +366,6 @@  void hppa_cpu_alarm_timer(void *);
 int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr);
 #endif
 void QEMU_NORETURN hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra);
+void eval_interrupt(HPPACPU *cpu);
 
 #endif /* HPPA_CPU_H */
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 8d5edd3a20..e3acaa39eb 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -25,7 +25,7 @@ 
 #include "qom/cpu.h"
 
 #ifndef CONFIG_USER_ONLY
-static void eval_interrupt(HPPACPU *cpu)
+void eval_interrupt(HPPACPU *cpu)
 {
     CPUState *cs = CPU(cpu);
     if (cpu->env.cr[CR_EIRR] & cpu->env.cr[CR_EIEM]) {
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index a55a5dfc02..f93211c84f 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -662,6 +662,7 @@  void HELPER(reset)(CPUHPPAState *env)
 
 target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
 {
+    HPPACPU *cpu = hppa_env_get_cpu(env);
     target_ulong psw = env->psw;
     /*
      * Setting the PSW Q bit to 1, if it was not already 1, is an
@@ -673,6 +674,11 @@  target_ureg HELPER(swap_system_mask)(CPUHPPAState *env, target_ureg nsm)
      * so let this go without comment.
      */
     env->psw = (psw & ~PSW_SM) | (nsm & PSW_SM);
+    if (!(psw & PSW_I) && (nsm & PSW_I)) {
+        qemu_mutex_lock_iothread();
+        eval_interrupt(cpu);
+        qemu_mutex_unlock_iothread();
+    }
     return psw & PSW_SM;
 }