[PATCH] sparc: Add assembly workaround for LEON3FT B2BST errata

Daniel Cederman cederman at gaisler.com
Thu Jul 13 07:26:50 UTC 2017


This patch adds NOP instructions to prevent instruction sequences
that are sensitive to the LEON3FT B2BST errata. See GRLIB-TN-0009:
"LEON3FT Stale Cache Entry After Store with Data Tag Parity Error"
for more information.

The sequences are only modified if __FIX_LEON3FT_B2BST is defined.

The patch works in conjunction with the -mfix-ut700, -mfix-gr712rc,
and -mfix-ut699 GCC flags that prevents the sensitive sequences from
being generated.

See also https://devel.rtems.org/ticket/3057
---
 c/src/lib/libbsp/sparc/shared/irq_asm.S         | 47 +++++++++++++++++++++++++
 c/src/lib/libcpu/sparc/access/access.S          | 28 +++++++++++++++
 c/src/lib/libcpu/sparc/reg_win/window.S         | 12 +++++++
 cpukit/score/cpu/sparc/cpu_asm.S                | 22 ++++++++++++
 cpukit/score/cpu/sparc/rtems/score/sparc.h      | 10 ++++++
 cpukit/score/cpu/sparc/sparc-context-validate.S |  1 +
 6 files changed, 120 insertions(+)

diff --git a/c/src/lib/libbsp/sparc/shared/irq_asm.S b/c/src/lib/libbsp/sparc/shared/irq_asm.S
index 075c780..b4374c3 100644
--- a/c/src/lib/libbsp/sparc/shared/irq_asm.S
+++ b/c/src/lib/libbsp/sparc/shared/irq_asm.S
@@ -66,14 +66,22 @@ SYM(_CPU_Context_switch):
          */
 
         std     %l0, [%o0 + L0_OFFSET]       ! save the local registers
