| I've tracked down what I think is a problem causing qemu-system-ppc |
| to hang whilst booting images. |
| |
| I believe the decrementer timer stops receiving interrupts so |
| tasks in our images hang indefinitely as the timer stopped. |
| |
| It can be summed up with this line of debug: |
| |
| ppc_set_irq: 0x55b4e0d562f0 n_IRQ 8 level 1 => pending 00000100req 00000004 |
| |
| It should normally read: |
| |
| ppc_set_irq: 0x55b4e0d562f0 n_IRQ 8 level 1 => pending 00000100req 00000002 |
| |
| The question is why CPU_INTERRUPT_EXITTB ends up being set when the |
| lines above this log message clearly sets CPU_INTERRUPT_HARD (via |
| cpu_interrupt() ). |
| |
| I note in cpu.h: |
| |
| /* updates protected by BQL */ |
| uint32_t interrupt_request; |
| |
| (for struct CPUState) |
| |
| The ppc code does "cs->interrupt_request |= CPU_INTERRUPT_EXITTB" in 5 |
| places, 3 in excp_helper.c and 2 in helper_regs.h. In all cases, |
| g_assert(qemu_mutex_iothread_locked()); fails. If I do something like: |
| |
| if (!qemu_mutex_iothread_locked()) { |
| qemu_mutex_lock_iothread(); |
| cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| qemu_mutex_unlock_iothread(); |
| } else { |
| cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| } |
| |
| in these call sites then I can no longer lock qemu up with my test |
| case. |
| |
| I suspect the _HARD setting gets overwritten which stops the |
| decrementer interrupts being delivered. |
| |
| Upstream-Status: Submitted [Issue discussed on qemu mailing list 2017/11/20] |
| RP 2017/11/20 |
| |
| Index: qemu-2.10.1/target/ppc/excp_helper.c |
| =================================================================== |
| --- qemu-2.10.1.orig/target/ppc/excp_helper.c |
| +++ qemu-2.10.1/target/ppc/excp_helper.c |
| @@ -207,7 +207,9 @@ static inline void powerpc_excp(PowerPCC |
| "Entering checkstop state\n"); |
| } |
| cs->halted = 1; |
| - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
| + qemu_mutex_lock_iothread(); |
| + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| + qemu_mutex_unlock_iothread(); |
| } |
| if (env->msr_mask & MSR_HVB) { |
| /* ISA specifies HV, but can be delivered to guest with HV clear |
| @@ -940,7 +942,9 @@ void helper_store_msr(CPUPPCState *env, |
| |
| if (excp != 0) { |
| CPUState *cs = CPU(ppc_env_get_cpu(env)); |
| - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
| + qemu_mutex_lock_iothread(); |
| + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| + qemu_mutex_unlock_iothread(); |
| raise_exception(env, excp); |
| } |
| } |
| @@ -995,7 +999,9 @@ static inline void do_rfi(CPUPPCState *e |
| /* No need to raise an exception here, |
| * as rfi is always the last insn of a TB |
| */ |
| - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
| + qemu_mutex_lock_iothread(); |
| + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| + qemu_mutex_unlock_iothread(); |
| |
| /* Reset the reservation */ |
| env->reserve_addr = -1; |
| Index: qemu-2.10.1/target/ppc/helper_regs.h |
| =================================================================== |
| --- qemu-2.10.1.orig/target/ppc/helper_regs.h |
| +++ qemu-2.10.1/target/ppc/helper_regs.h |
| @@ -114,11 +114,15 @@ static inline int hreg_store_msr(CPUPPCS |
| } |
| if (((value >> MSR_IR) & 1) != msr_ir || |
| ((value >> MSR_DR) & 1) != msr_dr) { |
| - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
| + qemu_mutex_lock_iothread(); |
| + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| + qemu_mutex_unlock_iothread(); |
| } |
| if ((env->mmu_model & POWERPC_MMU_BOOKE) && |
| ((value >> MSR_GS) & 1) != msr_gs) { |
| - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
| + qemu_mutex_lock_iothread(); |
| + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| + qemu_mutex_unlock_iothread(); |
| } |
| if (unlikely((env->flags & POWERPC_FLAG_TGPR) && |
| ((value ^ env->msr) & (1 << MSR_TGPR)))) { |