From 8cab7d96ec46edb803583a41bb1c906fc76bcd18 Mon Sep 17 00:00:00 2001 From: rtel Date: Tue, 4 Dec 2018 01:23:41 +0000 Subject: [PATCH] Update RISC-V port to use a separate interrupt stack. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2598 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Source/portable/GCC/RISC-V-RV32/port.c | 56 ++++++++++++++----- .../Source/portable/GCC/RISC-V-RV32/portASM.S | 9 +-- .../portable/GCC/RISC-V-RV32/portmacro.h | 37 ++++++++++-- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/port.c b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/port.c index 28b4b0477..139d1c833 100644 --- a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/port.c +++ b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/port.c @@ -34,6 +34,16 @@ #include "task.h" #include "portmacro.h" +#ifdef configISR_STACK_SIZE + /* The stack used by interrupt service routines. */ + static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 }; + const StackType_t * const xISRStackTop = &( xISRStack[ ( configISR_STACK_SIZE & ~portBYTE_ALIGNMENT_MASK ) - 1 ] ); +#else +#warning What should _sp be named? + extern const uint32_t _sp[]; + const uint32_t xISRStackTop = ( uint32_t ) _sp; +#endif + /* * Setup the timer to generate the tick interrupts. The implementation in this * file is weak to allow application writers to change the timer used to @@ -54,6 +64,30 @@ const uint64_t *pullNextTime = &ullNextTime; const uint32_t ulTimerIncrementsForOneTick = ( uint32_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */ volatile uint64_t * const pullMachineTimerCompareRegister = ( volatile uint64_t * const ) ( configCLINT_BASE_ADDRESS + 0x4000 ); +/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task +stack checking. A problem in the ISR stack will trigger an assert, not call the +stack overflow hook function (because the stack overflow hook is specific to a +task stack, not the ISR stack). */ +#if( configCHECK_FOR_STACK_OVERFLOW > 2 ) + #warning This path not tested, or even compiled yet. + /* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for + the task stacks, and so will legitimately appear in many positions within + the ISR stack. */ + #define portISR_STACK_FILL_BYTE 0xee + + static const uint8_t ucExpectedStackBytes[] = { + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ + portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \ + + #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) ) +#else + /* Define the function away. */ + #define portCHECK_ISR_STACK() +#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */ + /*-----------------------------------------------------------*/ void prvTaskExitError( void ) @@ -194,22 +228,11 @@ volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configCLI /* Prepare the time to use after the next tick interrupt. */ ullNextTime += ( uint64_t ) ulTimerIncrementsForOneTick; - /* Enable timer interrupt */ + /* Enable timer interrupt. */ __asm volatile( "csrs mie, %0" :: "r"(0x80) ); /* 1<<7 for timer interrupt. */ } /*-----------------------------------------------------------*/ -void Software_IRQHandler( void ) -{ -volatile uint32_t * const ulSoftInterrupt = ( uint32_t * ) configCLINT_BASE_ADDRESS; - - vTaskSwitchContext(); - - /* Clear software interrupt. */ - *( ( uint32_t * ) configCLINT_BASE_ADDRESS ) &= 0x08UL; -} -/*-----------------------------------------------------------*/ - BaseType_t xPortStartScheduler( void ) { extern void xPortStartFirstTask( void ); @@ -218,10 +241,15 @@ extern void xPortStartFirstTask( void ); { volatile uint32_t mtvec = 0; - /* Check the least significant two bits of mtvec are 00 - indicating single - vector mode. */ + /* Check the least significant two bits of mtvec are 00 - indicating + single vector mode. */ __asm volatile( "csrr %0, mtvec" : "=r"( mtvec ) ); configASSERT( ( mtvec & 0x03UL ) == 0 ); + + /* Check alignment of the interrupt stack - which is the same as the + stack that was being used by main() prior to the scheduler being + started. */ + configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 ); } #endif diff --git a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portASM.S b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portASM.S index 5f6c3a10e..e9ba83856 100644 --- a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portASM.S +++ b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portASM.S @@ -49,7 +49,7 @@ .extern pullMachineTimerCompareRegister .extern pullNextTime .extern ulTimerIncrementsForOneTick - +.extern xISRStackTop /*-----------------------------------------------------------*/ @@ -136,14 +136,13 @@ vPortTrapHandler: csrr a0, mcause csrr a1, mepc - mv a2, sp test_if_environment_call: li t0, 11 /* 11 == environment call when using qemu. */ bne a0, t0, test_if_timer addi a1, a1, 4 /* Synchronous so return to the instruction after the environment call. */ sw a1, 0( sp ) /* Save updated exception return address. */ -/*_RB_ Does stack need aligning here? */ + lw sp, xISRStackTop /* Switch to ISR stack before function call. */ jal vTaskSwitchContext j processed_source @@ -167,13 +166,15 @@ test_if_timer: add t6, t3, t5 /* Add overflow to high word of ullNextTime. */ sw t4, 0(t1) /* Store new low word of ullNextTime. */ sw t6, 4(t1) /* Store new high word of ullNextTime. */ + lw sp, xISRStackTop /* Switch to ISR stack before function call. */ jal xTaskIncrementTick beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */ jal vTaskSwitchContext j processed_source as_yet_unhandled: - j as_yet_unhandled /* External interrupt? */ +// ebreak /* External interrupt? */ + j as_yet_unhandled processed_source: lw sp, pxCurrentTCB /* Load pxCurrentTCB. */ diff --git a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portmacro.h b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portmacro.h index 72b8b8392..c0c1b6b09 100644 --- a/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/RISC-V-RV32/portmacro.h @@ -70,8 +70,9 @@ not need to be guarded with a critical section. */ /* Scheduler utilities. */ -#define portYIELD() __asm volatile( "ecall" ); // software interrupt alternative *( ( uint32_t * ) configCLINT_BASE_ADDRESS ) |= 0x08UL -#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYield() +extern void vTaskSwitchContext( void ); +#define portYIELD() __asm volatile( "ecall" ); +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vTaskSwitchContext() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ @@ -84,12 +85,37 @@ extern void vTaskEnterCritical( void ); extern void vTaskExitCritical( void ); #define portSET_INTERRUPT_MASK_FROM_ISR() 0 -#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) -#define portDISABLE_INTERRUPTS() __asm volatile( "csrc mstatus, 8" ) -#define portENABLE_INTERRUPTS() __asm volatile( "csrs mstatus, 8" ) +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#define portDISABLE_INTERRUPTS() __asm volatile( "csrc mstatus, 8" ); __asm volatile( "fence" ) +#define portENABLE_INTERRUPTS() __asm volatile( "csrs mstatus, 8" ); __asm volatile( "fence" ) #define portENTER_CRITICAL() vTaskEnterCritical() #define portEXIT_CRITICAL() vTaskExitCritical() +/*-----------------------------------------------------------*/ + +/* Architecture specific optimisations. */ +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 ) + + /* Check the configuration. */ + #if( configMAX_PRIORITIES > 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + /*-----------------------------------------------------------*/ + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - __builtin_clz( uxReadyPriorities ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. These are @@ -107,7 +133,6 @@ not necessary for to use this port. They are defined so the common demo files #ifndef portFORCE_INLINE #define portFORCE_INLINE inline __attribute__(( always_inline)) #endif -portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) {} #ifdef __cplusplus } -- 2.39.5