diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/cpu/sparc/cpu.c | 51 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/include/rtems/score/cpu.h | 53 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h | 22 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/sparc-bad-trap.S | 231 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/sparc-exception-frame-print.c | 157 |
5 files changed, 513 insertions, 1 deletions
diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c index a7bf7dfcaf..10ad44049a 100644 --- a/cpukit/score/cpu/sparc/cpu.c +++ b/cpukit/score/cpu/sparc/cpu.c @@ -147,6 +147,57 @@ RTEMS_STATIC_ASSERT( CPU_Interrupt_frame_alignment ); +#define SPARC_ASSERT_REGISTER_WINDOW_OFFSET( member, off ) \ + RTEMS_STATIC_ASSERT( \ + offsetof( SPARC_Register_window, member ) == \ + RTEMS_XCONCAT( SPARC_REGISTER_WINDOW_OFFSET_, off ), \ + SPARC_Register_window ## member \ + ) + +SPARC_ASSERT_REGISTER_WINDOW_OFFSET( local[ 0 ], LOCAL( 0 ) ); +SPARC_ASSERT_REGISTER_WINDOW_OFFSET( local[ 1 ], LOCAL( 1 ) ); +SPARC_ASSERT_REGISTER_WINDOW_OFFSET( input[ 0 ], INPUT( 0 ) ); +SPARC_ASSERT_REGISTER_WINDOW_OFFSET( input[ 1 ], INPUT( 1 ) ); + +RTEMS_STATIC_ASSERT( + sizeof( SPARC_Register_window ) == SPARC_REGISTER_WINDOW_SIZE, + SPARC_REGISTER_WINDOW_SIZE +); + +#define SPARC_ASSERT_EXCEPTION_OFFSET( member, off ) \ + RTEMS_STATIC_ASSERT( \ + offsetof( CPU_Exception_frame, member ) == \ + RTEMS_XCONCAT( SPARC_EXCEPTION_OFFSET_, off ), \ + CPU_Exception_frame_offset_ ## member \ + ) + +SPARC_ASSERT_EXCEPTION_OFFSET( psr, PSR ); +SPARC_ASSERT_EXCEPTION_OFFSET( pc, PC ); +SPARC_ASSERT_EXCEPTION_OFFSET( npc, NPC ); +SPARC_ASSERT_EXCEPTION_OFFSET( trap, TRAP ); +SPARC_ASSERT_EXCEPTION_OFFSET( wim, WIM ); +SPARC_ASSERT_EXCEPTION_OFFSET( y, Y ); +SPARC_ASSERT_EXCEPTION_OFFSET( global[ 0 ], GLOBAL( 0 ) ); +SPARC_ASSERT_EXCEPTION_OFFSET( global[ 1 ], GLOBAL( 1 ) ); +SPARC_ASSERT_EXCEPTION_OFFSET( output[ 0 ], OUTPUT( 0 ) ); +SPARC_ASSERT_EXCEPTION_OFFSET( output[ 1 ], OUTPUT( 1 ) ); + +#if SPARC_HAS_FPU == 1 +SPARC_ASSERT_EXCEPTION_OFFSET( fsr, FSR ); +SPARC_ASSERT_EXCEPTION_OFFSET( fp[ 0 ], FP( 0 ) ); +SPARC_ASSERT_EXCEPTION_OFFSET( fp[ 1 ], FP( 1 ) ); +#endif + +RTEMS_STATIC_ASSERT( + sizeof( CPU_Exception_frame ) == SPARC_EXCEPTION_FRAME_SIZE, + SPARC_EXCEPTION_FRAME_SIZE +); + +RTEMS_STATIC_ASSERT( + sizeof( CPU_Exception_frame ) % CPU_ALIGNMENT == 0, + CPU_Exception_frame_alignment +); + /* * _CPU_Initialize * diff --git a/cpukit/score/cpu/sparc/include/rtems/score/cpu.h b/cpukit/score/cpu/sparc/include/rtems/score/cpu.h index 0daf1d9a28..f3f50d4f78 100644 --- a/cpukit/score/cpu/sparc/include/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/include/rtems/score/cpu.h @@ -1023,9 +1023,60 @@ RTEMS_NO_RETURN void _CPU_Context_restore( Context_Control *new_context ); } while ( 0 ) #endif +/** + * @brief This structure contains the local and input registers of a register + * window. + */ typedef struct { + /** @brief This member contains the local 0..7 register values. */ + uint32_t local[ 8 ]; + + /** @brief This member contains the input 0..7 register values. */ + uint32_t input[ 8 ]; +} SPARC_Register_window; + +/** + * @brief This structure contains the register set of a context which caused an + * unexpected trap. + */ +typedef struct { + /** @brief This member contains the PSR register value. */ + uint32_t psr; + + /** @brief This member contains the PC value. */ + uint32_t pc; + + /** @brief This member contains the nPC value. */ + uint32_t npc; + + /** @brief This member contains the trap number. */ uint32_t trap; - CPU_Interrupt_frame *isf; + + /** @brief This member contains the WIM register value. */ + uint32_t wim; + + /** @brief This member contains the Y register value. */ + uint32_t y; + + /** @brief This member contains the global 0..7 register values. */ + uint32_t global[ 8 ]; + + /** @brief This member contains the output 0..7 register values. */ + uint32_t output[ 8 ] ; + + /** + * @brief This member contains the additional register windows according to + * the saved WIM. + */ + SPARC_Register_window windows[ SPARC_NUMBER_OF_REGISTER_WINDOWS - 1 ]; + +#if SPARC_HAS_FPU == 1 + /** This member contain the FSR register value. */ + uint32_t fsr; + + /** @brief This member contains the floating point 0..31 register values. */ + uint64_t fp[ 16 ]; +#endif } CPU_Exception_frame; void _CPU_Exception_frame_print( const CPU_Exception_frame *frame ); diff --git a/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h index a99da74fa9..a8ed0aec23 100644 --- a/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h +++ b/cpukit/score/cpu/sparc/include/rtems/score/cpuimpl.h @@ -117,6 +117,28 @@ #endif #endif +#define SPARC_REGISTER_WINDOW_OFFSET_LOCAL( i ) ( ( i ) * 4 ) +#define SPARC_REGISTER_WINDOW_OFFSET_INPUT( i ) ( ( i ) * 4 + 32 ) +#define SPARC_REGISTER_WINDOW_SIZE 64 + +#define SPARC_EXCEPTION_OFFSET_PSR 0 +#define SPARC_EXCEPTION_OFFSET_PC 4 +#define SPARC_EXCEPTION_OFFSET_NPC 8 +#define SPARC_EXCEPTION_OFFSET_TRAP 12 +#define SPARC_EXCEPTION_OFFSET_WIM 16 +#define SPARC_EXCEPTION_OFFSET_Y 20 +#define SPARC_EXCEPTION_OFFSET_GLOBAL( i ) ( ( i ) * 4 + 24 ) +#define SPARC_EXCEPTION_OFFSET_OUTPUT( i ) ( ( i ) * 4 + 56 ) +#define SPARC_EXCEPTION_OFFSET_WINDOWS( i ) ( ( i ) * 64 + 88 ) + +#if SPARC_HAS_FPU == 1 +#define SPARC_EXCEPTION_OFFSET_FSR 536 +#define SPARC_EXCEPTION_OFFSET_FP( i ) ( ( i ) * 8 + 544 ) +#define SPARC_EXCEPTION_FRAME_SIZE 672 +#else +#define SPARC_EXCEPTION_FRAME_SIZE 536 +#endif + #ifndef ASM #ifdef __cplusplus diff --git a/cpukit/score/cpu/sparc/sparc-bad-trap.S b/cpukit/score/cpu/sparc/sparc-bad-trap.S new file mode 100644 index 0000000000..2e73a4a7da --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-bad-trap.S @@ -0,0 +1,231 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreCPUSPARC + * + * @brief This source file contains the implementation of _SPARC_Bad_trap(). + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/asm.h> +#include <rtems/score/percpu.h> + + /* + * The trap handler entry was set up by TRAP(). + */ + PUBLIC(_SPARC_Bad_trap) +SYM(_SPARC_Bad_trap): + + /* + * Do not use the existing stack since it may be invalid. Use the ISR + * stack for this processor. If the trap was caused from within + * interrupt context, then a return to the context which caused the + * trap would be unreliable. + */ + set SYM(_ISR_Stack_size), %l5 + +#if defined(RTEMS_SMP) && defined(__leon__) + rd %asr17, %l6 + srl %l6, LEON3_ASR17_PROCESSOR_INDEX_SHIFT, %l6 + add %l6, 1, %l4 + smul %l4, %l5, %l5 +#endif + set SYM(_ISR_Stack_area_begin), %l7 + add %l7, %l5, %l7 + andn %l7, CPU_STACK_ALIGNMENT - 1, %l7 + + /* + * Establish an area on the stack for a CPU_Exception_frame. + */ + sub %l7, SPARC_EXCEPTION_FRAME_SIZE, %l7 + + /* + * Start saving the context which caused the trap. + */ + mov %wim, %l4 + rd %y, %l5 + std %l0, [%l7 + SPARC_EXCEPTION_OFFSET_PSR] + SPARC_LEON3FT_B2BST_NOP + std %l2, [%l7 + SPARC_EXCEPTION_OFFSET_NPC] + SPARC_LEON3FT_B2BST_NOP + st %l4, [%l7 + SPARC_EXCEPTION_OFFSET_WIM] + st %l5, [%l7 + SPARC_EXCEPTION_OFFSET_Y] + std %g0, [%l7 + SPARC_EXCEPTION_OFFSET_GLOBAL(0)] + SPARC_LEON3FT_B2BST_NOP + std %g2, [%l7 + SPARC_EXCEPTION_OFFSET_GLOBAL(2)] + SPARC_LEON3FT_B2BST_NOP + std %g4, [%l7 + SPARC_EXCEPTION_OFFSET_GLOBAL(4)] + SPARC_LEON3FT_B2BST_NOP + std %g6, [%l7 + SPARC_EXCEPTION_OFFSET_GLOBAL(6)] + SPARC_LEON3FT_B2BST_NOP + std %i0, [%l7 + SPARC_EXCEPTION_OFFSET_OUTPUT(0)] + SPARC_LEON3FT_B2BST_NOP + std %i2, [%l7 + SPARC_EXCEPTION_OFFSET_OUTPUT(2)] + SPARC_LEON3FT_B2BST_NOP + std %i4, [%l7 + SPARC_EXCEPTION_OFFSET_OUTPUT(4)] + SPARC_LEON3FT_B2BST_NOP + std %i6, [%l7 + SPARC_EXCEPTION_OFFSET_OUTPUT(6)] + + /* + * Initialize %g6 since it may be corrupt. + */ + set SYM(_Per_CPU_Information), %g6 +#if defined(RTEMS_SMP) && defined(__leon__) + sll %l6, PER_CPU_CONTROL_SIZE_LOG2, %l4 + add %g6, %l4, %g6 +#endif + + /* + * Disable WIM traps. + */ + mov %g0, %wim + nop + nop + nop + + /* + * Save the remaining register windows. + */ + set SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g2 + add %l7, SPARC_EXCEPTION_OFFSET_WINDOWS(0), %g3 + +.Lsave_register_windows: + + restore + std %l0, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_LOCAL(0)] + SPARC_LEON3FT_B2BST_NOP + std %l2, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_LOCAL(2)] + SPARC_LEON3FT_B2BST_NOP + std %l4, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_LOCAL(4)] + SPARC_LEON3FT_B2BST_NOP + std %l6, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_LOCAL(6)] + SPARC_LEON3FT_B2BST_NOP + std %i0, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_INPUT(0)] + SPARC_LEON3FT_B2BST_NOP + std %i2, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_INPUT(2)] + SPARC_LEON3FT_B2BST_NOP + std %i4, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_INPUT(4)] + SPARC_LEON3FT_B2BST_NOP + std %i6, [%g3 + SPARC_REGISTER_WINDOW_OFFSET_INPUT(6)] + add %g3, SPARC_REGISTER_WINDOW_SIZE, %g3 + subcc %g2, 1, %g2 + bne .Lsave_register_windows + nop + + /* + * Go back to register window at trap entry. + */ + restore + + /* + * Initialize the WIM based on the PSR[CWP] to have all register + * windows available for the fatal error procedure. + */ + and %l0, SPARC_PSR_CWP_MASK, %l4 + set 1, %l5 + sll %l5, %l4, %l5 + mov %l5, %wim + +#if SPARC_HAS_FPU == 1 + /* + * Enable the FPU in the new PSR (PSR[EF] == 1). + */ + sethi %hi(SPARC_PSR_EF_MASK), %l4 + or %l0, %l4, %l0 +#endif + + /* + * Enable traps and disable interrupts. + */ + or %l0, 0xf20, %l0 + wr %l0, %psr + nop + nop + nop + +#if SPARC_HAS_FPU == 1 + st %fsr, [%l7 + SPARC_EXCEPTION_OFFSET_FSR] + std %f0, [%l7 + SPARC_EXCEPTION_OFFSET_FP(0)] + SPARC_LEON3FT_B2BST_NOP + std %f2, [%l7 + SPARC_EXCEPTION_OFFSET_FP(1)] + SPARC_LEON3FT_B2BST_NOP + std %f4, [%l7 + SPARC_EXCEPTION_OFFSET_FP(2)] + SPARC_LEON3FT_B2BST_NOP + std %f6, [%l7 + SPARC_EXCEPTION_OFFSET_FP(3)] + SPARC_LEON3FT_B2BST_NOP + std %f8, [%l7 + SPARC_EXCEPTION_OFFSET_FP(4)] + SPARC_LEON3FT_B2BST_NOP + std %f10, [%l7 + SPARC_EXCEPTION_OFFSET_FP(5)] + SPARC_LEON3FT_B2BST_NOP + std %f12, [%l7 + SPARC_EXCEPTION_OFFSET_FP(6)] + SPARC_LEON3FT_B2BST_NOP + std %f14, [%l7 + SPARC_EXCEPTION_OFFSET_FP(7)] + SPARC_LEON3FT_B2BST_NOP + std %f16, [%l7 + SPARC_EXCEPTION_OFFSET_FP(8)] + SPARC_LEON3FT_B2BST_NOP + std %f18, [%l7 + SPARC_EXCEPTION_OFFSET_FP(9)] + SPARC_LEON3FT_B2BST_NOP + std %f20, [%l7 + SPARC_EXCEPTION_OFFSET_FP(10)] + SPARC_LEON3FT_B2BST_NOP + std %f22, [%l7 + SPARC_EXCEPTION_OFFSET_FP(11)] + SPARC_LEON3FT_B2BST_NOP + std %f24, [%l7 + SPARC_EXCEPTION_OFFSET_FP(12)] + SPARC_LEON3FT_B2BST_NOP + std %f26, [%l7 + SPARC_EXCEPTION_OFFSET_FP(13)] + SPARC_LEON3FT_B2BST_NOP + std %f28, [%l7 + SPARC_EXCEPTION_OFFSET_FP(14)] + SPARC_LEON3FT_B2BST_NOP + std %f30, [%l7 + SPARC_EXCEPTION_OFFSET_FP(15)] +#endif + +#if !defined(SPARC_USE_LAZY_FP_SWITCH) + /* + * Call + * _Internal_error( INTERNAL_ERROR_ILLEGAL_USE_OF_FLOATING_POINT_UNIT ) + * if necessary. + */ + cmp %l3, 4 + bne .Lno_fp_disable_trap + nop + call SYM(_Internal_error) + set 38, %o0 +.Lno_fp_disable_trap: +#endif + + /* + * Call _Terminate( RTEMS_FATAL_SOURCE_EXCEPTION, %l0 ). + */ + sub %l7, SPARC_MINIMUM_STACK_FRAME_SIZE, %sp + set 9, %o0 + call SYM(_Terminate) + mov %l7, %o1 diff --git a/cpukit/score/cpu/sparc/sparc-exception-frame-print.c b/cpukit/score/cpu/sparc/sparc-exception-frame-print.c new file mode 100644 index 0000000000..f216c1dc63 --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-exception-frame-print.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSScoreCPUSPARC + * + * @brief This source file contains the SPARC-specific implementation of + * _CPU_Exception_frame_print(). + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/score/cpu.h> +#include <rtems/bspIo.h> +#include <inttypes.h> + +void _CPU_Exception_frame_print( const CPU_Exception_frame *frame ) +{ + size_t i; + size_t j; + const char *desc; + + switch ( SPARC_REAL_TRAP_NUMBER( frame->trap ) ) { + case 0x01: + desc = " (instruction access exception)"; + break; + case 0x02: + desc = " (illegal instruction)"; + break; + case 0x03: + desc = " (privileged instruction)"; + break; + case 0x04: + desc = " (fp disabled)"; + break; + case 0x05: + desc = " (window overflow)"; + break; + case 0x06: + desc = " (window underflow)"; + break; + case 0x07: + desc = " (memory address not aligned)"; + break; + case 0x08: + desc = " (fp exception)"; + break; + case 0x09: + desc = " (data access exception)"; + break; + case 0x0A: + desc = " (tag overflow)"; + break; + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + desc = " (external interrupt)"; + break; + case 0x24: + desc = " (cp disabled)"; + break; + case 0x28: + desc = " (cp exception)"; + break; + default: + desc = ""; + break; + } + + printk( + "\n" + "unexpected trap %" PRIu32 "%s\n" + "PSR = 0x%08" PRIx32 "\n" + "PC = 0x%08" PRIx32 "\n" + "nPC = 0x%08" PRIx32 "\n" + "WIM = 0x%08" PRIx32 "\n" + "Y = 0x%08" PRIx32 "\n", + frame->trap, + desc, + frame->psr, + frame->pc, + frame->npc, + frame->wim, + frame->y + ); + + for ( i = 0; i < RTEMS_ARRAY_SIZE( frame->global ); ++i ) { + printk( "g%zu = 0x%08" PRIx32 "\n", i, frame->global[ i ] ); + } + + for ( i = 0; i < RTEMS_ARRAY_SIZE( frame->output ); ++i ) { + printk( "o%zu[CWP - 0] = 0x%08" PRIx32 "\n", i, frame->output[ i ] ); + } + + for ( i = 0; i < RTEMS_ARRAY_SIZE( frame->windows ); ++i ) { + const SPARC_Register_window *win; + + win = &frame->windows[ i ]; + + for ( j = 0; j < RTEMS_ARRAY_SIZE( win->local ); ++j ) { + printk( "l%zu[CWP - %zu] = 0x%08" PRIx32 "\n", j, i, win->local[ j ] ); + } + + for ( j = 0; j < RTEMS_ARRAY_SIZE( win->input ); ++j ) { + printk( "i%zu[CWP - %zu] = 0x%08" PRIx32 "\n", j, i, win->input[ j ] ); + } + } + +#if SPARC_HAS_FPU == 1 + printk( "FSR = 0x%08" PRIx32 "\n", frame->fsr ); + + for ( i = 0; i < RTEMS_ARRAY_SIZE( frame->fp ); ++i ) { + j = i * 2; + printk( "fp%zu:fp%zu = 0x%016" PRIx64 "\n", j, j + 1, frame->fp[ i ] ); + } +#endif +} |