Commit 58eb132d authored by Andy Ross's avatar Andy Ross Committed by Carles Cufi
Browse files

arch/xtensa: Fix return context for nested interupts

The xtensa interrupt return path was forgetting to check the nested
interrupt state and calling into the scheduler to select the context
to which to return, which of course is completely wrong.  We MUST
return to the ISR we interrupted.

In fact in practice this was only visible in the case of a nested
interrupt that causes a context switch, otherwise the "interrupted"
argument just gets returned and things work.  In particular, it can
happen when the nested context is a fatal exception that aborts the
current thread, which is how this was discovered.  The timing required
to see this on live interrupts on real applications is likely to have
been extremely difficult to detect.

Fixes #45779

Signed-off-by: default avatarAndy Ross <andrew.j.ross@intel.com>
parent 5d80dbd3
Loading
Loading
Loading
Loading
+9 −3
Changes for arch/xtensa/core/xtensa-asm2.c: 9 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -151,6 +151,12 @@ static ALWAYS_INLINE void usage_stop(void)
#endif
}

static inline void *return_to(void *interrupted)
{
	return _current_cpu->nested <= 1 ?
		z_get_next_switch_handle(interrupted) : interrupted;
}

/* The wrapper code lives here instead of in the python script that
 * generates _xtensa_handle_one_int*().  Seems cleaner, still kind of
 * ugly.
@@ -170,7 +176,7 @@ __unused void *xtensa_int##l##_c(void *interrupted_stack) \
		irqs ^= m;					\
		__asm__ volatile("wsr.intclear %0" : : "r"(m)); \
	}							\
	return z_get_next_switch_handle(interrupted_stack);		\
	return return_to(interrupted_stack);		\
}

#if XCHAL_NMILEVEL >= 2
@@ -254,7 +260,7 @@ void *xtensa_excint1_c(int *interrupted_stack)
				     (void *)interrupted_stack);
	}

	return z_get_next_switch_handle(interrupted_stack);
	return return_to(interrupted_stack);
}

#if defined(CONFIG_GDBSTUB)
@@ -264,7 +270,7 @@ void *xtensa_debugint_c(int *interrupted_stack)

	z_gdb_isr((void *)interrupted_stack);

	return z_get_next_switch_handle(interrupted_stack);
	return return_to(interrupted_stack);
}
#endif