From 1c59cad4aa40238c1aa3085adf3d079114c077b8 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Fri, 24 Apr 2015 16:05:50 +0200 Subject: sparc: Add support for sptests/spcontext01 Implement _CPU_Context_validate() and _CPU_Context_volatile_clobber(). Update #2270. --- cpukit/score/cpu/sparc/Makefile.am | 2 + cpukit/score/cpu/sparc/rtems/score/cpu.h | 12 +- cpukit/score/cpu/sparc/sparc-context-validate.S | 368 +++++++++++++++++++++ .../cpu/sparc/sparc-context-volatile-clobber.S | 156 +++++++++ 4 files changed, 528 insertions(+), 10 deletions(-) create mode 100644 cpukit/score/cpu/sparc/sparc-context-validate.S create mode 100644 cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am index c6ea1c3da9..8cf4f4a65a 100644 --- a/cpukit/score/cpu/sparc/Makefile.am +++ b/cpukit/score/cpu/sparc/Makefile.am @@ -11,6 +11,8 @@ include_rtems_score_HEADERS += rtems/score/cpuatomic.h noinst_LIBRARIES = libscorecpu.a libscorecpu_a_SOURCES = cpu.c cpu_asm.S +libscorecpu_a_SOURCES += sparc-context-volatile-clobber.S +libscorecpu_a_SOURCES += sparc-context-validate.S libscorecpu_a_SOURCES += sparc-counter.c libscorecpu_a_SOURCES += sparcv8-atomic.c libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h index 235b3652ac..64e87509b4 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h @@ -1216,17 +1216,9 @@ void _CPU_Context_restore_fp( Context_Control_fp **fp_context_ptr ); -static inline void _CPU_Context_volatile_clobber( uintptr_t pattern ) -{ - /* TODO */ -} +void _CPU_Context_volatile_clobber( uintptr_t pattern ); -static inline void _CPU_Context_validate( uintptr_t pattern ) -{ - while (1) { - /* TODO */ - } -} +void _CPU_Context_validate( uintptr_t pattern ); typedef struct { uint32_t trap; diff --git a/cpukit/score/cpu/sparc/sparc-context-validate.S b/cpukit/score/cpu/sparc/sparc-context-validate.S new file mode 100644 index 0000000000..0ee7177d73 --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-context-validate.S @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#define FRAME_OFFSET_BUFFER (CPU_MINIMUM_STACK_FRAME_SIZE) +#define FRAME_OFFSET_L0 (FRAME_OFFSET_BUFFER + 0x04) +#define FRAME_OFFSET_L1 (FRAME_OFFSET_L0 + 0x04) +#define FRAME_OFFSET_L2 (FRAME_OFFSET_L1 + 0x04) +#define FRAME_OFFSET_L3 (FRAME_OFFSET_L2 + 0x04) +#define FRAME_OFFSET_L4 (FRAME_OFFSET_L3 + 0x04) +#define FRAME_OFFSET_L5 (FRAME_OFFSET_L4 + 0x04) +#define FRAME_OFFSET_L6 (FRAME_OFFSET_L5 + 0x04) +#define FRAME_OFFSET_L7 (FRAME_OFFSET_L6 + 0x04) +#define FRAME_OFFSET_I0 (FRAME_OFFSET_L7 + 0x04) +#define FRAME_OFFSET_I1 (FRAME_OFFSET_I0 + 0x04) +#define FRAME_OFFSET_I2 (FRAME_OFFSET_I1 + 0x04) +#define FRAME_OFFSET_I3 (FRAME_OFFSET_I2 + 0x04) +#define FRAME_OFFSET_I4 (FRAME_OFFSET_I3 + 0x04) +#define FRAME_OFFSET_I5 (FRAME_OFFSET_I4 + 0x04) +#define FRAME_OFFSET_I6 (FRAME_OFFSET_I5 + 0x04) +#define FRAME_OFFSET_I7 (FRAME_OFFSET_I6 + 0x04) +#define FRAME_OFFSET_SP (FRAME_OFFSET_I7 + 0x04) +#define FRAME_END (FRAME_OFFSET_SP + 0x04) +#define FRAME_SIZE \ + ((FRAME_END + CPU_STACK_ALIGNMENT - 1) & ~(CPU_STACK_ALIGNMENT - 1)) + +.macro check_register reg + sub %g1, 1, %g1 + cmp %g1, \reg + bne restore_registers + nop +.endm + +.macro check_float_register reg + sub %g1, 1, %g1 + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + cmp %g1, %o1 + bne restore_registers + nop +.endm + +.macro check_fsr_register reg + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + sub %g1, 1, %g1 + clr %g3 + sethi %hi(0xCF800000), %g3 + or %g3, %lo(0x0FFF), %g3 + and %g1, %g3, %g3 + and %o1, %g3, %o1 + cmp %o1, %g3 + bne restore_registers + nop +.endm + +.macro write_register reg + add %g1, 1, %g1 + mov %g1, \reg +.endm + +.macro write_float_register reg + add %g1, 1, %g1 + st %g1, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], \reg +.endm + +.macro write_fsr_register reg + st \reg, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], %o1 + add %g1, 1, %g1 + clr %g3 + + /* + * FSR is masked with undefined, reserved or system-specific values + * (e.g. FPU architecture version, FP queue). + */ + sethi %hi(0xCF800000), %g3 + or %g3, %lo(0x0FFF), %g3 + and %g1, %g3, %g3 + or %o1, %g3, %g3 + st %g3, [%sp + FRAME_OFFSET_BUFFER] + ld [%sp + FRAME_OFFSET_BUFFER], \reg +.endm + + .align 4 + PUBLIC(_CPU_Context_validate) +SYM(_CPU_Context_validate): + + /* + * g2 checks if the Floating Point Unit in the Processor Status + * Register (PSR) is set. + */ + mov %psr, %g2 + sethi %hi(SPARC_PSR_EF_MASK), %g3 + and %g2, %g3, %g2 + + /* g1 is used to save the original pattern */ + mov %o0, %g1 + + /* g4 establishes window counter */ + clr %g4 + + add %sp, -FRAME_SIZE, %sp + + st %l0, [%sp + FRAME_OFFSET_L0] + st %l1, [%sp + FRAME_OFFSET_L1] + st %l2, [%sp + FRAME_OFFSET_L2] + st %l3, [%sp + FRAME_OFFSET_L3] + st %l4, [%sp + FRAME_OFFSET_L4] + st %l5, [%sp + FRAME_OFFSET_L5] + st %l6, [%sp + FRAME_OFFSET_L6] + st %l7, [%sp + FRAME_OFFSET_L7] + st %i0, [%sp + FRAME_OFFSET_I0] + st %i1, [%sp + FRAME_OFFSET_I1] + st %i2, [%sp + FRAME_OFFSET_I2] + st %i3, [%sp + FRAME_OFFSET_I3] + st %i4, [%sp + FRAME_OFFSET_I4] + st %i5, [%sp + FRAME_OFFSET_I5] + st %i6, [%sp + FRAME_OFFSET_I6] + st %i7, [%sp + FRAME_OFFSET_I7] + st %sp, [%sp + FRAME_OFFSET_SP] + + cmp %g4, 0 + bne write_locals_and_outputs + nop + be check_for_fp + nop + +new_check_cycle: + clr %g4 + sub %g1, 1, %g1 + + /* Write pattern values into registers */ + +check_for_fp: + cmp %g2, 0 + be write_y + nop + + write_fsr_register %fsr + write_float_register %f0 + write_float_register %f1 + write_float_register %f2 + write_float_register %f3 + write_float_register %f4 + write_float_register %f5 + write_float_register %f6 + write_float_register %f7 + write_float_register %f8 + write_float_register %f9 + write_float_register %f10 + write_float_register %f11 + write_float_register %f12 + write_float_register %f13 + write_float_register %f14 + write_float_register %f15 + write_float_register %f16 + write_float_register %f17 + write_float_register %f18 + write_float_register %f19 + write_float_register %f20 + write_float_register %f21 + write_float_register %f22 + write_float_register %f23 + write_float_register %f24 + write_float_register %f25 + write_float_register %f26 + write_float_register %f27 + write_float_register %f28 + write_float_register %f29 + write_float_register %f30 + write_float_register %f31 + +write_y: + write_register %y + + write_register %i0 + write_register %i1 + write_register %i2 + write_register %i3 + write_register %i4 + write_register %i5 + /* Don't write register $i6 => frame pointer */ + /* Don't write register $i7 => return address */ + b write_locals_and_outputs + nop + +switch_to_next_window: + save %sp, -FRAME_SIZE, %sp + +write_locals_and_outputs: + /* l0 is used as a scratch register */ + write_register %l1 + write_register %l2 + write_register %l3 + write_register %l4 + write_register %l5 + write_register %l6 + write_register %l7 + write_register %o1 + write_register %o2 + write_register %o3 + write_register %o4 + write_register %o5 + /* Don't write register $o6 => stack pointer */ + /* Don't write register $o7 => return address */ + + add %g4, 1, %g4 + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + bne switch_to_next_window + nop + + /* Dummy increment to set up reverse mechanism for checking process */ + add %g1, 1, %g1 + clr %g4 + + /* Checking begins here */ +window_checking: + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + be y_checking + nop + +further_checking: + cmp %g4, 0 + bne goto_local_registers + nop + + /* Check normal registers */ + check_register %o5 + check_register %o4 + check_register %o3 + check_register %o2 + check_register %o1 + +goto_local_registers: + check_register %l7 + check_register %l6 + check_register %l5 + check_register %l4 + check_register %l3 + check_register %l2 + check_register %l1 + + check_register %i5 + check_register %i4 + check_register %i3 + check_register %i2 + check_register %i1 + /* + For the last window i0 also needs to be checked as this variable + is not overwritten by the outputs of another window. + */ + add %g4, 1, %g4 + cmp %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS + bne dont_check_i0 + nop + check_register %i0 + b y_checking + nop + +dont_check_i0: + restore + + ba window_checking + nop + + /* Check Y register */ +y_checking: + mov %y, %o1 + check_register %o1 + cmp %g2, 0 + be new_check_cycle + nop + + /* Check floating point registers */ + check_float_register %f31 + check_float_register %f30 + check_float_register %f29 + check_float_register %f28 + check_float_register %f27 + check_float_register %f26 + check_float_register %f25 + check_float_register %f24 + check_float_register %f23 + check_float_register %f22 + check_float_register %f21 + check_float_register %f20 + check_float_register %f19 + check_float_register %f18 + check_float_register %f17 + check_float_register %f16 + check_float_register %f15 + check_float_register %f14 + check_float_register %f13 + check_float_register %f12 + check_float_register %f11 + check_float_register %f10 + check_float_register %f9 + check_float_register %f8 + check_float_register %f7 + check_float_register %f6 + check_float_register %f5 + check_float_register %f4 + check_float_register %f3 + check_float_register %f2 + check_float_register %f1 + check_float_register %f0 + check_fsr_register %fsr + + be new_check_cycle + nop + + /****** RESTORE STARTS HERE *******/ + + /* Restore non-volatile registers */ + +restore_registers: + and %g4, (SPARC_NUMBER_OF_REGISTER_WINDOWS - 1), %g4 + cmp %g4, 0 + be real_restore + nop + restore + sub %g4, 1, %g4 + bne restore_registers + nop + +real_restore: + ld [%sp + FRAME_OFFSET_L0], %l0 + ld [%sp + FRAME_OFFSET_L1], %l1 + ld [%sp + FRAME_OFFSET_L2], %l2 + ld [%sp + FRAME_OFFSET_L3], %l3 + ld [%sp + FRAME_OFFSET_L4], %l4 + ld [%sp + FRAME_OFFSET_L5], %l5 + ld [%sp + FRAME_OFFSET_L6], %l6 + ld [%sp + FRAME_OFFSET_L7], %l7 + ld [%sp + FRAME_OFFSET_I0], %i0 + ld [%sp + FRAME_OFFSET_I1], %i1 + ld [%sp + FRAME_OFFSET_I2], %i2 + ld [%sp + FRAME_OFFSET_I3], %i3 + ld [%sp + FRAME_OFFSET_I4], %i4 + ld [%sp + FRAME_OFFSET_I5], %i5 + ld [%sp + FRAME_OFFSET_I6], %i6 + ld [%sp + FRAME_OFFSET_I7], %i7 + + sub %sp, -FRAME_SIZE, %sp + +return_value: + /* Load callback address and jump back */ + jmp %o7 + 8 + add %sp, FRAME_SIZE, %sp diff --git a/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S b/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S new file mode 100644 index 0000000000..6e364cd3f6 --- /dev/null +++ b/cpukit/score/cpu/sparc/sparc-context-volatile-clobber.S @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#define SCRATCH_0 (CPU_MINIMUM_STACK_FRAME_SIZE) +#define SCRATCH_1 (SCRATCH_0 + 0x04) +#define FRAME_END (SCRATCH_1 + 0x04) +#define FRAME_SIZE \ + ((FRAME_END + CPU_STACK_ALIGNMENT - 1) & ~(CPU_STACK_ALIGNMENT - 1)) + +.macro clobber_register reg + sub %g2, 1, %g2 + mov %g2, \reg +.endm + +.macro clobber_fp_register reg + sub %g2, 1, %g2 + st %g2, [%sp + SCRATCH_0] + ld [%sp + SCRATCH_0], \reg +.endm + + .section ".bss" + .align 4 + + /* + * Use a global variable to vary the clobbered windows in each + * invocation to test the window overflow and underflow conditions. + */ +window_clobber_count: + .skip 4 + + .section ".text" + .align 4 + + PUBLIC(_CPU_Context_volatile_clobber) +SYM(_CPU_Context_volatile_clobber): + + /* Increment number of flushed windows by one */ + sethi %hi(window_clobber_count), %o1 + ld [%o1 + %lo(window_clobber_count)], %o2 + add %o2, 1, %o2 + st %o2, [%o1 + %lo(window_clobber_count)] + + /* Clear window counter number */ + clr %g1 + + /* Save pattern to global register */ + mov %o0, %g2 + +window_clobber: + + /* Switch window */ + + save %sp, -FRAME_SIZE, %sp + + /* Check how many windows shall be flushed */ + sethi %hi(window_clobber_count), %o1 + ld [%o1 + %lo(window_clobber_count)], %o2 + st %o2, [%o1 + %lo(window_clobber_count)] + and %o2, (SPARC_NUMBER_OF_REGISTER_WINDOWS - 1), %o1 + cmp %o1, 0 + bne no_manual_update + nop + add %o1, SPARC_NUMBER_OF_REGISTER_WINDOWS, %o1 + +no_manual_update: + /* Register to determine whether FPU is switched on */ + mov %psr, %o2 + sethi %hi(SPARC_PSR_EF_MASK), %o3 + and %o3, %o2, %o2 + + clobber_register %o3 + clobber_register %o4 + clobber_register %o5 + /* Don't overwrite return address $o7 */ + clobber_register %g3 + clobber_register %g4 + clobber_register %y + + cmp %o2, 0 + be window_update_check + nop + + clobber_fp_register %f0 + clobber_fp_register %f1 + clobber_fp_register %f2 + clobber_fp_register %f3 + clobber_fp_register %f4 + clobber_fp_register %f5 + clobber_fp_register %f6 + clobber_fp_register %f7 + clobber_fp_register %f8 + clobber_fp_register %f9 + clobber_fp_register %f10 + clobber_fp_register %f11 + clobber_fp_register %f12 + clobber_fp_register %f13 + clobber_fp_register %f14 + clobber_fp_register %f15 + clobber_fp_register %f16 + clobber_fp_register %f17 + clobber_fp_register %f18 + clobber_fp_register %f19 + clobber_fp_register %f20 + clobber_fp_register %f21 + clobber_fp_register %f22 + clobber_fp_register %f23 + clobber_fp_register %f24 + clobber_fp_register %f25 + clobber_fp_register %f26 + clobber_fp_register %f27 + clobber_fp_register %f28 + clobber_fp_register %f29 + clobber_fp_register %f30 + clobber_fp_register %f31 + +window_update_check: + + /* Counter to how many windows were switched */ + add %g1, 1, %g1 + cmp %g1, %o1 + bl window_clobber + nop + +restore_check: + + cmp %g1, 0 + be clobber_return + nop + + restore + sub %g1, 1, %g1 + ba restore_check + nop + +clobber_return: + + jmp %o7 + 8 + add %sp, FRAME_SIZE, %sp -- cgit v1.2.3