diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/cpu/aarch64/aarch64-exception-default.c | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/cpukit/score/cpu/aarch64/aarch64-exception-default.c b/cpukit/score/cpu/aarch64/aarch64-exception-default.c index 2ebb3dee9f..f1591cbd5d 100644 --- a/cpukit/score/cpu/aarch64/aarch64-exception-default.c +++ b/cpukit/score/cpu/aarch64/aarch64-exception-default.c @@ -41,10 +41,87 @@ #include "config.h" #endif -#include <rtems/score/cpu.h> #include <rtems/fatal.h> +#include <rtems/score/aarch64-system-registers.h> +#include <rtems/score/cpu.h> +#include <rtems/score/percpu.h> void _AArch64_Exception_default( CPU_Exception_frame *frame ) { + uint64_t EC = AARCH64_ESR_EL1_EC_GET( frame->register_syndrome ); + + /* Emulate FPSR flags for FENV if a FPU exception occurred */ + if ( EC == 0x2c ) { + /* + * This must be done because FENV depends on FPSR values, but trapped FPU + * exceptions don't set FPSR bits. In the case where a signal is mapped, the + * signal code executes after the exception frame is restored and FENV + * functions executed in that context will need this information to be + * accurate. + */ + uint64_t ISS = AARCH64_ESR_EL1_EC_GET( frame->register_syndrome ); + + /* If the exception bits are valid, use them */ + if ( ( ISS & ( 1 << 23 ) ) != 0 ) { + /* The bits of the lower byte match the FPSR exception bits */ + frame->register_fpsr |= ( ISS & 0xff ); + } + } + rtems_fatal( RTEMS_FATAL_SOURCE_EXCEPTION, (rtems_fatal_code) frame ); } + +void _CPU_Exception_disable_thread_dispatch( void ) +{ + Per_CPU_Control *cpu_self = _Per_CPU_Get(); + + /* Increment interrupt nest and thread dispatch disable level */ + ++cpu_self->thread_dispatch_disable_level; + ++cpu_self->isr_nest_level; +} + +void _AArch64_Exception_frame_copy( + CPU_Exception_frame *new_ef, + CPU_Exception_frame *old_ef +) +{ + *new_ef = *old_ef; +} + +int _CPU_Exception_frame_get_signal( CPU_Exception_frame *ef ) +{ + uint64_t EC = AARCH64_ESR_EL1_EC_GET( ef->register_syndrome ); + + switch ( EC ) { + case 0x1: /* WFI */ + case 0x7: /* SVE/SIMD/FP */ + case 0xa: /* LD64B/ST64B* */ + case 0x18: /* MSR/MRS/system instruction */ + case 0x19: /* SVE */ + case 0x15: /* Supervisor call */ + case 0x26: /* SP Alignment */ + case 0x31: /* Breakpoint */ + case 0x33: /* Step */ + case 0x35: /* Watchpoint */ + case 0x3c: /* Break Instruction */ + return -1; + case 0x2c: /* FPU */ + return SIGFPE; + case 0x21: /* Instruction Abort */ + case 0x25: /* Data Abort */ + return SIGSEGV; + default: + return SIGILL; + } +} + +void _CPU_Exception_frame_set_resume( CPU_Exception_frame *ef, void *address ) +{ + ef->register_pc = address; +} + +#define AARCH64_INSTRUCTION_SIZE 4 +void _CPU_Exception_frame_make_resume_next_instruction( CPU_Exception_frame *ef ) +{ + ef->register_pc += AARCH64_INSTRUCTION_SIZE; +} |