From 63f86fc7a2f6426fd73823e4ded6eed92c822642 Mon Sep 17 00:00:00 2001 From: Gavin Lambert Date: Wed, 3 Aug 2022 18:31:18 +1200 Subject: [PATCH] Implement MicroBlazeV9 stack protection (#523) * Implement stack protection for MicroBlaze (without MPU wrappers) --- portable/GCC/MicroBlazeV9/port.c | 12 +++++ portable/GCC/MicroBlazeV9/portasm.S | 69 ++++++++++++++++++++++----- portable/GCC/MicroBlazeV9/portmacro.h | 5 ++ 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/portable/GCC/MicroBlazeV9/port.c b/portable/GCC/MicroBlazeV9/port.c index 8e70db9a2..5f0e2616d 100644 --- a/portable/GCC/MicroBlazeV9/port.c +++ b/portable/GCC/MicroBlazeV9/port.c @@ -105,7 +105,11 @@ static XIntc xInterruptControllerInstance; * * 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 @@ extern void _start1( void ); *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 6bea21f98..937b680d8 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 @@ back into the caller stack. */ #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 @@ back into the caller stack. */ 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 @@ back into the caller stack. */ 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 @@ _interrupt_handler: /* 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 @@ VPortYieldASM: /* 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 17166b7cb..3df7d5c8e 100644 --- a/portable/GCC/MicroBlazeV9/portmacro.h +++ b/portable/GCC/MicroBlazeV9/portmacro.h @@ -152,6 +152,11 @@ extern volatile uint32_t ulTaskSwitchRequested; #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 )