imx233: fix IRQ handler w.r.t unwinder

The IRQ handler saves registers on the IRQ stack, saves the old PC to imx233
HW_DIGCTL_SCRATCH0 register and switcht to SVC for the actual handling. The
old code had a problem in that if the unwinder is called during the IRQ (for
example by the watchdog), then __get_sp() will use SPSR_svc to discover the
previous mode, switch to it and recover SP. But SPSR_svc is invalid, it should
be SPSR_irq but we switch from IRQ to SVC mode. The new code copies SPSR_irq
to SPSR_svc in IRQ to fix this problem. It also saves/restore SCRATCH0 in
case I one day renable nested interrupts or use SCRATCH0 for other purposes.
I also changed the old watchdog code to call UIE directly instead of trying
to make the code crash with a SWI.

Change-Id: Id87462d410764b019bd2aa9adc71cb917ade32e3
This commit is contained in:
Amaury Pouly 2016-09-21 00:09:23 +01:00
parent 7e0820fe21
commit a523c3fcfe
2 changed files with 18 additions and 10 deletions

View file

@ -52,15 +52,16 @@
#define WATCHDOG_HW_DELAY (10 * HZ)
#define WATCHDOG_SW_DELAY (5 * HZ)
void UIE(unsigned int pc, unsigned int num);
static void woof_woof(void)
{
/* stop hadrware watchdog, we catched the error */
/* stop hardware watchdog, we catched the error */
imx233_rtc_enable_watchdog(false);
/* recover current PC and trigger abort, so in the hope to get a useful
* backtrace */
uint32_t pc = HW_DIGCTL_SCRATCH0;
/* write a "SWI #0xdead" instruction at the faulty instruction so that it
* will trigger a proper backtrace */
*(uint32_t *)pc = 0xef00dead;
commit_discard_idcache();
UIE(pc, 4);
}
static void good_dog(void)