| /* |
| * FreeRTOS Kernel <DEVELOPMENT BRANCH> |
| * Copyright (C) 2015-2019 Cadence Design Systems, Inc. |
| * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| * |
| * SPDX-License-Identifier: MIT |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of |
| * this software and associated documentation files (the "Software"), to deal in |
| * the Software without restriction, including without limitation the rights to |
| * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| * the Software, and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
| * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
| * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * https://www.FreeRTOS.org |
| * https://github.com/FreeRTOS |
| * |
| */ |
| |
| #include <stdlib.h> |
| #include <xtensa/config/core.h> |
| |
| #include "xtensa_rtos.h" |
| |
| #include "FreeRTOS.h" |
| #include "task.h" |
| |
| |
| /* Defined in portasm.h */ |
| extern void _frxt_tick_timer_init( void ); |
| |
| /* Defined in xtensa_context.S */ |
| extern void _xt_coproc_init( void ); |
| |
| |
| /*-----------------------------------------------------------*/ |
| |
| /* We require the address of the pxCurrentTCB variable, but don't want to know |
| * any details of its type. */ |
| typedef void TCB_t; |
| extern volatile TCB_t * volatile pxCurrentTCB; |
| |
| unsigned port_xSchedulerRunning = 0; /* Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting */ |
| unsigned port_interruptNesting = 0; /* Interrupt nesting level */ |
| |
| /*-----------------------------------------------------------*/ |
| |
| /* User exception dispatcher when exiting */ |
| void _xt_user_exit( void ); |
| |
| /* |
| * Stack initialization |
| */ |
| #if portUSING_MPU_WRAPPERS |
| StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, |
| TaskFunction_t pxCode, |
| void * pvParameters, |
| BaseType_t xRunPrivileged ) |
| #else |
| StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, |
| TaskFunction_t pxCode, |
| void * pvParameters ) |
| #endif |
| { |
| StackType_t * sp; |
| StackType_t * tp; |
| XtExcFrame * frame; |
| |
| #if XCHAL_CP_NUM > 0 |
| uint32_t * p; |
| #endif |
| |
| /* Create interrupt stack frame aligned to 16 byte boundary */ |
| sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - XT_STK_FRMSZ ) & ~0xf ); |
| |
| /* Clear the entire frame (do not use memset() because we don't depend on C library) */ |
| for( tp = sp; tp <= pxTopOfStack; ++tp ) |
| { |
| *tp = 0; |
| } |
| |
| frame = ( XtExcFrame * ) sp; |
| |
| /* Explicitly initialize certain saved registers */ |
| frame->pc = ( UBaseType_t ) pxCode; /* task entrypoint */ |
| frame->a0 = 0; /* to terminate GDB backtrace */ |
| frame->a1 = ( UBaseType_t ) sp + XT_STK_FRMSZ; /* physical top of stack frame */ |
| frame->exit = ( UBaseType_t ) _xt_user_exit; /* user exception exit dispatcher */ |
| |
| /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ |
| /* Also set entry point argument parameter. */ |
| #ifdef __XTENSA_CALL0_ABI__ |
| frame->a2 = ( UBaseType_t ) pvParameters; |
| frame->ps = PS_UM | PS_EXCM; |
| #else |
| /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ |
| frame->a6 = ( UBaseType_t ) pvParameters; |
| frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 ); |
| #endif |
| |
| #ifdef XT_USE_SWPRI |
| /* Set the initial virtual priority mask value to all 1's. */ |
| frame->vpri = 0xFFFFFFFF; |
| #endif |
| |
| #if XCHAL_CP_NUM > 0 |
| /* Init the coprocessor save area (see xtensa_context.h) */ |
| |
| /* No access to TCB here, so derive indirectly. Stack growth is top to bottom. |
| * //p = (uint32_t *) xMPUSettings->coproc_area; |
| */ |
| p = ( uint32_t * ) ( ( ( uint32_t ) pxTopOfStack - XT_CP_SIZE ) & ~0xf ); |
| configASSERT( ( uint32_t ) p >= frame->a1 ); |
| p[ 0 ] = 0; |
| p[ 1 ] = 0; |
| p[ 2 ] = ( ( ( uint32_t ) p ) + 12 + XCHAL_TOTAL_SA_ALIGN - 1 ) & -XCHAL_TOTAL_SA_ALIGN; |
| #endif |
| |
| return sp; |
| } |
| |
| /*-----------------------------------------------------------*/ |
| |
| void vPortEndScheduler( void ) |
| { |
| /* It is unlikely that the Xtensa port will get stopped. If required simply |
| * disable the tick interrupt here. */ |
| } |
| |
| /*-----------------------------------------------------------*/ |
| |
| BaseType_t xPortStartScheduler( void ) |
| { |
| /* Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored */ |
| |
| #if XCHAL_CP_NUM > 0 |
| /* Initialize co-processor management for tasks. Leave CPENABLE alone. */ |
| _xt_coproc_init(); |
| #endif |
| |
| /* Init the tick divisor value */ |
| _xt_tick_divisor_init(); |
| |
| /* Setup the hardware to generate the tick. */ |
| _frxt_tick_timer_init(); |
| |
| #if XT_USE_THREAD_SAFE_CLIB |
| /* Init C library */ |
| vPortClibInit(); |
| #endif |
| |
| port_xSchedulerRunning = 1; |
| |
| /* Cannot be directly called from C; never returns */ |
| __asm__ volatile ( "call0 _frxt_dispatch\n" ); |
| |
| /* Should not get here. */ |
| return pdTRUE; |
| } |
| /*-----------------------------------------------------------*/ |
| |
| BaseType_t xPortSysTickHandler( void ) |
| { |
| BaseType_t ret; |
| uint32_t interruptMask; |
| |
| portbenchmarkIntLatency(); |
| |
| /* Interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY must be |
| * disabled before calling xTaskIncrementTick as it access the |
| * kernel lists. */ |
| interruptMask = portSET_INTERRUPT_MASK_FROM_ISR(); |
| { |
| ret = xTaskIncrementTick(); |
| } |
| portCLEAR_INTERRUPT_MASK_FROM_ISR( interruptMask ); |
| |
| portYIELD_FROM_ISR( ret ); |
| |
| return ret; |
| } |
| /*-----------------------------------------------------------*/ |
| |
| /* |
| * Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area. |
| */ |
| #if portUSING_MPU_WRAPPERS |
| void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, |
| const struct xMEMORY_REGION * const xRegions, |
| StackType_t * pxBottomOfStack, |
| uint32_t ulStackDepth ) |
| { |
| #if XCHAL_CP_NUM > 0 |
| xMPUSettings->coproc_area = ( StackType_t * ) ( ( uint32_t ) ( pxBottomOfStack + ulStackDepth - 1 ) ); |
| xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); |
| xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - XT_CP_SIZE ) & ~0xf ); |
| |
| /* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to |
| * clear the stack area after we return. This is done in pxPortInitialiseStack(). |
| */ |
| #endif |
| } |
| #endif /* if portUSING_MPU_WRAPPERS */ |