From ec124385f20d0fbcd5327d6357a07c059a4fa3a1 Mon Sep 17 00:00:00 2001 From: Nick Andrews Date: Tue, 15 Sep 2026 23:15:23 +0100 Subject: [PATCH] amiga kernel: restore INTENA's master bit when leaving a Paula interrupt A program may hold a Disable() and still turn the hardware interrupts back on itself (Speedway Manager cracktro: Disable(), INTENA=$C020, AddIntServer(VERTB), spin on the server's counter). Our VERTB servers take Disable()/Enable() sections (timer.device's vblank handler, the graphics VBlank server), and with the interrupted task's IDNestCnt at 0 their Enable() never writes $C000 again, so the first vertical blank silently cleared INTEN and the program froze (issue #742). Kickstart's Enable() behaves the same, but its VERTB servers never do this. Interrupt handling must be transparent to the interrupted code: the master bit was set or the interrupt could not have happened, so set it again on the way out of the level 1-6 handlers. --- arch/m68k-amiga/kernel/amiga_irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/m68k-amiga/kernel/amiga_irq.c b/arch/m68k-amiga/kernel/amiga_irq.c index b9c4bfe22b2..801111acb93 100644 --- a/arch/m68k-amiga/kernel/amiga_irq.c +++ b/arch/m68k-amiga/kernel/amiga_irq.c @@ -142,6 +142,14 @@ static inline UWORD custom_r(ULONG reg) #define PAULA_IRQ_EXIT() \ /* mask = custom_r(INTENAR) & custom_r(INTREQR) & (irq_mask); */ \ } while (0); \ + /* The master enable was set or we would not be here. A server that \ + * takes a Disable()/Enable() section finds the interrupted task's \ + * IDNestCnt >= 0 when that task has an outstanding Disable() but \ + * re-enabled the hardware itself (demos do: Disable(), set INTENA, \ + * AddIntServer(), spin on a VBL counter), and its Enable() then leaves \ + * INTEN clear for good. Interrupt handling must be transparent to the \ + * interrupted code, so put the bit back */ \ + custom_w(INTENA, INTF_SETCLR | INTF_INTEN); \ /* Call Exec/ExitIntr */ \ return TRUE;