#include "task.h"\r
#include "portmacro.h"\r
\r
+#ifdef configISR_STACK_SIZE\r
+ /* The stack used by interrupt service routines. */\r
+ static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 };\r
+ const StackType_t * const xISRStackTop = &( xISRStack[ ( configISR_STACK_SIZE & ~portBYTE_ALIGNMENT_MASK ) - 1 ] );\r
+#else\r
+#warning What should _sp be named?\r
+ extern const uint32_t _sp[];\r
+ const uint32_t xISRStackTop = ( uint32_t ) _sp;\r
+#endif\r
+\r
/*\r
* Setup the timer to generate the tick interrupts. The implementation in this\r
* file is weak to allow application writers to change the timer used to\r
const uint32_t ulTimerIncrementsForOneTick = ( uint32_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */\r
volatile uint64_t * const pullMachineTimerCompareRegister = ( volatile uint64_t * const ) ( configCLINT_BASE_ADDRESS + 0x4000 );\r
\r
+/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task\r
+stack checking. A problem in the ISR stack will trigger an assert, not call the\r
+stack overflow hook function (because the stack overflow hook is specific to a\r
+task stack, not the ISR stack). */\r
+#if( configCHECK_FOR_STACK_OVERFLOW > 2 )\r
+ #warning This path not tested, or even compiled yet.\r
+ /* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for\r
+ the task stacks, and so will legitimately appear in many positions within\r
+ the ISR stack. */\r
+ #define portISR_STACK_FILL_BYTE 0xee\r
+\r
+ static const uint8_t ucExpectedStackBytes[] = {\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \\r
+ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \\r
+\r
+ #define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )\r
+#else\r
+ /* Define the function away. */\r
+ #define portCHECK_ISR_STACK()\r
+#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */\r
+\r
/*-----------------------------------------------------------*/\r
\r
void prvTaskExitError( void )\r
/* Prepare the time to use after the next tick interrupt. */\r
ullNextTime += ( uint64_t ) ulTimerIncrementsForOneTick;\r
\r
- /* Enable timer interrupt */\r
+ /* Enable timer interrupt. */\r
__asm volatile( "csrs mie, %0" :: "r"(0x80) ); /* 1<<7 for timer interrupt. */\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void Software_IRQHandler( void )\r
-{\r
-volatile uint32_t * const ulSoftInterrupt = ( uint32_t * ) configCLINT_BASE_ADDRESS;\r
-\r
- vTaskSwitchContext();\r
-\r
- /* Clear software interrupt. */\r
- *( ( uint32_t * ) configCLINT_BASE_ADDRESS ) &= 0x08UL;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
BaseType_t xPortStartScheduler( void )\r
{\r
extern void xPortStartFirstTask( void );\r
{\r
volatile uint32_t mtvec = 0;\r
\r
- /* Check the least significant two bits of mtvec are 00 - indicating single\r
- vector mode. */\r
+ /* Check the least significant two bits of mtvec are 00 - indicating\r
+ single vector mode. */\r
__asm volatile( "csrr %0, mtvec" : "=r"( mtvec ) );\r
configASSERT( ( mtvec & 0x03UL ) == 0 );\r
+\r
+ /* Check alignment of the interrupt stack - which is the same as the\r
+ stack that was being used by main() prior to the scheduler being\r
+ started. */\r
+ configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );\r
}\r
#endif\r
\r
.extern pullMachineTimerCompareRegister\r
.extern pullNextTime\r
.extern ulTimerIncrementsForOneTick\r
-\r
+.extern xISRStackTop\r
\r
/*-----------------------------------------------------------*/\r
\r
\r
csrr a0, mcause\r
csrr a1, mepc\r
- mv a2, sp\r
\r
test_if_environment_call:\r
li t0, 11 /* 11 == environment call when using qemu. */\r
bne a0, t0, test_if_timer\r
addi a1, a1, 4 /* Synchronous so return to the instruction after the environment call. */\r
sw a1, 0( sp ) /* Save updated exception return address. */\r
-/*_RB_ Does stack need aligning here? */\r
+ lw sp, xISRStackTop /* Switch to ISR stack before function call. */\r
jal vTaskSwitchContext\r
j processed_source\r
\r
add t6, t3, t5 /* Add overflow to high word of ullNextTime. */\r
sw t4, 0(t1) /* Store new low word of ullNextTime. */\r
sw t6, 4(t1) /* Store new high word of ullNextTime. */\r
+ lw sp, xISRStackTop /* Switch to ISR stack before function call. */\r
jal xTaskIncrementTick\r
beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */\r
jal vTaskSwitchContext\r
j processed_source\r
\r
as_yet_unhandled:\r
- j as_yet_unhandled /* External interrupt? */\r
+// ebreak /* External interrupt? */\r
+ j as_yet_unhandled\r
\r
processed_source:\r
lw sp, pxCurrentTCB /* Load pxCurrentTCB. */\r
\r
\r
/* Scheduler utilities. */\r
-#define portYIELD() __asm volatile( "ecall" ); // software interrupt alternative *( ( uint32_t * ) configCLINT_BASE_ADDRESS ) |= 0x08UL\r
-#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYield()\r
+extern void vTaskSwitchContext( void );\r
+#define portYIELD() __asm volatile( "ecall" );\r
+#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vTaskSwitchContext()\r
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )\r
/*-----------------------------------------------------------*/\r
\r
extern void vTaskExitCritical( void );\r
\r
#define portSET_INTERRUPT_MASK_FROM_ISR() 0\r
-#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue )\r
-#define portDISABLE_INTERRUPTS() __asm volatile( "csrc mstatus, 8" )\r
-#define portENABLE_INTERRUPTS() __asm volatile( "csrs mstatus, 8" )\r
+#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue\r
+#define portDISABLE_INTERRUPTS() __asm volatile( "csrc mstatus, 8" ); __asm volatile( "fence" )\r
+#define portENABLE_INTERRUPTS() __asm volatile( "csrs mstatus, 8" ); __asm volatile( "fence" )\r
#define portENTER_CRITICAL() vTaskEnterCritical()\r
#define portEXIT_CRITICAL() vTaskExitCritical()\r
\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Architecture specific optimisations. */\r
+#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION\r
+ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1\r
+#endif\r
+\r
+#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )\r
+\r
+ /* Check the configuration. */\r
+ #if( configMAX_PRIORITIES > 32 )\r
+ #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.\r
+ #endif\r
+\r
+ /* Store/clear the ready priorities in a bit map. */\r
+ #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )\r
+ #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )\r
+\r
+ /*-----------------------------------------------------------*/\r
+\r
+ #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - __builtin_clz( uxReadyPriorities ) )\r
+\r
+#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */\r
+\r
+\r
/*-----------------------------------------------------------*/\r
\r
/* Task function macros as described on the FreeRTOS.org WEB site. These are\r
#ifndef portFORCE_INLINE\r
#define portFORCE_INLINE inline __attribute__(( always_inline))\r
#endif\r
-portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) {}\r
\r
#ifdef __cplusplus\r
}\r