+        SPARC_LEON3FT_B2BST_NOP
         std     %l2, [%o0 + L2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l4, [%o0 + L4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l6, [%o0 + L6_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         std     %i0, [%o0 + I0_OFFSET]       ! save the input registers
+        SPARC_LEON3FT_B2BST_NOP
         std     %i2, [%o0 + I2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i4, [%o0 + I4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i6, [%o0 + I6_FP_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         std     %o6, [%o0 + O6_SP_OFFSET]    ! save the output registers
 
@@ -158,14 +166,22 @@ save_frame_loop:
          */
 
         std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         ba      save_frame_loop
         nop
@@ -375,13 +391,20 @@ win_ovflow:
          */
 
         std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
 
         restore
@@ -406,15 +429,21 @@ dont_do_the_window:
                                                ! make space for ISF
 
         std     %l0, [%sp + ISF_PSR_OFFSET]    ! save psr, PC
+        SPARC_LEON3FT_B2BST_NOP
         st      %l2, [%sp + ISF_NPC_OFFSET]    ! save nPC
         st      %g1, [%sp + ISF_G1_OFFSET]     ! save g1
         std     %g2, [%sp + ISF_G2_OFFSET]     ! save g2, g3
+        SPARC_LEON3FT_B2BST_NOP
         std     %l4, [%sp + ISF_G4_OFFSET]     ! save g4, g5 -- see above
+        SPARC_LEON3FT_B2BST_NOP
         st      %g7, [%sp + ISF_G7_OFFSET]     ! save g7
 
         std     %i0, [%sp + ISF_I0_OFFSET]     ! save i0, i1
+        SPARC_LEON3FT_B2BST_NOP
         std     %i2, [%sp + ISF_I2_OFFSET]     ! save i2, i3
+        SPARC_LEON3FT_B2BST_NOP
         std     %i4, [%sp + ISF_I4_OFFSET]     ! save i4, i5
+        SPARC_LEON3FT_B2BST_NOP
         std     %i6, [%sp + ISF_I6_FP_OFFSET]  ! save i6/fp, i7
 
         rd      %y, %g1
@@ -440,6 +469,7 @@ dont_do_the_window:
 
         add      %l7, 1, %l7
         st       %l7, [%g6 + PER_CPU_ISR_NEST_LEVEL]
+        SPARC_LEON3FT_B2BST_NOP
 
         add      %l6, 1, %l6
         st       %l6, [%g6 + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
@@ -587,6 +617,7 @@ profiling_not_outer_most_exit:
         ldub     [%g6 + PER_CPU_DISPATCH_NEEDED], %o2
         ld       [%g6 + PER_CPU_ISR_DISPATCH_DISABLE], %o3
         st       %l7, [%g6 + PER_CPU_ISR_NEST_LEVEL]
+        SPARC_LEON3FT_B2BST_NOP
         sub      %l6, 1, %l6
         st       %l6, [%g6 + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
 
@@ -635,21 +666,37 @@ isr_dispatch:
          */
         sub     %sp, FP_FRAME_SIZE, %sp
         std     %f0, [%sp + FP_FRAME_OFFSET_FO_F1]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f2, [%sp + FP_FRAME_OFFSET_F2_F3]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f4, [%sp + FP_FRAME_OFFSET_F4_F5]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f6, [%sp + FP_FRAME_OFFSET_F6_F7]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f8, [%sp + FP_FRAME_OFFSET_F8_F9]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f10, [%sp + FP_FRAME_OFFSET_F1O_F11]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f12, [%sp + FP_FRAME_OFFSET_F12_F13]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f14, [%sp + FP_FRAME_OFFSET_F14_F15]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f16, [%sp + FP_FRAME_OFFSET_F16_F17]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f18, [%sp + FP_FRAME_OFFSET_F18_F19]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f20, [%sp + FP_FRAME_OFFSET_F2O_F21]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f22, [%sp + FP_FRAME_OFFSET_F22_F23]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f24, [%sp + FP_FRAME_OFFSET_F24_F25]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f26, [%sp + FP_FRAME_OFFSET_F26_F27]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f28, [%sp + FP_FRAME_OFFSET_F28_F29]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f30, [%sp + FP_FRAME_OFFSET_F3O_F31]
+        SPARC_LEON3FT_B2BST_NOP
         st      %fsr, [%sp + FP_FRAME_OFFSET_FSR]
         call    SYM(_Thread_Do_dispatch)
          mov    %g6, %o0
diff --git a/c/src/lib/libcpu/sparc/access/access.S b/c/src/lib/libcpu/sparc/access/access.S
index cb8693b..9397cb8 100644
--- a/c/src/lib/libcpu/sparc/access/access.S
+++ b/c/src/lib/libcpu/sparc/access/access.S
@@ -59,6 +59,33 @@ SYM(_ld64):
 	retl
 	 ldd [%o0], %o0
 
+#if defined(__FIX_LEON3FT_B2BST)
+
+SYM(_st8):
+	stub %o1, [%o0]
+	retl
+	 nop
+
+SYM(_st_be16):
+SYM(_st16):
+	stuh %o1, [%o0]
+	retl
+	 nop
+
+SYM(_st_be32):
+SYM(_st32):
+	st %o1, [%o0]
+	retl
+	 nop
+
+SYM(_st_be64):
+SYM(_st64):
+	std %o1, [%o0]
+	retl
+	 nop
+
+#else
+
 SYM(_st8):
 	retl
 	 stb %o1, [%o0]
@@ -79,3 +106,4 @@ SYM(_st64):
 	mov %o1, %o2
 	retl
 	 std %o2, [%o0]
+#endif
diff --git a/c/src/lib/libcpu/sparc/reg_win/window.S b/c/src/lib/libcpu/sparc/reg_win/window.S
index b874559..5a36fd6 100644
--- a/c/src/lib/libcpu/sparc/reg_win/window.S
+++ b/c/src/lib/libcpu/sparc/reg_win/window.S
@@ -51,19 +51,24 @@ SYM(window_overflow_trap_handler):
          */
 
         std  %l0, [%sp + 0x00]           ! save local register set
+        SPARC_LEON3FT_B2BST_NOP
         std  %l2, [%sp + 0x08]
         mov  %wim, %l3
         sll  %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l2
                                          ! l2  = WIM << (Number Windows - 1)
         std  %l4, [%sp + 0x10]
+        SPARC_LEON3FT_B2BST_NOP
         std  %l6, [%sp + 0x18]
         srl  %l3, 1, %l3                 ! l3  = WIM >> 1
         wr   %l3, %l2, %wim              ! WIM = (WIM >> 1) ^
                                          !       (WIM << (Number Windows - 1))
                                          ! 3 instruction delay not needed here
         std  %i0, [%sp + 0x20]           ! save input register set
+        SPARC_LEON3FT_B2BST_NOP
         std  %i2, [%sp + 0x28]
+        SPARC_LEON3FT_B2BST_NOP
         std  %i4, [%sp + 0x30]
+        SPARC_LEON3FT_B2BST_NOP
         std  %i6, [%sp + 0x38]
         restore                          ! Go back to trap window.
         jmp  %l1                         ! Re-execute save.
@@ -206,13 +211,20 @@ save_frame_loop:
          */
 
         std     %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
 
         std     %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
 
         ba      save_frame_loop
diff --git a/cpukit/score/cpu/sparc/cpu_asm.S b/cpukit/score/cpu/sparc/cpu_asm.S
index 4e683da..399c955 100644
--- a/cpukit/score/cpu/sparc/cpu_asm.S
+++ b/cpukit/score/cpu/sparc/cpu_asm.S
@@ -46,23 +46,45 @@
 SYM(_CPU_Context_save_fp):
         ld      [%o0], %o1
         std     %f0, [%o1 + FO_F1_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f2, [%o1 + F2_F3_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f4, [%o1 + F4_F5_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f6, [%o1 + F6_F7_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f8, [%o1 + F8_F9_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f10, [%o1 + F1O_F11_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f12, [%o1 + F12_F13_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f14, [%o1 + F14_F15_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f16, [%o1 + F16_F17_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f18, [%o1 + F18_F19_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f20, [%o1 + F2O_F21_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f22, [%o1 + F22_F23_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f24, [%o1 + F24_F25_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f26, [%o1 + F26_F27_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f28, [%o1 + F28_F29_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
         std     %f30, [%o1 + F3O_F31_OFFSET]
+        SPARC_LEON3FT_B2BST_NOP
+#if defined(__FIX_LEON3FT_B2BST)
+        st     %fsr, [%o1 + FSR_OFFSET]
+        jmp     %o7 + 8
+         nop
+#else
         jmp     %o7 + 8
          st     %fsr, [%o1 + FSR_OFFSET]
+#endif
 
 /*
  *  void _CPU_Context_restore_fp(
diff --git a/cpukit/score/cpu/sparc/rtems/score/sparc.h b/cpukit/score/cpu/sparc/rtems/score/sparc.h
index 97a59dd..eb69b76 100644
--- a/cpukit/score/cpu/sparc/rtems/score/sparc.h
+++ b/cpukit/score/cpu/sparc/rtems/score/sparc.h
@@ -63,6 +63,16 @@ extern "C" {
 #define SPARC_NUMBER_OF_REGISTER_WINDOWS 8
 
 /**
+ * See GRLIB-TN-0009: "LEON3FT Stale Cache Entry After Store with
+ * Data Tag Parity Error"
+ */
+#if defined(__FIX_LEON3FT_B2BST)
+  #define SPARC_LEON3FT_B2BST_NOP nop
+#else
+  #define SPARC_LEON3FT_B2BST_NOP
+#endif
+
+/**
  * This macro contains a string describing the multilib variant being
  * build.
  */
diff --git a/cpukit/score/cpu/sparc/sparc-context-validate.S b/cpukit/score/cpu/sparc/sparc-context-validate.S
index e0724e0..777f4dd 100644
--- a/cpukit/score/cpu/sparc/sparc-context-validate.S
+++ b/cpukit/score/cpu/sparc/sparc-context-validate.S
@@ -282,6 +282,7 @@ y_checking:
 	 nop
 
 	st	%o1, [%sp + FRAME_OFFSET_BUFFER_2]
+	SPARC_LEON3FT_B2BST_NOP
 	/* Check floating point registers */
 	check_float_register	%f31
 	check_float_register	%f30
-- 
2.9.3



More information about the devel mailing list