Implement MicroBlazeV9 stack protection (#523)

* Implement stack protection for MicroBlaze (without MPU wrappers)
diff --git a/portable/GCC/MicroBlazeV9/port.c b/portable/GCC/MicroBlazeV9/port.c
index 8e70db9..5f0e261 100644
--- a/portable/GCC/MicroBlazeV9/port.c
+++ b/portable/GCC/MicroBlazeV9/port.c
@@ -105,7 +105,11 @@
  *

  * See the portable.h header file.

  */

+#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )

+StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters )

+#else

 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )

+#endif

 {

 extern void *_SDA2_BASE_, *_SDA_BASE_;

 const uint32_t ulR2 = ( uint32_t ) &_SDA2_BASE_;

@@ -122,6 +126,14 @@
 	*pxTopOfStack = ( StackType_t ) 0x00000000;

 	pxTopOfStack--;

 

+	#if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )

+		/* Store the stack limits. */

+		*pxTopOfStack = (StackType_t) (pxTopOfStack + 3);

+		pxTopOfStack--;

+		*pxTopOfStack = (StackType_t) pxEndOfStack;

+		pxTopOfStack--;

+	#endif

+

 	#if( XPAR_MICROBLAZE_USE_FPU != 0 )

 		/* The FSR value placed in the initial task context is just 0. */

 		*pxTopOfStack = portINITIAL_FSR;

diff --git a/portable/GCC/MicroBlazeV9/portasm.S b/portable/GCC/MicroBlazeV9/portasm.S
index 6bea21f..937b680 100644
--- a/portable/GCC/MicroBlazeV9/portasm.S
+++ b/portable/GCC/MicroBlazeV9/portasm.S
@@ -33,16 +33,6 @@
 #include "microblaze_exceptions_g.h"

 #include "xparameters.h"

 

-/* The context is oversized to allow functions called from the ISR to write

-back into the caller stack. */

-#if( XPAR_MICROBLAZE_USE_FPU != 0 )

-	#define portCONTEXT_SIZE 136

-	#define portMINUS_CONTEXT_SIZE -136

-#else

-	#define portCONTEXT_SIZE 132

-	#define portMINUS_CONTEXT_SIZE -132

-#endif

-

 /* Offsets from the stack pointer at which saved registers are placed. */

 #define portR31_OFFSET	4

 #define portR30_OFFSET	8

@@ -76,7 +66,31 @@
 #define portR2_OFFSET	120

 #define portCRITICAL_NESTING_OFFSET 124

 #define portMSR_OFFSET 128

-#define portFSR_OFFSET 132

+

+#if( XPAR_MICROBLAZE_USE_FPU != 0 )

+	#define portFSR_OFFSET 132

+	#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+		#define portSLR_OFFSET 136

+		#define portSHR_OFFSET 140

+

+		#define portCONTEXT_SIZE 144

+		#define portMINUS_CONTEXT_SIZE -144

+	#else

+		#define portCONTEXT_SIZE 136

+		#define portMINUS_CONTEXT_SIZE -136

+	#endif

+#else

+	#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+		#define portSLR_OFFSET 132

+		#define portSHR_OFFSET 136

+

+		#define portCONTEXT_SIZE 140

+		#define portMINUS_CONTEXT_SIZE -140

+	#else

+		#define portCONTEXT_SIZE 132

+		#define portMINUS_CONTEXT_SIZE -132

+	#endif

+#endif

 

 	.extern pxCurrentTCB

 	.extern XIntc_DeviceInterruptHandler

@@ -144,6 +158,14 @@
 		swi r18, r1, portFSR_OFFSET

 	#endif

 

+#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+	/* Save the stack limits */

+	mfs r18, rslr

+	swi r18, r1, portSLR_OFFSET

+	mfs r18, rshr

+	swi r18, r1, portSHR_OFFSET

+#endif

+

 	/* Save the top of stack value to the TCB. */

 	lwi r3, r0, pxCurrentTCB

 	sw	r1, r0, r3

@@ -156,6 +178,17 @@
 	lwi r18, r0, pxCurrentTCB

 	lw	r1, r0, r18

 

+#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+	/* Restore the stack limits -- must not load from r1 (Stack Pointer)

+	because if the address of load or store instruction is out of range,

+	it will trigger Stack Protection Violation exception. */

+	or	r18, r0, r1

+	lwi	r12, r18, portSLR_OFFSET

+	mts	rslr, r12

+	lwi	r12, r18, portSHR_OFFSET

+	mts	rshr, r12

+#endif

+

 	/* Restore the general registers. */

 	lwi r31, r1, portR31_OFFSET

 	lwi r30, r1, portR30_OFFSET

@@ -252,6 +285,13 @@
 	/* Switch to the ISR stack. */

 	lwi r1, r0, pulISRStack

 

+#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+	ori r18, r0, _stack_end

+	mts rslr, r18

+	ori r18, r0, _stack

+	mts rshr, r18

+#endif

+

 	/* The parameter to the interrupt handler. */

 	ori r5, r0, configINTERRUPT_CONTROLLER_TO_USE

 

@@ -296,6 +336,13 @@
 	/* Switch to use the ISR stack. */

 	lwi r1, r0, pulISRStack

 

+#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+	ori r18, r0, _stack_end

+	mts rslr, r18

+	ori r18, r0, _stack

+	mts rshr, r18

+#endif

+

 	/* Select the next task to execute. */

 	bralid r15, vTaskSwitchContext

 	or r0, r0, r0

diff --git a/portable/GCC/MicroBlazeV9/portmacro.h b/portable/GCC/MicroBlazeV9/portmacro.h
index 17166b7..3df7d5c 100644
--- a/portable/GCC/MicroBlazeV9/portmacro.h
+++ b/portable/GCC/MicroBlazeV9/portmacro.h
@@ -152,6 +152,11 @@
 #define portNOP()					asm volatile ( "NOP" )

 /*-----------------------------------------------------------*/

 

+#if( XPAR_MICROBLAZE_USE_STACK_PROTECTION )

+#define portHAS_STACK_OVERFLOW_CHECKING	1

+#endif

+/*-----------------------------------------------------------*/

+

 /* Task function macros as described on the FreeRTOS.org WEB site. */

 #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )

 #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )