bsps/mips: Report an exception as one

An exception which no handler consumed ended in
rtems_fatal_error_occurred(1), which is INTERNAL_ERROR_RTEMS_API, where
every other port reports RTEMS_FATAL_SOURCE_EXCEPTION with the exception
frame as the code.  A fatal error extension cannot recognise the former,
so a test which expects an exception and returns from its extension with
longjmp() could not resume.  That pattern is how tc-compiler-builtins.c
checks the break which the compiler emits for a division by zero, and it
stopped ts-unit-no-clock-0.

The exception vectors are dispatched like interrupt vectors and the GDB
stub installs handlers on several of them, so the dispatch stays and the
frame of the exception being vectored is published for the default
handler to recognise.  Report a vector without a frame as a spurious
interrupt, which is what the shared default handler does.

Do not print here.  The fatal error extension prints the frame when the
system really terminates, so a recovered exception stays silent instead
of writing two lines into the test output on every recovery.  The cause
table moves next to _CPU_Exception_frame_print(), which gains the cause
of the exception it prints.

Update #5691.

Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
This commit is contained in:
Sebastian Huber
2026-08-20 18:07:36 -05:00
committed by Joel Sherrill
parent b28d2837a5
commit 7ec23f42d6
3 changed files with 71 additions and 50 deletions
+5
View File
@@ -39,6 +39,11 @@
extern void mips_install_isr_entries( void );
extern void mips_vector_isr_handlers( CPU_Interrupt_frame *frame );
/*
* The frame of the exception being vectored, or NULL outside such a vector.
*/
extern CPU_Exception_frame *mips_exception_frame;
#if __mips == 1
extern void exc_utlb_code(void);
extern void exc_dbg_code(void);
+16 -50
View File
@@ -36,48 +36,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/irq-generic.h>
#include <libcpu/isr_entries.h>
#include <rtems/bspIo.h>
static const char *const cause_strings[32] = {
/* 0 */ "Int",
/* 1 */ "TLB Mods",
/* 2 */ "TLB Load",
/* 3 */ "TLB Store",
/* 4 */ "Address Load",
/* 5 */ "Address Store",
/* 6 */ "Instruction Bus Error",
/* 7 */ "Data Bus Error",
/* 8 */ "Syscall",
/* 9 */ "Breakpoint",
/* 10 */ "Reserved Instruction",
/* 11 */ "Coprocessor Unuseable",
/* 12 */ "Overflow",
/* 13 */ "Trap",
/* 14 */ "Instruction Virtual Coherency Error",
/* 15 */ "FP Exception",
/* 16 */ "Reserved 16",
/* 17 */ "Reserved 17",
/* 18 */ "Reserved 18",
/* 19 */ "Reserved 19",
/* 20 */ "Reserved 20",
/* 21 */ "Reserved 21",
/* 22 */ "Reserved 22",
/* 23 */ "Watch",
/* 24 */ "Reserved 24",
/* 25 */ "Reserved 25",
/* 26 */ "Reserved 26",
/* 27 */ "Reserved 27",
/* 28 */ "Reserved 28",
/* 29 */ "Reserved 29",
/* 30 */ "Reserved 30",
/* 31 */ "Data Virtual Coherency Error"
};
#include <rtems/fatal.h>
#include <rtems/score/interr.h>
static inline bool bsp_irq_is_valid(rtems_vector_number vector)
{
@@ -185,17 +149,19 @@ void bsp_interrupt_facility_initialize(void)
void bsp_interrupt_handler_default(rtems_vector_number vector)
{
uint32_t sr;
uint32_t cause;
/*
* An exception which no handler consumed is reported with the source and
* the argument every other port uses, so that a fatal error extension can
* recognise it and, where the exception is expected, resume with a
* longjmp(). Do not report it here: the extension prints the frame if the
* system really terminates.
*/
if ( mips_exception_frame != NULL ) {
rtems_fatal(
RTEMS_FATAL_SOURCE_EXCEPTION,
(rtems_fatal_code) mips_exception_frame
);
}
mips_get_sr( sr );
mips_get_cause( cause );
printk( "Unhandled exception %" PRId32 "\n", vector );
printk( "sr: 0x%08" PRIu32 " cause: 0x%08" PRIu32 " --> %s\n", sr, cause,
cause_strings[(cause >> 2) &0x1f] );
#if 0
mips_dump_exception_frame( frame );
#endif
rtems_fatal_error_occurred(1);
_Terminate( RTEMS_FATAL_SOURCE_SPURIOUS_INTERRUPT, vector );
}
+50
View File
@@ -50,6 +50,41 @@ struct regdef
char *name;
};
static const char *const cause_strings[32] = {
/* 0 */ "Int",
/* 1 */ "TLB Mods",
/* 2 */ "TLB Load",
/* 3 */ "TLB Store",
/* 4 */ "Address Load",
/* 5 */ "Address Store",
/* 6 */ "Instruction Bus Error",
/* 7 */ "Data Bus Error",
/* 8 */ "Syscall",
/* 9 */ "Breakpoint",
/* 10 */ "Reserved Instruction",
/* 11 */ "Coprocessor Unuseable",
/* 12 */ "Overflow",
/* 13 */ "Trap",
/* 14 */ "Instruction Virtual Coherency Error",
/* 15 */ "FP Exception",
/* 16 */ "Reserved 16",
/* 17 */ "Reserved 17",
/* 18 */ "Reserved 18",
/* 19 */ "Reserved 19",
/* 20 */ "Reserved 20",
/* 21 */ "Reserved 21",
/* 22 */ "Reserved 22",
/* 23 */ "Watch",
/* 24 */ "Reserved 24",
/* 25 */ "Reserved 25",
/* 26 */ "Reserved 26",
/* 27 */ "Reserved 27",
/* 28 */ "Reserved 28",
/* 29 */ "Reserved 29",
/* 30 */ "Reserved 30",
/* 31 */ "Data Virtual Coherency Error"
};
static const struct regdef dumpregs[]= {
{ R_RA, "R_RA" }, { R_V0, "R_V0" }, { R_V1, "R_V1" },
{ R_A0, "R_A0" }, { R_A1, "R_A1" }, { R_A2, "R_A2" },
@@ -67,6 +102,12 @@ void _CPU_Exception_frame_print( const CPU_Exception_frame *frame )
int i;
size_t j;
printk(
" CAUSE %08" PRIx32 " --> %s\n",
(uint32_t) frame->cause,
cause_strings[ ( (uint32_t) frame->cause >> 2 ) & 0x1f ]
);
frame_u32 = (uint32_t *)frame;
for(i=0; dumpregs[i].offset > -1; i++)
{
@@ -89,6 +130,13 @@ void _CPU_Exception_frame_print( const CPU_Exception_frame *frame )
* all be close to the same set.
*/
/*
* The frame of the exception being vectored, or NULL outside such a vector.
* bsp_interrupt_handler_default() uses it to tell an exception which no
* handler consumed from a spurious interrupt.
*/
CPU_Exception_frame *mips_exception_frame;
void mips_vector_exceptions( CPU_Interrupt_frame *frame )
{
(void) frame;
@@ -99,5 +147,7 @@ void mips_vector_exceptions( CPU_Interrupt_frame *frame )
mips_get_cause( cause );
exc = (cause >> 2) & 0x1f;
mips_exception_frame = frame;
bsp_interrupt_handler_dispatch( exc );
mips_exception_frame = NULL;
}