diff options
Diffstat (limited to 'cpukit/score/cpu/sparc/sparc-context-validate.S')
-rw-r--r-- | cpukit/score/cpu/sparc/sparc-context-validate.S | 368 |
1 files changed, 368 insertions, 0 deletions
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 + * <rtems@embedded-brains.de> + * + * 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 <rtems/asm.h> +#include <rtems/score/cpu.h> + +#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 |