[PATCH v2] score: Add CPU context validation

Sebastian Huber sebastian.huber at embedded-brains.de
Wed May 8 15:15:28 UTC 2013


---
 cpukit/score/cpu/arm/Makefile.am                   |    2 +
 cpukit/score/cpu/arm/arm-context-validate.S        |  139 +++++++++++
 .../score/cpu/arm/arm-context-volatile-clobber.S   |   37 +++
 cpukit/score/cpu/arm/rtems/score/cpu.h             |    4 +
 cpukit/score/cpu/avr/rtems/score/cpu.h             |   12 +
 cpukit/score/cpu/bfin/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/h8300/rtems/score/cpu.h           |   12 +
 cpukit/score/cpu/i386/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/lm32/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/m32c/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/m32r/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/m68k/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/mips/rtems/score/cpu.h            |   12 +
 cpukit/score/cpu/moxie/rtems/score/cpu.h           |   12 +
 cpukit/score/cpu/nios2/Makefile.am                 |    2 +
 cpukit/score/cpu/nios2/nios2-context-validate.S    |  146 +++++++++++
 .../cpu/nios2/nios2-context-volatile-clobber.S     |   42 +++
 cpukit/score/cpu/nios2/rtems/score/cpu.h           |    4 +
 cpukit/score/cpu/no_cpu/rtems/score/cpu.h          |   31 +++
 cpukit/score/cpu/powerpc/Makefile.am               |    2 +
 cpukit/score/cpu/powerpc/ppc-context-validate.S    |  263 ++++++++++++++++++++
 .../cpu/powerpc/ppc-context-volatile-clobber.S     |   45 ++++
 cpukit/score/cpu/powerpc/rtems/score/cpu.h         |    4 +
 cpukit/score/cpu/sh/rtems/score/cpu.h              |   12 +
 cpukit/score/cpu/sparc/rtems/score/cpu.h           |   12 +
 cpukit/score/cpu/sparc64/rtems/score/cpu.h         |   12 +
 cpukit/score/cpu/v850/rtems/score/cpu.h            |   12 +
 doc/porting/miscellaneous.t                        |   25 ++
 testsuites/sptests/Makefile.am                     |    1 +
 testsuites/sptests/configure.ac                    |    1 +
 testsuites/sptests/spcontext01/Makefile.am         |   19 ++
 testsuites/sptests/spcontext01/init.c              |  188 ++++++++++++++
 testsuites/sptests/spcontext01/spcontext01.doc     |   11 +
 testsuites/sptests/spcontext01/spcontext01.scn     |    2 +
 34 files changed, 1136 insertions(+), 0 deletions(-)
 create mode 100644 cpukit/score/cpu/arm/arm-context-validate.S
 create mode 100644 cpukit/score/cpu/arm/arm-context-volatile-clobber.S
 create mode 100644 cpukit/score/cpu/nios2/nios2-context-validate.S
 create mode 100644 cpukit/score/cpu/nios2/nios2-context-volatile-clobber.S
 create mode 100644 cpukit/score/cpu/powerpc/ppc-context-validate.S
 create mode 100644 cpukit/score/cpu/powerpc/ppc-context-volatile-clobber.S
 create mode 100644 testsuites/sptests/spcontext01/Makefile.am
 create mode 100644 testsuites/sptests/spcontext01/init.c
 create mode 100644 testsuites/sptests/spcontext01/spcontext01.doc
 create mode 100644 testsuites/sptests/spcontext01/spcontext01.scn

diff --git a/cpukit/score/cpu/arm/Makefile.am b/cpukit/score/cpu/arm/Makefile.am
index 61a278b..37ab901 100644
--- a/cpukit/score/cpu/arm/Makefile.am
+++ b/cpukit/score/cpu/arm/Makefile.am
@@ -16,6 +16,8 @@ libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
 libscorecpu_a_SOURCES =
 libscorecpu_a_SOURCES += cpu.c
 libscorecpu_a_SOURCES += cpu_asm.S
+libscorecpu_a_SOURCES += arm-context-validate.S
+libscorecpu_a_SOURCES += arm-context-volatile-clobber.S
 libscorecpu_a_SOURCES += arm_exc_abort.S
 libscorecpu_a_SOURCES += arm_exc_interrupt.S
 libscorecpu_a_SOURCES += arm_exc_handler_low.S
diff --git a/cpukit/score/cpu/arm/arm-context-validate.S b/cpukit/score/cpu/arm/arm-context-validate.S
new file mode 100644
index 0000000..4591d20
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm-context-validate.S
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+#define FRAME_OFFSET_R4 0
+#define FRAME_OFFSET_R5 4
+#define FRAME_OFFSET_R6 8
+#define FRAME_OFFSET_R7 12
+#define FRAME_OFFSET_R8 16
+#define FRAME_OFFSET_R9 20
+#define FRAME_OFFSET_R10 24
+#define FRAME_OFFSET_R11 28
+#define FRAME_OFFSET_LR 32
+
+#define FRAME_SIZE (FRAME_OFFSET_LR + 4)
+
+	.section	.text
+
+FUNCTION_THUMB_ENTRY(_CPU_Context_validate)
+
+	/* Save */
+
+	sub	sp, sp, #FRAME_SIZE
+
+	mov	r1, r4
+	str	r1, [sp, #FRAME_OFFSET_R4]
+	mov	r1, r5
+	str	r1, [sp, #FRAME_OFFSET_R5]
+	mov	r1, r6
+	str	r1, [sp, #FRAME_OFFSET_R6]
+	mov	r1, r7
+	str	r1, [sp, #FRAME_OFFSET_R7]
+	mov	r1, r8
+	str	r1, [sp, #FRAME_OFFSET_R8]
+	mov	r1, r9
+	str	r1, [sp, #FRAME_OFFSET_R9]
+	mov	r1, r10
+	str	r1, [sp, #FRAME_OFFSET_R10]
+	mov	r1, r11
+	str	r1, [sp, #FRAME_OFFSET_R11]
+	mov	r1, lr
+	str	r1, [sp, #FRAME_OFFSET_LR]
+
+	/* Fill */
+
+	/* R1 is used for temporary values */
+	mov	r1, r0
+
+	/* R2 contains the stack pointer */
+	mov	r2, sp
+
+.macro fill_register reg
+	add	r1, r1, #1
+	mov	\reg, r1
+.endm
+
+	fill_register	r3
+	fill_register	r4
+	fill_register	r5
+	fill_register	r6
+	fill_register	r7
+	fill_register	r8
+	fill_register	r9
+	fill_register	r10
+	fill_register	r11
+	fill_register	r12
+	fill_register	lr
+
+	/* Check */
+check:
+
+.macro check_register reg
+	add	r1, r1, #1
+	cmp	\reg, r1
+	bne	restore
+.endm
+
+	cmp	r2, sp
+	bne	restore
+
+	mov	r1, r0
+
+	check_register	r3
+	check_register	r4
+	check_register	r5
+	check_register	r6
+	check_register	r7
+	check_register	r8
+	check_register	r9
+	check_register	r10
+	check_register	r11
+	check_register	r12
+	check_register	lr
+
+	b	check
+
+	/* Restore */
+restore:
+
+	ldr	r1, [sp, #FRAME_OFFSET_R4]
+	mov	r4, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R5]
+	mov	r5, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R6]
+	mov	r6, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R7]
+	mov	r7, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R8]
+	mov	r8, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R9]
+	mov	r9, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R10]
+	mov	r10, r1
+	ldr	r1, [sp, #FRAME_OFFSET_R11]
+	mov	r11, r1
+	ldr	r1, [sp, #FRAME_OFFSET_LR]
+	mov	lr, r1
+
+	add	sp, sp, #FRAME_SIZE
+
+	bx	lr
+
+FUNCTION_END(_CPU_Context_validate)
diff --git a/cpukit/score/cpu/arm/arm-context-volatile-clobber.S b/cpukit/score/cpu/arm/arm-context-volatile-clobber.S
new file mode 100644
index 0000000..b79e570
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm-context-volatile-clobber.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+	.section	.text
+
+FUNCTION_THUMB_ENTRY(_CPU_Context_volatile_clobber)
+
+.macro clobber_register reg
+	sub	r0, r0, #1
+	mov	\reg, r0
+.endm
+
+	clobber_register	r1
+	clobber_register	r2
+	clobber_register	r3
+	clobber_register	r12
+
+	bx	lr
+
+FUNCTION_END(_CPU_Context_volatile_clobber)
diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h
index 5ed6b9b..b6f39ac 100644
--- a/cpukit/score/cpu/arm/rtems/score/cpu.h
+++ b/cpukit/score/cpu/arm/rtems/score/cpu.h
@@ -423,6 +423,10 @@ void _CPU_Context_save_fp( Context_Control_fp **fp_context_ptr );
 
 void _CPU_Context_restore_fp( Context_Control_fp **fp_context_ptr );
 
+void _CPU_Context_volatile_clobber( uintptr_t pattern );
+
+void _CPU_Context_validate( uintptr_t pattern );
+
 static inline uint32_t CPU_swap_u32( uint32_t value )
 {
 #if defined(__thumb2__)
diff --git a/cpukit/score/cpu/avr/rtems/score/cpu.h b/cpukit/score/cpu/avr/rtems/score/cpu.h
index 5f1577a..080f387 100644
--- a/cpukit/score/cpu/avr/rtems/score/cpu.h
+++ b/cpukit/score/cpu/avr/rtems/score/cpu.h
@@ -1114,6 +1114,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /* FIXME */
 typedef CPU_Interrupt_frame CPU_Exception_frame;
 
diff --git a/cpukit/score/cpu/bfin/rtems/score/cpu.h b/cpukit/score/cpu/bfin/rtems/score/cpu.h
index 1b26527..aba01e9 100644
--- a/cpukit/score/cpu/bfin/rtems/score/cpu.h
+++ b/cpukit/score/cpu/bfin/rtems/score/cpu.h
@@ -1213,6 +1213,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /** @} */
 
 /* FIXME */
diff --git a/cpukit/score/cpu/h8300/rtems/score/cpu.h b/cpukit/score/cpu/h8300/rtems/score/cpu.h
index 6031f96..ea0ee7c 100644
--- a/cpukit/score/cpu/h8300/rtems/score/cpu.h
+++ b/cpukit/score/cpu/h8300/rtems/score/cpu.h
@@ -1097,6 +1097,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /* FIXME */
 typedef CPU_Interrupt_frame CPU_Exception_frame;
 
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index 6667604..6a19fb1 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -667,6 +667,18 @@ void _CPU_Context_restore_fp(
   } while (0)
 #endif
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
 
 #endif /* ASM */
diff --git a/cpukit/score/cpu/lm32/rtems/score/cpu.h b/cpukit/score/cpu/lm32/rtems/score/cpu.h
index 1f8a370..eef9ac8 100644
--- a/cpukit/score/cpu/lm32/rtems/score/cpu.h
+++ b/cpukit/score/cpu/lm32/rtems/score/cpu.h
@@ -1202,6 +1202,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /** @} */
 
 /* FIXME */
diff --git a/cpukit/score/cpu/m32c/rtems/score/cpu.h b/cpukit/score/cpu/m32c/rtems/score/cpu.h
index 8d9acc3..ccb9e38 100644
--- a/cpukit/score/cpu/m32c/rtems/score/cpu.h
+++ b/cpukit/score/cpu/m32c/rtems/score/cpu.h
@@ -1153,6 +1153,18 @@ void _CPU_Context_restore(
   Context_Control *new_context
 ) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /* FIXME */
 typedef CPU_Interrupt_frame CPU_Exception_frame;
 
diff --git a/cpukit/score/cpu/m32r/rtems/score/cpu.h b/cpukit/score/cpu/m32r/rtems/score/cpu.h
index 8c8a9c1..2c97ddb 100644
--- a/cpukit/score/cpu/m32r/rtems/score/cpu.h
+++ b/cpukit/score/cpu/m32r/rtems/score/cpu.h
@@ -1194,6 +1194,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /** @} */
 
 /* FIXME */
diff --git a/cpukit/score/cpu/m68k/rtems/score/cpu.h b/cpukit/score/cpu/m68k/rtems/score/cpu.h
index 0f244e1..2af5be8 100644
--- a/cpukit/score/cpu/m68k/rtems/score/cpu.h
+++ b/cpukit/score/cpu/m68k/rtems/score/cpu.h
@@ -711,6 +711,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /**
  *  This method prints the CPU exception frame.
  *
diff --git a/cpukit/score/cpu/mips/rtems/score/cpu.h b/cpukit/score/cpu/mips/rtems/score/cpu.h
index 130c960..229490b 100644
--- a/cpukit/score/cpu/mips/rtems/score/cpu.h
+++ b/cpukit/score/cpu/mips/rtems/score/cpu.h
@@ -1125,6 +1125,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 void _BSP_Exception_frame_print( const CPU_Exception_frame *frame );
 
 static inline void _CPU_Exception_frame_print(
diff --git a/cpukit/score/cpu/moxie/rtems/score/cpu.h b/cpukit/score/cpu/moxie/rtems/score/cpu.h
index e51798b..7c48d7b 100644
--- a/cpukit/score/cpu/moxie/rtems/score/cpu.h
+++ b/cpukit/score/cpu/moxie/rtems/score/cpu.h
@@ -970,6 +970,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /**
  * @brief The set of registers that specifies the complete processor state.
  *
diff --git a/cpukit/score/cpu/nios2/Makefile.am b/cpukit/score/cpu/nios2/Makefile.am
index 27bfb30..6fdc786 100644
--- a/cpukit/score/cpu/nios2/Makefile.am
+++ b/cpukit/score/cpu/nios2/Makefile.am
@@ -23,6 +23,8 @@ noinst_LIBRARIES = libscorecpu.a
 libscorecpu_a_SOURCES =
 libscorecpu_a_SOURCES += nios2-context-initialize.c
 libscorecpu_a_SOURCES += nios2-context-switch.S
+libscorecpu_a_SOURCES += nios2-context-validate.S
+libscorecpu_a_SOURCES += nios2-context-volatile-clobber.S
 libscorecpu_a_SOURCES += nios2-eic-il-low-level.S
 libscorecpu_a_SOURCES += nios2-eic-rsie-low-level.S
 libscorecpu_a_SOURCES += nios2-exception-frame-print.c
diff --git a/cpukit/score/cpu/nios2/nios2-context-validate.S b/cpukit/score/cpu/nios2/nios2-context-validate.S
new file mode 100644
index 0000000..9a5f5e1
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-context-validate.S
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+#define FRAME_OFFSET_R16 0
+#define FRAME_OFFSET_R17 4
+#define FRAME_OFFSET_R18 8
+#define FRAME_OFFSET_R19 12
+#define FRAME_OFFSET_R20 16
+#define FRAME_OFFSET_R21 20
+#define FRAME_OFFSET_R22 24
+#define FRAME_OFFSET_R23 28
+#define FRAME_OFFSET_FP 32
+#define FRAME_OFFSET_RA 36
+
+#define FRAME_SIZE (FRAME_OFFSET_RA + 4)
+
+	.set	noat
+	.section	.text
+
+	.global _CPU_Context_validate
+
+_CPU_Context_validate:
+
+	/* Save */
+	subi	sp, sp, FRAME_SIZE
+	stw	r16, FRAME_OFFSET_R16(sp)
+	stw	r17, FRAME_OFFSET_R17(sp)
+	stw	r18, FRAME_OFFSET_R18(sp)
+	stw	r19, FRAME_OFFSET_R19(sp)
+	stw	r20, FRAME_OFFSET_R20(sp)
+	stw	r21, FRAME_OFFSET_R21(sp)
+	stw	r22, FRAME_OFFSET_R22(sp)
+	stw	r23, FRAME_OFFSET_R23(sp)
+	stw	fp, FRAME_OFFSET_FP(sp)
+	stw	ra, FRAME_OFFSET_RA(sp)
+
+	/* Fill */
+
+	/* AT contains the stack pointer */
+	mov	at, sp
+
+	/* R2 is used for temporary values */
+
+	subi	r3, r4, 1
+	addi	r5, r4, 1
+	addi	r6, r4, 2
+	addi	r7, r4, 3
+	addi	r8, r4, 4
+	addi	r9, r4, 5
+	addi	r10, r4, 6
+	addi	r11, r4, 7
+	addi	r12, r4, 8
+	addi	r13, r4, 9
+	addi	r14, r4, 10
+	addi	r15, r4, 11
+	addi	r16, r4, 12
+	addi	r17, r4, 13
+	addi	r18, r4, 14
+	addi	r19, r4, 15
+	addi	r20, r4, 16
+	addi	r21, r4, 17
+	addi	r22, r4, 18
+	addi	r23, r4, 19
+	addi	fp, r4, 20
+	addi	ra, r4, 21
+
+	/* Check */
+check:
+	bne	sp, at, restore
+	subi	r2, r4, 1
+	bne	r2, r3, restore
+	addi	r2, r4, 1
+	bne	r2, r5, restore
+	addi	r2, r4, 2
+	bne	r2, r6, restore
+	addi	r2, r4, 3
+	bne	r2, r7, restore
+	addi	r2, r4, 4
+	bne	r2, r8, restore
+	addi	r2, r4, 5
+	bne	r2, r9, restore
+	addi	r2, r4, 6
+	bne	r2, r10, restore
+	addi	r2, r4, 7
+	bne	r2, r11, restore
+	addi	r2, r4, 8
+	bne	r2, r12, restore
+	addi	r2, r4, 9
+	bne	r2, r13, restore
+	addi	r2, r4, 10
+	bne	r2, r14, restore
+	addi	r2, r4, 11
+	bne	r2, r15, restore
+	addi	r2, r4, 12
+	bne	r2, r16, restore
+	addi	r2, r4, 13
+	bne	r2, r17, restore
+	addi	r2, r4, 14
+	bne	r2, r18, restore
+	addi	r2, r4, 15
+	bne	r2, r19, restore
+	addi	r2, r4, 16
+	bne	r2, r20, restore
+	addi	r2, r4, 17
+	bne	r2, r21, restore
+	addi	r2, r4, 18
+	bne	r2, r22, restore
+	addi	r2, r4, 19
+	bne	r2, r23, restore
+	addi	r2, r4, 20
+	bne	r2, fp, restore
+	addi	r2, r4, 21
+	bne	r2, ra, restore
+	br	check
+
+	/* Restore */
+restore:
+	ldw	ra, FRAME_OFFSET_RA(sp)
+	ldw	fp, FRAME_OFFSET_FP(sp)
+	ldw	r23, FRAME_OFFSET_R23(sp)
+	ldw	r22, FRAME_OFFSET_R22(sp)
+	ldw	r21, FRAME_OFFSET_R21(sp)
+	ldw	r20, FRAME_OFFSET_R20(sp)
+	ldw	r19, FRAME_OFFSET_R19(sp)
+	ldw	r18, FRAME_OFFSET_R18(sp)
+	ldw	r17, FRAME_OFFSET_R17(sp)
+	ldw	r16, FRAME_OFFSET_R16(sp)
+	addi	sp, sp, FRAME_SIZE
+	ret
diff --git a/cpukit/score/cpu/nios2/nios2-context-volatile-clobber.S b/cpukit/score/cpu/nios2/nios2-context-volatile-clobber.S
new file mode 100644
index 0000000..7b484e7
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-context-volatile-clobber.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+	.set	noat
+	.section	.text
+
+	.global _CPU_Context_volatile_clobber
+
+_CPU_Context_volatile_clobber:
+
+	subi	at, r4, 11
+	subi	r2, r4, 12
+	subi	r3, r4, 13
+	subi	r5, r4, 1
+	subi	r6, r4, 2
+	subi	r7, r4, 3
+	subi	r8, r4, 4
+	subi	r9, r4, 5
+	subi	r10, r4, 6
+	subi	r11, r4, 7
+	subi	r12, r4, 8
+	subi	r13, r4, 9
+	subi	r14, r4, 10
+	subi	r15, r4, 11
+	ret
diff --git a/cpukit/score/cpu/nios2/rtems/score/cpu.h b/cpukit/score/cpu/nios2/rtems/score/cpu.h
index b0e94c5..d3b5046 100644
--- a/cpukit/score/cpu/nios2/rtems/score/cpu.h
+++ b/cpukit/score/cpu/nios2/rtems/score/cpu.h
@@ -333,6 +333,10 @@ void _CPU_Context_restore(
   Context_Control *new_context
 ) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
 
+void _CPU_Context_volatile_clobber( uintptr_t pattern );
+
+void _CPU_Context_validate( uintptr_t pattern );
+
 void _CPU_Exception_frame_print( const CPU_Exception_frame *frame );
 
 static inline uint32_t CPU_swap_u32( uint32_t value )
diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
index 8c4a61b..6d72976 100644
--- a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
+++ b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h
@@ -1295,6 +1295,37 @@ void _CPU_Context_restore_fp(
 );
 
 /**
+ * @ingroup CPUContext
+ *
+ * @brief Clobbers all volatile registers with values derived from the pattern
+ * parameter.
+ *
+ * This function is used only in test sptests/spcontext01.
+ *
+ * @param[in] pattern Pattern used to generate distinct register values.
+ *
+ * @see _CPU_Context_validate().
+ */
+void _CPU_Context_volatile_clobber( uintptr_t pattern );
+
+/**
+ * @ingroup CPUContext
+ *
+ * @brief Initializes and validates the CPU context with values derived from
+ * the pattern parameter.
+ *
+ * This function will not return if the CPU context remains consistent.  In
+ * case this function returns the CPU port is broken.
+ *
+ * This function is used only in test sptests/spcontext01.
+ *
+ * @param[in] pattern Pattern used to generate distinct register values.
+ *
+ * @see _CPU_Context_volatile_clobber().
+ */
+void _CPU_Context_validate( uintptr_t pattern );
+
+/**
  * @brief The set of registers that specifies the complete processor state.
  *
  * The CPU exception frame may be available in fatal error conditions like for
diff --git a/cpukit/score/cpu/powerpc/Makefile.am b/cpukit/score/cpu/powerpc/Makefile.am
index 7fd64ef..b205762 100644
--- a/cpukit/score/cpu/powerpc/Makefile.am
+++ b/cpukit/score/cpu/powerpc/Makefile.am
@@ -14,6 +14,8 @@ include_rtems_powerpc_HEADERS = rtems/powerpc/registers.h
 
 noinst_LIBRARIES = libscorecpu.a
 libscorecpu_a_SOURCES = cpu.c
+libscorecpu_a_SOURCES += ppc-context-volatile-clobber.S
+libscorecpu_a_SOURCES += ppc-context-validate.S
 libscorecpu_a_SOURCES += ppc-isr-vector-install.c
 libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
 
diff --git a/cpukit/score/cpu/powerpc/ppc-context-validate.S b/cpukit/score/cpu/powerpc/ppc-context-validate.S
new file mode 100644
index 0000000..0e3154e
--- /dev/null
+++ b/cpukit/score/cpu/powerpc/ppc-context-validate.S
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+#include <rtems/score/cpu.h>
+
+#define LR_OFFSET 8
+#define CR_OFFSET 12
+#define OFFSET(i) ((i) * PPC_GPR_SIZE + 16)
+#define GPR14_OFFSET OFFSET(0)
+#define GPR15_OFFSET OFFSET(1)
+#define GPR16_OFFSET OFFSET(2)
+#define GPR17_OFFSET OFFSET(3)
+#define GPR18_OFFSET OFFSET(4)
+#define GPR19_OFFSET OFFSET(5)
+#define GPR20_OFFSET OFFSET(6)
+#define GPR21_OFFSET OFFSET(7)
+#define GPR22_OFFSET OFFSET(8)
+#define GPR23_OFFSET OFFSET(9)
+#define GPR24_OFFSET OFFSET(10)
+#define GPR25_OFFSET OFFSET(11)
+#define GPR26_OFFSET OFFSET(12)
+#define GPR27_OFFSET OFFSET(13)
+#define GPR28_OFFSET OFFSET(14)
+#define GPR29_OFFSET OFFSET(15)
+#define GPR30_OFFSET OFFSET(16)
+#define GPR31_OFFSET OFFSET(17)
+#define FRAME_SIZE \
+  ((OFFSET(18) + CPU_STACK_ALIGNMENT - 1) & (CPU_STACK_ALIGNMENT - 1))
+
+	.global _CPU_Context_validate
+
+_CPU_Context_validate:
+
+	/* Save */
+	stwu	r1, -FRAME_SIZE(r1)
+	mflr	r4
+	stw	r4, LR_OFFSET(r1)
+	mfcr	r4
+	stw	r4, CR_OFFSET(r1)
+	stw	r14, GPR14_OFFSET(r1)
+	stw	r15, GPR15_OFFSET(r1)
+	stw	r16, GPR16_OFFSET(r1)
+	stw	r17, GPR17_OFFSET(r1)
+	stw	r18, GPR18_OFFSET(r1)
+	stw	r19, GPR19_OFFSET(r1)
+	stw	r20, GPR20_OFFSET(r1)
+	stw	r21, GPR21_OFFSET(r1)
+	stw	r22, GPR22_OFFSET(r1)
+	stw	r23, GPR23_OFFSET(r1)
+	stw	r24, GPR24_OFFSET(r1)
+	stw	r25, GPR25_OFFSET(r1)
+	stw	r26, GPR26_OFFSET(r1)
+	stw	r27, GPR27_OFFSET(r1)
+	stw	r28, GPR28_OFFSET(r1)
+	stw	r29, GPR29_OFFSET(r1)
+	stw	r30, GPR30_OFFSET(r1)
+	stw	r31, GPR31_OFFSET(r1)
+
+	/* Fill */
+
+	/* CR and GPR29 are equal most of the time */
+	addi	r4, r3, 24
+	mtcr	r4
+
+	addi	r4, r3, 25
+	mtlr	r4
+	addi	r4, r3, 26
+	mtctr	r4
+	addi	r4, r3, 27
+	mtxer	r4
+	addi	r0, r3, 28
+
+	/* GPR4 is used for temporary values */
+
+	addi	r5, r3, 1
+	addi	r6, r3, 2
+	addi	r7, r3, 3
+	addi	r8, r3, 4
+	addi	r9, r3, 5
+	addi	r10, r3, 6
+	addi	r11, r3, 7
+	addi	r12, r3, 8
+	addi	r14, r3, 9
+	addi	r15, r3, 10
+	addi	r16, r3, 11
+	addi	r17, r3, 12
+	addi	r18, r3, 13
+	addi	r19, r3, 14
+	addi	r20, r3, 15
+	addi	r21, r3, 16
+	addi	r22, r3, 17
+	addi	r23, r3, 18
+	addi	r24, r3, 19
+	addi	r25, r3, 20
+	addi	r26, r3, 21
+	addi	r27, r3, 22
+	addi	r28, r3, 23
+
+	/* GPR29 and CR are equal most of the time */
+	addi	r29, r3, 24
+
+	/* GPR30 contains the MSR pattern */
+	mfmsr	r30
+	xor	r30, r30, r3
+
+	/* GPR31 contains the stack pointer */
+	mr	r31, r1
+
+	/* Check */
+check:
+	mfcr	r4
+	cmpw	r4, r29
+	bne	restore
+	addi	r4, r3, 1
+	cmpw	r4, r5
+	bne	restore
+	addi	r4, r3, 2
+	cmpw	r4, r6
+	bne	restore
+	addi	r4, r3, 3
+	cmpw	r4, r7
+	bne	restore
+	addi	r4, r3, 4
+	cmpw	r4, r8
+	bne	restore
+	addi	r4, r3, 5
+	cmpw	r4, r9
+	bne	restore
+	addi	r4, r3, 6
+	cmpw	r4, r10
+	bne	restore
+	addi	r4, r3, 7
+	cmpw	r4, r11
+	bne	restore
+	addi	r4, r3, 8
+	cmpw	r4, r12
+	bne	restore
+	lis	r4, _SDA_BASE_ at h
+	ori	r4, r4, _SDA_BASE_ at l
+	cmpw	r4, r13
+	bne	restore
+	addi	r4, r3, 9
+	cmpw	r4, r14
+	bne	restore
+	addi	r4, r3, 10
+	cmpw	r4, r15
+	bne	restore
+	addi	r4, r3, 11
+	cmpw	r4, r16
+	bne	restore
+	addi	r4, r3, 12
+	cmpw	r4, r17
+	bne	restore
+	addi	r4, r3, 13
+	cmpw	r4, r18
+	bne	restore
+	addi	r4, r3, 14
+	cmpw	r4, r19
+	bne	restore
+	addi	r4, r3, 15
+	cmpw	r4, r20
+	bne	restore
+	addi	r4, r3, 16
+	cmpw	r4, r21
+	bne	restore
+	addi	r4, r3, 17
+	cmpw	r4, r22
+	bne	restore
+	addi	r4, r3, 18
+	cmpw	r4, r23
+	bne	restore
+	addi	r4, r3, 19
+	cmpw	r4, r24
+	bne	restore
+	addi	r4, r3, 20
+	cmpw	r4, r25
+	bne	restore
+	addi	r4, r3, 21
+	cmpw	r4, r26
+	bne	restore
+	addi	r4, r3, 22
+	cmpw	r4, r27
+	bne	restore
+	addi	r4, r3, 23
+	cmpw	r4, r28
+	bne	restore
+	addi	r4, r3, 24
+	cmpw	r4, r29
+	bne	restore
+	mfmsr	r4
+	xor	r4, r4, r3
+	cmpw	r4, r30
+	bne	restore
+	addi	r4, r3, 25
+	mflr	r5
+	cmpw	r4, r5
+	bne	restore
+	addi	r4, r3, 26
+	mfctr	r5
+	cmpw	r4, r5
+	bne	restore
+	addi	r4, r3, 27
+	mfxer	r5
+	cmpw	r4, r5
+	bne	restore
+	addi	r4, r3, 28
+	cmpw	r4, r0
+	bne	restore
+	cmpw	r31, r1
+	bne	restore
+#if 0
+	/* This is only valid if we use the EABI */
+	lis	r4, _SDA2_BASE_ at h
+	ori	r4, r4, _SDA2_BASE_ at l
+	cmpw	r4, r2
+	bne	restore
+#endif
+	mtcr	r29
+	addi	r5, r3, 1
+	b	check
+
+	/* Restore */
+restore:
+	lwz	r31, GPR31_OFFSET(r1)
+	lwz	r30, GPR30_OFFSET(r1)
+	lwz	r29, GPR29_OFFSET(r1)
+	lwz	r28, GPR28_OFFSET(r1)
+	lwz	r27, GPR27_OFFSET(r1)
+	lwz	r26, GPR26_OFFSET(r1)
+	lwz	r25, GPR25_OFFSET(r1)
+	lwz	r24, GPR24_OFFSET(r1)
+	lwz	r23, GPR23_OFFSET(r1)
+	lwz	r22, GPR22_OFFSET(r1)
+	lwz	r21, GPR21_OFFSET(r1)
+	lwz	r20, GPR20_OFFSET(r1)
+	lwz	r19, GPR19_OFFSET(r1)
+	lwz	r18, GPR18_OFFSET(r1)
+	lwz	r17, GPR17_OFFSET(r1)
+	lwz	r16, GPR16_OFFSET(r1)
+	lwz	r15, GPR15_OFFSET(r1)
+	lwz	r14, GPR14_OFFSET(r1)
+	lwz	r4, CR_OFFSET(r1)
+	mtcr	r4
+	lwz	r4, LR_OFFSET(r1)
+	mtlr	r4
+	addi	r1, r1, FRAME_SIZE
+	blr
diff --git a/cpukit/score/cpu/powerpc/ppc-context-volatile-clobber.S b/cpukit/score/cpu/powerpc/ppc-context-volatile-clobber.S
new file mode 100644
index 0000000..f4a5721
--- /dev/null
+++ b/cpukit/score/cpu/powerpc/ppc-context-volatile-clobber.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/asm.h>
+
+	.global _CPU_Context_volatile_clobber
+
+_CPU_Context_volatile_clobber:
+
+	addi	r4, r3, 10
+	rlwinm	r4, r4, 0, 20, 7
+	mfcr	r5
+	rlwinm	r5, r5, 0, 8, 19
+	or	r4, r4, r5
+	mtcr	r4
+	addi	r4, r3, 11
+	mtctr	r4
+	addi	r4, r3, 12
+	mtxer	r4
+	addi	r0, r3, 13
+	addi	r4, r3, 1
+	addi	r5, r3, 2
+	addi	r6, r3, 3
+	addi	r7, r3, 4
+	addi	r8, r3, 5
+	addi	r9, r3, 6
+	addi	r10, r3, 7
+	addi	r11, r3, 8
+	addi	r12, r3, 9
+	blr
diff --git a/cpukit/score/cpu/powerpc/rtems/score/cpu.h b/cpukit/score/cpu/powerpc/rtems/score/cpu.h
index 37d8c34..080c5bb 100644
--- a/cpukit/score/cpu/powerpc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/powerpc/rtems/score/cpu.h
@@ -992,6 +992,10 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+void _CPU_Context_volatile_clobber( uintptr_t pattern );
+
+void _CPU_Context_validate( uintptr_t pattern );
+
 typedef struct {
   uint32_t EXC_SRR0;
   uint32_t EXC_SRR1;
diff --git a/cpukit/score/cpu/sh/rtems/score/cpu.h b/cpukit/score/cpu/sh/rtems/score/cpu.h
index f5ad90c..d4412f6 100644
--- a/cpukit/score/cpu/sh/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sh/rtems/score/cpu.h
@@ -886,6 +886,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /* FIXME */
 typedef CPU_Interrupt_frame CPU_Exception_frame;
 
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index b95d411..2209c89 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -1227,6 +1227,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 typedef struct {
   uint32_t trap;
   CPU_Interrupt_frame *isf;
diff --git a/cpukit/score/cpu/sparc64/rtems/score/cpu.h b/cpukit/score/cpu/sparc64/rtems/score/cpu.h
index 36c7144..314143b 100644
--- a/cpukit/score/cpu/sparc64/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc64/rtems/score/cpu.h
@@ -1028,6 +1028,18 @@ void _CPU_Context_restore_fp(
   Context_Control_fp **fp_context_ptr
 );
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /* FIXME */
 typedef CPU_Interrupt_frame CPU_Exception_frame;
 
diff --git a/cpukit/score/cpu/v850/rtems/score/cpu.h b/cpukit/score/cpu/v850/rtems/score/cpu.h
index c0b6f9e..12c824b 100644
--- a/cpukit/score/cpu/v850/rtems/score/cpu.h
+++ b/cpukit/score/cpu/v850/rtems/score/cpu.h
@@ -1128,6 +1128,18 @@ void _CPU_Context_restore_fp(
 );
 #endif
 
+static inline void _CPU_Context_volatile_clobber( uintptr_t pattern )
+{
+  /* TODO */
+}
+
+static inline void _CPU_Context_validate( uintptr_t pattern )
+{
+  while (1) {
+    /* TODO */
+  }
+}
+
 /** @} */
 
 /* FIXME */
diff --git a/doc/porting/miscellaneous.t b/doc/porting/miscellaneous.t
index e93d5e6..cba85f7 100644
--- a/doc/porting/miscellaneous.t
+++ b/doc/porting/miscellaneous.t
@@ -18,6 +18,31 @@ void _CPU_Fatal_halt(
 );
 @end example
 
+ at section CPU Context Validation
+
+The test case @code{sptests/spcontext01} ensures that the context switching and
+interrupt processing works.  This test uses two support functions provided by
+the CPU port.  These two functions are only used for this test and have no
+other purpose.
+
+ at example
+void _CPU_Context_volatile_clobber( uintptr_t pattern );
+
+void _CPU_Context_validate( uintptr_t pattern );
+ at end example
+
+The @code{_CPU_Context_volatile_clobber()} function clobbers all volatile
+registers with values derived from the pattern parameter.  This makes sure that
+the interrupt prologue code restores all volatile registers of the interrupted
+context.
+
+The @code{_CPU_Context_validate()} function initializes and validates the CPU
+context with values derived from the pattern parameter.  This function will not
+return if the CPU context remains consistent.  In case this function returns
+the CPU port is broken.  The test uses two threads which concurrently validate
+the CPU context with a different patterns for each thread.  This ensures that
+the context switching code works.
+
 @section Processor Endianness
 
 Endianness refers to the order in which numeric values are stored in
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index c9d20dd..4b0fff6 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -30,6 +30,7 @@ SUBDIRS = \
     spcbssched01 spcbssched02 spcbssched03 spqreslib sptimespec01 \
     spatomic01 spatomic02 spatomic03 spatomic04 spatomic05 \
     spatomic06 spatomic07
+SUBDIRS += spcontext01
 SUBDIRS += spfatal26
 SUBDIRS += speventtransient01
 SUBDIRS += speventsystem01
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index a43a1ad..ba3aa92 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -27,6 +27,7 @@ AC_CHECK_SIZEOF([time_t])
 
 # Explicitly list all Makefiles here
 AC_CONFIG_FILES([Makefile
+spcontext01/Makefile
 spfatal26/Makefile
 spinternalerror02/Makefile
 spinternalerror01/Makefile
diff --git a/testsuites/sptests/spcontext01/Makefile.am b/testsuites/sptests/spcontext01/Makefile.am
new file mode 100644
index 0000000..b1c7de2
--- /dev/null
+++ b/testsuites/sptests/spcontext01/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = spcontext01
+spcontext01_SOURCES = init.c
+
+dist_rtems_tests_DATA = spcontext01.scn spcontext01.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(spcontext01_OBJECTS)
+LINK_LIBS = $(spcontext01_LDLIBS)
+
+spcontext01$(EXEEXT): $(spcontext01_OBJECTS) $(spcontext01_DEPENDENCIES)
+	@rm -f spcontext01$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/sptests/spcontext01/init.c b/testsuites/sptests/spcontext01/init.c
new file mode 100644
index 0000000..f9c1803
--- /dev/null
+++ b/testsuites/sptests/spcontext01/init.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "tmacros.h"
+
+#define ITERATION_COUNT 2000
+
+#define PRIORITY_HIGH 2
+
+#define PRIORITY_LOW 3
+
+#define FINISH_EVENT RTEMS_EVENT_0
+
+typedef struct {
+  rtems_id control_task;
+  rtems_id validate_tasks[2];
+  size_t task_index;
+  int iteration_counter;
+} test_context;
+
+static test_context test_instance;
+
+static void validate_task(rtems_task_argument arg)
+{
+  _CPU_Context_validate(arg);
+  rtems_test_assert(0);
+}
+
+static void start_validate_task(
+  rtems_id *id,
+  uintptr_t pattern,
+  rtems_task_priority priority
+)
+{
+  rtems_status_code sc;
+
+  sc = rtems_task_create(
+    rtems_build_name('V', 'A', 'L', 'I'),
+    priority,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    id
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_start(*id, validate_task, pattern);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void reset_timer_or_finish(test_context *self, rtems_id timer)
+{
+  rtems_status_code sc;
+  int i = self->iteration_counter;
+
+  if (i < ITERATION_COUNT) {
+    self->iteration_counter = i + 1;
+
+    sc = rtems_timer_reset(timer);
+    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  } else {
+    sc = rtems_event_send(self->control_task, FINISH_EVENT);
+    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  }
+}
+
+static void switch_priorities(test_context *self)
+{
+  rtems_status_code sc;
+  size_t index = self->task_index;
+  size_t next = (index + 1) & 0x1;
+  size_t task_high = index;
+  size_t task_low = next;
+  rtems_task_priority priority;
+
+  self->task_index = next;
+
+  sc = rtems_task_set_priority(
+    self->validate_tasks[task_high],
+    PRIORITY_HIGH,
+    &priority
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_set_priority(
+    self->validate_tasks[task_low],
+    PRIORITY_LOW,
+    &priority
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void clobber_and_switch_timer(rtems_id timer, void *arg)
+{
+  uintptr_t pattern = (uintptr_t) 0xffffffffffffffffU;
+  test_context *self = arg;
+
+  reset_timer_or_finish(self, timer);
+  switch_priorities(self);
+
+  _CPU_Context_volatile_clobber(pattern);
+}
+
+static void start_timer(test_context *self)
+{
+  rtems_status_code sc;
+  rtems_id timer;
+
+  sc = rtems_timer_create(rtems_build_name('C', 'L', 'S', 'W'), &timer);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_timer_fire_after(timer, 2, clobber_and_switch_timer, self);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void wait_for_finish(void)
+{
+  rtems_status_code sc;
+  rtems_event_set out;
+
+  sc = rtems_event_receive(
+    FINISH_EVENT,
+    RTEMS_WAIT | RTEMS_EVENT_ALL,
+    RTEMS_NO_TIMEOUT,
+    &out
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  rtems_test_assert(out == FINISH_EVENT);
+}
+
+static void test(test_context *self)
+{
+  uintptr_t pattern_0 = (uintptr_t) 0xaaaaaaaaaaaaaaaaU;
+  uintptr_t pattern_1 = (uintptr_t) 0x5555555555555555U;
+
+  memset(self, 0, sizeof(*self));
+
+  self->control_task = rtems_task_self();
+
+  start_validate_task(&self->validate_tasks[0], pattern_0, PRIORITY_LOW);
+  start_validate_task(&self->validate_tasks[1], pattern_1, PRIORITY_HIGH);
+  start_timer(self);
+  wait_for_finish();
+}
+
+static void Init(rtems_task_argument arg)
+{
+  test_context *self = &test_instance;
+
+  puts("\n\n*** TEST SPCONTEXT 1 ***");
+
+  test(self);
+
+  puts("*** END OF TEST SPCONTEXT 1 ***");
+
+  rtems_test_exit(0);
+}
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 1000
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+
+#define CONFIGURE_MAXIMUM_TASKS 3
+#define CONFIGURE_MAXIMUM_TIMERS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spcontext01/spcontext01.doc b/testsuites/sptests/spcontext01/spcontext01.doc
new file mode 100644
index 0000000..2c2c4cf
--- /dev/null
+++ b/testsuites/sptests/spcontext01/spcontext01.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: spcontext01
+
+directives:
+
+  TBD
+
+concepts:
+
+  - Ensure the context switching and interrupt processing works
diff --git a/testsuites/sptests/spcontext01/spcontext01.scn b/testsuites/sptests/spcontext01/spcontext01.scn
new file mode 100644
index 0000000..b7b823b
--- /dev/null
+++ b/testsuites/sptests/spcontext01/spcontext01.scn
@@ -0,0 +1,2 @@
+*** TEST SPCONTEXT 1 ***
+*** END OF TEST SPCONTEXT 1 ***
-- 
1.7.7




More information about the devel mailing list