Moved proj up
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
### Makefile to build the FreeRTOS library ###
|
||||
|
||||
# Build target (options: sim, board)
|
||||
|
||||
TARGET = sim
|
||||
SMALL =
|
||||
|
||||
# Tools
|
||||
|
||||
CC = xt-clang
|
||||
AS = xt-clang
|
||||
AR = xt-ar
|
||||
ISS = xt-run
|
||||
XT_CORE = $(patsubst %-params,%,$(notdir $(shell xt-clang --show-config=core)))
|
||||
CONFIGDIR = $(shell xt-clang --show-config=config)
|
||||
|
||||
# For platform-specific commands
|
||||
|
||||
include $(CONFIGDIR)/misc/hostenv.mk
|
||||
|
||||
# Source code and build locations
|
||||
|
||||
# Build with MPU support
|
||||
ifeq ($(MPU),1)
|
||||
MPUFLAGS = -DportUSING_MPU_WRAPPERS=1 -DportALIGN_SECTIONS
|
||||
endif
|
||||
|
||||
# Build with overlay support
|
||||
ifeq ($(OVERLAY),1)
|
||||
OVLYFLAGS = -DXT_USE_THREAD_SAFE_CLIB=1 -DXT_USE_OVLY=1
|
||||
endif
|
||||
|
||||
SRCROOT = $(subst /,$(S),$(CURDIR))
|
||||
TSTROOT = $(subst /,$(S),$(abspath $(SRCROOT)$(S)..$(S)..$(S)..$(S)..$(S)..$(S)..$(S)Demo$(S)ThirdParty$(S)Partner-Supported-Demos$(S)Cadence_Xtensa_ISS_xt-clang$(SMALL)))
|
||||
BLDROOT = $(TSTROOT)$(S)build
|
||||
BLDAUX ?=
|
||||
BLDDIR = $(BLDROOT)$(S)$(XT_CORE)$(BLDAUX)
|
||||
|
||||
FR_SRCDIR = $(abspath $(SRCROOT)$(S)..$(S)..$(S)..$(S)..$(S)..)
|
||||
FR_SRCDIR2 = $(FR_SRCDIR)$(S)portable$(S)MemMang
|
||||
ifeq ($(MPU),1)
|
||||
FR_SRCDIR3 = $(FR_SRCDIR)$(S)portable$(S)Common
|
||||
endif
|
||||
XT_SRCDIR = $(SRCROOT)
|
||||
|
||||
vpath %.c $(FR_SRCDIR) $(FR_SRCDIR2) $(FR_SRCDIR3) $(XT_SRCDIR)
|
||||
vpath %.S $(XT_SRCDIR)
|
||||
|
||||
# File lists
|
||||
# NOTE: Only heap_4.c is included in the default FreeRTOS build.
|
||||
# If you want to use another heap manager then edit this file
|
||||
# and specify the one you want.
|
||||
|
||||
FR_C_FILES = $(notdir $(wildcard $(FR_SRCDIR)/*.c)) \
|
||||
$(notdir $(wildcard $(FR_SRCDIR3)/*.c)) \
|
||||
heap_4.c
|
||||
XT_C_FILES = $(notdir $(wildcard $(XT_SRCDIR)/*.c))
|
||||
XT_S_FILES = $(notdir $(wildcard $(XT_SRCDIR)/*.S))
|
||||
|
||||
# List of all .o files that will go into the library
|
||||
|
||||
LIB_C_O = $(patsubst %.c,%.o,$(filter-out asm-offsets.c,$(XT_C_FILES) $(FR_C_FILES)))
|
||||
LIB_S_O = $(patsubst %.S,%.o,$(XT_S_FILES))
|
||||
LIB_O_LIST = $(addprefix $(BLDDIR)/,$(LIB_C_O) $(LIB_S_O))
|
||||
|
||||
# Output files
|
||||
|
||||
OSLIB = $(BLDDIR)$(S)libfreertos.a
|
||||
|
||||
# Build options
|
||||
|
||||
ifeq ($(TARGET),sim)
|
||||
DFLAGS = -DXT_SIMULATOR
|
||||
endif
|
||||
ifeq ($(TARGET),board)
|
||||
DFLAGS = -DXT_BOARD
|
||||
endif
|
||||
|
||||
IFLAGS = \
|
||||
-I$(FR_SRCDIR)$(S)include -I$(XT_SRCDIR) -I$(TSTROOT)$(S)common$(S)config_files -I$(BLDDIR)
|
||||
|
||||
CSTD = -std=c99
|
||||
ifeq ($(OVERLAY),1)
|
||||
CFLAGS = -Os -g
|
||||
else
|
||||
CFLAGS = -O2 -g
|
||||
endif
|
||||
WFLAGS = -Werror -Wall -Wextra
|
||||
CFGFLAGS ?=
|
||||
CCFLAGS = $(CSTD) $(CFGFLAGS) $(CFLAGS) $(WFLAGS) -mno-coproc -mlongcalls -ffunction-sections -mno-l32r-flix $(DFLAGS) $(MPUFLAGS) $(OVLYFLAGS)
|
||||
ASFLAGS = $(CCFLAGS)
|
||||
|
||||
# File-specific flags
|
||||
|
||||
FLAGS_xtensa_vectors_xea3 = -mtext-section-literals
|
||||
|
||||
FLAGS_mpu = -mtext-section-literals
|
||||
FLAGS_portasm = -mtext-section-literals
|
||||
FLAGS_xtensa_context = -mtext-section-literals -Wno-error
|
||||
FLAGS_xtensa_coproc_handler = -mtext-section-literals
|
||||
|
||||
# Include dependency rules (generated using -MD)
|
||||
|
||||
-include $(wildcard $(BLDDIR)/*.d)
|
||||
|
||||
# Targets
|
||||
|
||||
all : $(BLDDIR)/.mkdir $(BLDDIR)/reent.h $(OSLIB)
|
||||
|
||||
$(BLDDIR)/.mkdir :
|
||||
@$(MKPATH) $(BLDDIR)
|
||||
@echo "" > $@
|
||||
|
||||
$(BLDDIR)/reent.h : $(BLDDIR)/.mkdir
|
||||
-$(CP) $(subst /,$(S),$(CONFIGDIR))$(S)xtensa-elf$(S)include$(S)sys$(S)reent.h $(BLDDIR)$(S)reent.h
|
||||
|
||||
$(LIB_O_LIST) : $(BLDDIR)/asm-offsets.h
|
||||
|
||||
$(OSLIB) : $(LIB_O_LIST)
|
||||
$(AR) -rs $@ $^
|
||||
|
||||
$(BLDDIR)/asm-offsets.h : asm-offsets.c $(BLDDIR)/.mkdir
|
||||
$(CC) $(CCFLAGS) $(IFLAGS) -MD -MF $(subst .h,.d,$@) -MT $@ -ffunction-sections -fdata-sections -Wl,--gc-sections -o $@.exe $<
|
||||
$(ISS) $@.exe > $@
|
||||
$(RM) $(subst /,$(S),$@.exe)
|
||||
|
||||
$(BLDDIR)/%.o : %.c $(BLDDIR)/.mkdir
|
||||
$(CC) $(CCFLAGS) $(IFLAGS) $(FLAGS_$*) -mtext-section-literals -MD -MF $(subst .o,.d,$@) -c -o $@ $<
|
||||
|
||||
$(BLDDIR)/%.o : %.S $(BLDDIR)/.mkdir
|
||||
$(CC) $(ASFLAGS) $(IFLAGS) $(FLAGS_$*) -MD -MF $(subst .o,.d,$@) -c -o $@ $<
|
||||
|
||||
clean :
|
||||
$(RM_R) $(BLDDIR)
|
||||
|
||||
clean_all :
|
||||
$(RM_R) $(BLDROOT)
|
||||
|
||||
.PHONY : all clean clean_all
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "../../../../../tasks.c"
|
||||
|
||||
#define DEFINE(sym,val) \
|
||||
printf("#define %s %d /* %s */\n", #sym, (val), #val)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
DEFINE(TCB_TOP_OF_STACK_OFF, offsetof(TCB_t, pxTopOfStack));
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
DEFINE(TCB_MPU_SETTINGS_OFF, offsetof(TCB_t, xMPUSettings.mpumap));
|
||||
DEFINE(MPU_ENTRY_SIZE, sizeof(xthal_MPU_entry));
|
||||
DEFINE(MPU_ENTRY_AS_OFF, offsetof(xthal_MPU_entry, as));
|
||||
DEFINE(MPU_ENTRY_AT_OFF, offsetof(xthal_MPU_entry, at));
|
||||
DEFINE(TCB_TASK_NAME_OFF, offsetof(TCB_t, pcTaskName));
|
||||
#endif
|
||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||
DEFINE(TCB_END_OF_STACK_OFF, offsetof(TCB_t, pxEndOfStack));
|
||||
#endif
|
||||
#if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 )
|
||||
DEFINE(TCB_IMPURE_PTR_OFF, offsetof(TCB_t, xTLSBlock));
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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 "xtensa_rtos.h"
|
||||
#include "portmacro.h"
|
||||
#include "asm-offsets.h"
|
||||
|
||||
#include <xtensa/hal.h>
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
_xt_mpu_restore
|
||||
|
||||
!! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
|
||||
|
||||
Restores task's MPU state
|
||||
|
||||
Entry Conditions:
|
||||
A0 = Return address in caller.
|
||||
|
||||
*******************************************************************************/
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
|
||||
#if XCHAL_HAVE_XEA3 && (!defined __XTENSA_CALL0_ABI__)
|
||||
#define A2 a10
|
||||
#define A3 a11
|
||||
#define A4 a12
|
||||
#define A5 a13
|
||||
#define A6 a14
|
||||
#else
|
||||
#define A2 a2
|
||||
#define A3 a3
|
||||
#define A4 a4
|
||||
#define A5 a5
|
||||
#define A6 a6
|
||||
#endif
|
||||
|
||||
.altmacro
|
||||
|
||||
.macro mpu_set_entry entry
|
||||
/*
|
||||
* Load both first and last entry for a range to avoid memory access
|
||||
* when region is partially modified which may result in a TLB multihit.
|
||||
*/
|
||||
l32i A3, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AT_OFF)
|
||||
l32i A4, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AS_OFF)
|
||||
l32i A5, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AT_OFF)
|
||||
l32i A6, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AS_OFF)
|
||||
wptlb A3, A4
|
||||
wptlb A5, A6
|
||||
.endm
|
||||
|
||||
.section "privileged_functions"
|
||||
.global _xt_mpu_restore
|
||||
.type _xt_mpu_restore,@function
|
||||
.align 4
|
||||
_xt_mpu_restore:
|
||||
|
||||
movi A2, pxCurrentTCB
|
||||
l32i A2, A2, 0
|
||||
beqz A2, .Lset
|
||||
|
||||
movi A3, g_num_used_mpu_entries
|
||||
l32i A3, A3, 0
|
||||
movi A4, .Lset
|
||||
|
||||
/*
|
||||
* A3 = .Lset - 18 * g_num_used_mpu_entries -- is the address of code
|
||||
* that loads MPU entries of the first g_num_used_mpu_entries regions.
|
||||
* 18 is the size of piece of code generated by one mpu_set_entry macro
|
||||
*/
|
||||
slli A5, A3, 4
|
||||
addx2 A5, A3, A5
|
||||
sub A3, A4, A5
|
||||
|
||||
jx A3
|
||||
|
||||
.begin no-transform
|
||||
|
||||
/* Load MPU entries from last to first (not in MPU order,
|
||||
* in pxCurrentTCB->xMPUSettings order).
|
||||
*/
|
||||
.set i, 1
|
||||
.rept portNUM_MAX_SWAPPED_MPU_PAIRS
|
||||
mpu_set_entry %i
|
||||
.set i, i+1
|
||||
.endr
|
||||
.Lset:
|
||||
.end no-transform
|
||||
isync
|
||||
|
||||
ret
|
||||
|
||||
#ifdef portALIGN_SECTIONS
|
||||
.section privileged_functions
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section privileged_data
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section freertos_system_calls
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section .text
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section .data
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section .literal
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section .bss
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section .rodata
|
||||
.align XCHAL_MPU_ALIGN
|
||||
|
||||
.section private_region1
|
||||
.align XCHAL_MPU_ALIGN
|
||||
.section private_region2
|
||||
.align XCHAL_MPU_ALIGN
|
||||
.section private_region3
|
||||
.align XCHAL_MPU_ALIGN
|
||||
.section private_stack
|
||||
.align XCHAL_MPU_ALIGN
|
||||
#endif
|
||||
|
||||
#endif // portUSING_MPU_WRAPPERS
|
||||
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
# define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xtensa/hal.h>
|
||||
#include <xtensa/config/core.h>
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#include <xtensa/tie/xt_interrupt.h>
|
||||
#endif
|
||||
#if XCHAL_HAVE_ISL || XCHAL_HAVE_KSL || XCHAL_HAVE_PSL
|
||||
#include <xtensa/tie/xt_exception_dispatch.h>
|
||||
#endif
|
||||
|
||||
#include "xtensa_api.h"
|
||||
#include "xtensa_rtos.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Heap area (see heap_4.c). When MPU in use, align it to the MPU
|
||||
region boundary to avoid overlapping with non-heap data. */
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
#define HEAP_SIZE ((configTOTAL_HEAP_SIZE + XCHAL_MPU_ALIGN - 1) & -XCHAL_MPU_ALIGN)
|
||||
PRIVILEGED_DATA uint8_t ucHeap[ HEAP_SIZE ] __attribute__((aligned(XCHAL_MPU_ALIGN)));
|
||||
#else
|
||||
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
#endif
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
/* Configure a number of standard MPU regions that are used by all tasks. */
|
||||
extern BaseType_t prvSetupMPU( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Checks to see if being called from the context of an unprivileged task, and
|
||||
* if so raises the privilege level and returns false - otherwise does nothing
|
||||
* other than return true.
|
||||
*/
|
||||
BaseType_t xPortRaisePrivilege( void );
|
||||
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
extern void _xt_coproc_init( void );
|
||||
extern void _xt_coproc_exc(XtExcFrame * fp);
|
||||
#endif
|
||||
|
||||
// Defined in xtensa_vectors.S.
|
||||
extern void _xt_task_start( void );
|
||||
#if XCHAL_HAVE_XEA3 && portUSING_MPU_WRAPPERS
|
||||
extern void _xt_task_start_user( void );
|
||||
#endif
|
||||
|
||||
// Timer tick interval in cycles.
|
||||
static uint32_t xt_tick_cycles;
|
||||
TickType_t xMaxSuppressedTicks;
|
||||
|
||||
static uint32_t xt_tick_count;
|
||||
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
// Flag to indicate tick handling should be skipped.
|
||||
static volatile uint32_t xt_skip_tick;
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
int32_t xt_sw_intnum = -1;
|
||||
#endif
|
||||
|
||||
// Duplicate of inaccessible xSchedulerRunning.
|
||||
uint32_t port_xSchedulerRunning = 0U;
|
||||
|
||||
// Interrupt nesting level.
|
||||
uint32_t port_interruptNesting = 0U;
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tick timer interrupt handler.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void xt_tick_handler( void )
|
||||
{
|
||||
int32_t diff;
|
||||
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
if ( xt_skip_tick )
|
||||
{
|
||||
vTaskStepTick( xt_skip_tick );
|
||||
xt_tick_count += xt_skip_tick;
|
||||
xt_skip_tick = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
BaseType_t ret;
|
||||
uint32_t interruptMask;
|
||||
uint32_t ulOldCCompare = xt_get_ccompare( XT_TIMER_INDEX );
|
||||
|
||||
// Set CCOMPARE for next tick.
|
||||
xt_set_ccompare( XT_TIMER_INDEX, ulOldCCompare + xt_tick_cycles );
|
||||
|
||||
portbenchmarkIntLatency();
|
||||
|
||||
// Interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY must be
|
||||
// disabled before calling xTaskIncrementTick as it accesses the
|
||||
// kernel lists.
|
||||
interruptMask = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
{
|
||||
ret = xTaskIncrementTick();
|
||||
++xt_tick_count;
|
||||
}
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( interruptMask );
|
||||
|
||||
portYIELD_FROM_ISR( ret );
|
||||
|
||||
// Signed comparison gracefully handles cases where another source
|
||||
// has called xt_update_clock_frequency(), e.g. for tickless idle
|
||||
// or variable frequency support, and ccompare was advanced
|
||||
// farther than expected.
|
||||
diff = (int32_t)(xt_get_ccount() - ulOldCCompare);
|
||||
}
|
||||
while ( diff > (int32_t)xt_tick_cycles );
|
||||
}
|
||||
|
||||
static void update_xt_tick_cycles( void )
|
||||
{
|
||||
// Compute the number of cycles per tick.
|
||||
#ifdef XT_CLOCK_FREQ
|
||||
xt_tick_cycles = ( XT_CLOCK_FREQ / XT_TICK_PER_SEC );
|
||||
#elif defined(XT_BOARD)
|
||||
xt_tick_cycles = xtbsp_clock_freq_hz() / XT_TICK_PER_SEC;
|
||||
#else
|
||||
#error "No way to obtain processor clock frequency"
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tick timer init. Install interrupt handler, set up first tick, and
|
||||
// enable timer interrupt.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void xt_tick_timer_init( void )
|
||||
{
|
||||
update_xt_tick_cycles();
|
||||
xMaxSuppressedTicks = 0xFFFFFFFFU / xt_tick_cycles;
|
||||
xt_set_interrupt_handler( XT_TIMER_INTNUM, (xt_handler) xt_tick_handler, 0 );
|
||||
xt_set_ccompare( XT_TIMER_INDEX, xthal_get_ccount() + xt_tick_cycles );
|
||||
xt_tick_count = xTaskGetTickCount();
|
||||
xt_interrupt_enable( XT_TIMER_INTNUM );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tick timer stop. Disable timer interrupt and clear ccompare register.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void xt_tick_timer_stop( void )
|
||||
{
|
||||
xt_interrupt_disable( XT_TIMER_INTNUM );
|
||||
xt_set_ccompare( XT_TIMER_INDEX, 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Start the scheduler.
|
||||
//-----------------------------------------------------------------------------
|
||||
BaseType_t xPortStartScheduler( void )
|
||||
{
|
||||
#if XCHAL_HAVE_XEA3
|
||||
extern void xt_sched_handler(void * arg);
|
||||
int32_t i;
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
// Install the coprocessor exception handler.
|
||||
xt_set_exception_handler(EXCCAUSE_CP_DISABLED, _xt_coproc_exc);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
// Select a software interrupt to use for scheduling.
|
||||
for (i = 0; i < XCHAL_NUM_INTERRUPTS; i++) {
|
||||
if ((Xthal_inttype[i] == XTHAL_INTTYPE_SOFTWARE) && (Xthal_intlevel[i] == 1)) {
|
||||
xt_sw_intnum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (xt_sw_intnum == -1) {
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/* Set the interrupt handler and enable the interrupt. */
|
||||
xt_set_interrupt_handler(xt_sw_intnum, xt_sched_handler, 0);
|
||||
xt_interrupt_enable(xt_sw_intnum);
|
||||
|
||||
#if XCHAL_HAVE_KSL
|
||||
XT_WSR_KSL(0);
|
||||
#endif
|
||||
#if XCHAL_HAVE_ISL
|
||||
XT_WSR_ISL(0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set up and enable timer tick.
|
||||
xt_tick_timer_init();
|
||||
|
||||
#if XT_USE_THREAD_SAFE_CLIB
|
||||
// Init C library
|
||||
vPortClibInit();
|
||||
#endif
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
// Setup MPU
|
||||
if (prvSetupMPU() == pdFALSE)
|
||||
return pdFALSE;
|
||||
#endif
|
||||
|
||||
port_xSchedulerRunning = 1U;
|
||||
|
||||
// Cannot be directly called from C; never returns
|
||||
__asm__ volatile ("call0 _frxt_dispatch\n");
|
||||
|
||||
// Should never get here.
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stop the scheduler.
|
||||
//-----------------------------------------------------------------------------
|
||||
void vPortEndScheduler( void )
|
||||
{
|
||||
xt_tick_timer_stop();
|
||||
port_xSchedulerRunning = 0U;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stack initialization.
|
||||
// Reserve coprocessor save area if needed, construct a dummy stack frame and
|
||||
// populate it for task startup. Return the pointer to the dummy stack frame.
|
||||
// (NOTE: the value returned from this function is expected to be stored in
|
||||
// pxTCB->pxTopOfStack. In the task wrapper code, we will set the value of
|
||||
// pxTCB->pxEndOfStack, which will then be treated as the coprocessor state
|
||||
// area pointer.
|
||||
//-----------------------------------------------------------------------------
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void *pvParameters,
|
||||
BaseType_t xRunPrivileged,
|
||||
xMPU_SETTINGS * xMPUSettings )
|
||||
#else
|
||||
StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
||||
TaskFunction_t pxCode,
|
||||
void * pvParameters )
|
||||
#endif
|
||||
{
|
||||
StackType_t *sp;
|
||||
StackType_t *tp;
|
||||
StackType_t *ret;
|
||||
XtExcFrame *frame;
|
||||
#if XCHAL_CP_NUM > 0
|
||||
uint32_t *p;
|
||||
#endif
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
// TODO: Handle this...
|
||||
(void)xMPUSettings;
|
||||
#endif
|
||||
|
||||
// Allocate enough space for coprocessor state, align base address. This is the
|
||||
// adjusted top-of-stack and also the start of the coprocessor save area.
|
||||
sp = (StackType_t *) ((((uint32_t) pxTopOfStack) - (uint32_t) XT_CP_SIZE) & (uint32_t)~0xF);
|
||||
|
||||
// Allocate interrupt stack frame. XT_STK_FRMSZ is always a multiple of 16 bytes
|
||||
// so 16-byte alignment is ensured.
|
||||
tp = sp - (XT_STK_FRMSZ/sizeof(StackType_t));
|
||||
|
||||
// This is the address we will return.
|
||||
ret = tp;
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
frame = (XtExcFrame *) (tp + (XT_STK_XTRA_SZ/sizeof(StackType_t)));
|
||||
#else
|
||||
frame = (XtExcFrame *) tp;
|
||||
#endif
|
||||
|
||||
// Clear the frame (do not use memset() because we don't depend on C library).
|
||||
for (; tp < sp; ++tp)
|
||||
{
|
||||
*tp = 0;
|
||||
}
|
||||
|
||||
// Explicitly initialize certain saved registers. Note that the entry point
|
||||
// is set to be the task wrapper, and the address of the coprocessor save
|
||||
// area (sp) is saved in the dummy frame for the wrapper to use.
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
frame->pc = (long) pxCode; // task entrypoint
|
||||
frame->a0 = 0; // to terminate GDB backtrace
|
||||
frame->a1 = (long) sp; // top of stack - CP save area
|
||||
frame->exit = (long) _xt_task_start; // task start wrapper
|
||||
// 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 = (long) pvParameters;
|
||||
frame->ps = PS_UM | PS_EXCM;
|
||||
#else
|
||||
// + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd).
|
||||
frame->a6 = (long) pvParameters;
|
||||
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
|
||||
#endif
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
if(!xRunPrivileged) {
|
||||
frame->ps |= (1 << PS_RING_SHIFT);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
frame->a8 = (long) pxCode; // task entrypoint
|
||||
frame->a9 = (long) sp; // top of stack - CP save area
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
frame->pc = (!xRunPrivileged) ?
|
||||
(long) _xt_task_start_user : // PS_RING will be set later
|
||||
(long) _xt_task_start; // standard task start wrapper
|
||||
#else
|
||||
frame->pc = (long) _xt_task_start; // task start wrapper
|
||||
#endif
|
||||
frame->ps = PS_STACK_FIRSTKER; // initial PS
|
||||
frame->atomctl = 0; // initial value
|
||||
// Set entry point arg.
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
frame->a2 = (long) pvParameters;
|
||||
#else
|
||||
frame->a10 = (long) pvParameters;
|
||||
#endif
|
||||
#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).
|
||||
p = (uint32_t *) sp;
|
||||
p[0] = 0;
|
||||
p[1] = 0;
|
||||
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tickless idle support. Suppress N ticks and sleep when directed by kernel.
|
||||
//-----------------------------------------------------------------------------
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
|
||||
{
|
||||
eSleepModeStatus eSleepStatus;
|
||||
|
||||
// Lock out all interrupts. Otherwise reading and using ccount can
|
||||
// get messy. Shouldn't be a problem here since we are about to go
|
||||
// to sleep, and the waiti will re-enable interrupts shortly.
|
||||
|
||||
// Must call vTaskEnterCritical() in order to increment FreeRTOS
|
||||
// nesting count, otheriwse the call to vTaskStepTick() inside this
|
||||
// critical section will inadvertently reenable interrupts.
|
||||
portENTER_CRITICAL();
|
||||
|
||||
eSleepStatus = eTaskConfirmSleepModeStatus();
|
||||
if ( eSleepStatus == eAbortSleep )
|
||||
{
|
||||
// Abort, fall through.
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t num_cycles;
|
||||
uint32_t first_blocked_tick;
|
||||
uint32_t ccompare;
|
||||
uint32_t skip_tick;
|
||||
uint32_t now;
|
||||
|
||||
// Compute number of cycles to sleep for, capped by max limit.
|
||||
// we use one less than the number of ticks because we are already
|
||||
// partway through the current tick. This is adjusted later below.
|
||||
if ( xExpectedIdleTime > xMaxSuppressedTicks )
|
||||
{
|
||||
skip_tick = xMaxSuppressedTicks - 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
skip_tick = xExpectedIdleTime - 1U;
|
||||
}
|
||||
|
||||
num_cycles = xt_tick_cycles * skip_tick;
|
||||
first_blocked_tick = xt_get_ccompare( XT_TIMER_INDEX );
|
||||
xt_skip_tick = skip_tick;
|
||||
|
||||
// Set up for timer interrupt and sleep.
|
||||
ccompare = first_blocked_tick + num_cycles;
|
||||
xt_set_ccompare( XT_TIMER_INDEX, ccompare );
|
||||
#if XCHAL_HAVE_XEA3
|
||||
// Ccompare write will not clear pending interrupt.
|
||||
xt_interrupt_clear( XT_TIMER_INTNUM );
|
||||
#endif
|
||||
// Ensure any clearing of pending interrupt takes effect.
|
||||
// WAITI instruction will reduce interrupt level and sleep so
|
||||
// it must be followed by raising the interrupt level to ensure
|
||||
// the critical section is maintained. The NESTED version is
|
||||
// used here since it does not increment the nesting count that
|
||||
// is managed upon entry and exit of this function.
|
||||
XT_ISYNC();
|
||||
XT_WAITI( 0 );
|
||||
portENTER_CRITICAL_NESTED();
|
||||
|
||||
skip_tick = xt_skip_tick;
|
||||
now = xt_get_ccount();
|
||||
|
||||
// Awakened by non-timer interrupt, update tick counter here.
|
||||
|
||||
if ( skip_tick )
|
||||
{
|
||||
// If there's more than a tick period from now to the timer
|
||||
// deadline try to move deadline to the next possible tick.
|
||||
// Otherwise update tick count for the passed ticks, but don't
|
||||
// change the deadline.
|
||||
// If we get here, we have not handled a timer interrupt, so
|
||||
// ccompare is still in the future, or in the immediate past
|
||||
// (crossed after entering the critical section above). In the
|
||||
// latter case the pending interrupt will be cleared below.
|
||||
|
||||
if ( ccompare - now > xt_tick_cycles )
|
||||
{
|
||||
uint32_t prev_tick = first_blocked_tick - xt_tick_cycles;
|
||||
uint32_t actual_cycles = now - prev_tick;
|
||||
uint32_t ticks = actual_cycles / xt_tick_cycles;
|
||||
uint32_t diff;
|
||||
|
||||
ccompare = first_blocked_tick + ticks * xt_tick_cycles;
|
||||
|
||||
do
|
||||
{
|
||||
vTaskStepTick( ticks );
|
||||
xt_tick_count += ticks;
|
||||
#if XCHAL_HAVE_XEA3
|
||||
// ccompare may be very close in the xt_set_ccompare call
|
||||
// below, so we cannot reliably call xt_interrupt_clear
|
||||
// after it. Make sure that timer IRQ is clear when
|
||||
// xt_set_ccompare( XT_TIMER_INDEX, ccompare ) is called.
|
||||
// Set ccompare to current ccount to avoid timer IRQ
|
||||
// arriving in the gap between xt_interrupt_clear
|
||||
// and the following xt_set_ccompare.
|
||||
xt_set_ccompare( XT_TIMER_INDEX, xt_get_ccount() );
|
||||
// Ccompare write will not clear pending interrupt.
|
||||
xt_interrupt_clear( XT_TIMER_INTNUM );
|
||||
#endif
|
||||
xt_set_ccompare( XT_TIMER_INDEX, ccompare );
|
||||
diff = xt_get_ccount() - ccompare;
|
||||
ccompare += xt_tick_cycles;
|
||||
ticks = 1;
|
||||
|
||||
} while ( diff <= INT32_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskStepTick( skip_tick );
|
||||
xt_tick_count += skip_tick;
|
||||
}
|
||||
|
||||
xt_skip_tick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
extern void vPortResetPrivilege(BaseType_t previous);
|
||||
void vPortEnterCritical( void )
|
||||
{
|
||||
// TODO: handle configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
|
||||
// For reference, see commit 79704b from 9/16/2022
|
||||
if( portIS_PRIVILEGED() == pdFALSE )
|
||||
{
|
||||
portRAISE_PRIVILEGE();
|
||||
vTaskEnterCritical();
|
||||
portRESET_PRIVILEGE();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle port_interruptNesting
|
||||
vTaskEnterCritical();
|
||||
}
|
||||
}
|
||||
|
||||
void vPortExitCritical( void )
|
||||
{
|
||||
// TODO: handle configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS
|
||||
// For reference, see commit 79704b from 9/16/2022
|
||||
if( portIS_PRIVILEGED() == pdFALSE )
|
||||
{
|
||||
portRAISE_PRIVILEGE();
|
||||
vTaskExitCritical();
|
||||
portRESET_PRIVILEGE();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle port_interruptNesting
|
||||
vTaskExitCritical();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configUSE_VARIABLE_FREQUENCY != 0 )
|
||||
static void update_tick_remainder( uint32_t now )
|
||||
{
|
||||
uint32_t old_ccompare;
|
||||
uint32_t old_tick_cycles;
|
||||
|
||||
old_ccompare = xt_get_ccompare( XT_TIMER_INDEX );
|
||||
old_tick_cycles = xt_tick_cycles;
|
||||
update_xt_tick_cycles();
|
||||
|
||||
// If tick deadline has not been reached yet correct number of remaining
|
||||
// cycles, otherwise timer interrupt must be pending, just service it.
|
||||
|
||||
if ( old_ccompare - now < old_tick_cycles )
|
||||
{
|
||||
uint32_t new_ccompare = now +
|
||||
(uint32_t)((uint64_t)(old_ccompare - now) * xt_tick_cycles / old_tick_cycles);
|
||||
|
||||
xt_set_ccompare( XT_TIMER_INDEX, new_ccompare );
|
||||
now = xt_get_ccount();
|
||||
if ( new_ccompare - now > xt_tick_cycles )
|
||||
xt_tick_handler();
|
||||
}
|
||||
}
|
||||
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
void xt_update_clock_frequency( void )
|
||||
{
|
||||
uint32_t skip_tick;
|
||||
uint32_t now;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
|
||||
now = xt_get_ccount();
|
||||
skip_tick = xt_skip_tick;
|
||||
|
||||
if ( skip_tick )
|
||||
{
|
||||
uint32_t ccompare = xt_get_ccompare( XT_TIMER_INDEX );
|
||||
|
||||
// If there's more than a tick period from now to the timer
|
||||
// deadline try to move deadline to the next possible tick.
|
||||
// Otherwise update tick count for the passed ticks, but don't
|
||||
// change the deadline.
|
||||
|
||||
if ( ccompare - now > xt_tick_cycles &&
|
||||
ccompare - now <= INT32_MAX )
|
||||
{
|
||||
uint32_t first_blocked_tick = ccompare - xt_tick_cycles * skip_tick;
|
||||
uint32_t prev_tick = first_blocked_tick - xt_tick_cycles;
|
||||
uint32_t actual_cycles = now - prev_tick;
|
||||
uint32_t ticks = actual_cycles / xt_tick_cycles;
|
||||
uint32_t diff;
|
||||
|
||||
ccompare = first_blocked_tick + ticks * xt_tick_cycles;
|
||||
|
||||
do
|
||||
{
|
||||
vTaskStepTick( ticks );
|
||||
xt_tick_count += ticks;
|
||||
xt_set_ccompare( XT_TIMER_INDEX, ccompare );
|
||||
diff = xt_get_ccount() - ccompare;
|
||||
ccompare += xt_tick_cycles;
|
||||
ticks = 1;
|
||||
|
||||
} while ( diff <= INT32_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskStepTick( skip_tick );
|
||||
xt_tick_count += skip_tick;
|
||||
}
|
||||
xt_skip_tick = 0;
|
||||
}
|
||||
update_tick_remainder( now );
|
||||
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
#else
|
||||
void xt_update_clock_frequency( void )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
update_tick_remainder( xt_get_ccount() );
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+702
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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 "xtensa_rtos.h"
|
||||
#include "asm-offsets.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
.extern pxCurrentTCB
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Interrupt stack. The size of the interrupt stack is determined by the config
|
||||
* parameter "configISR_STACK_SIZE" in FreeRTOSConfig.h
|
||||
*******************************************************************************
|
||||
*/
|
||||
.data
|
||||
.align 16
|
||||
.global port_switch_flag
|
||||
port_switch_flag:
|
||||
.word 0
|
||||
|
||||
.global port_yield_flag
|
||||
port_yield_flag:
|
||||
.word 0
|
||||
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
.section "privileged_functions"
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* _frxt_setup_switch
|
||||
* void _frxt_setup_switch(void);
|
||||
*
|
||||
* Sets an internal flag indicating that a task switch is required on return
|
||||
* from interrupt handling.
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
.global _frxt_setup_switch
|
||||
.type _frxt_setup_switch,@function
|
||||
.align 4
|
||||
_frxt_setup_switch:
|
||||
|
||||
ENTRY(16)
|
||||
|
||||
movi a2, port_switch_flag
|
||||
movi a3, 1
|
||||
s32i a3, a2, 0
|
||||
|
||||
RET(16)
|
||||
|
||||
.size _frxt_setup_switch, . - _frxt_setup_switch
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* _frxt_int_enter
|
||||
* void _frxt_int_enter(void)
|
||||
*
|
||||
* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_ENTER function for
|
||||
* freeRTOS. Saves the rest of the interrupt context (not already saved).
|
||||
* May only be called from assembly code by the 'call0' instruction, with
|
||||
* interrupts disabled.
|
||||
* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
.globl _frxt_int_enter
|
||||
.type _frxt_int_enter,@function
|
||||
.align 4
|
||||
_frxt_int_enter:
|
||||
|
||||
/* Save a12-13 in the stack frame as required by _xt_context_save. */
|
||||
s32i a12, a1, XT_STK_A12
|
||||
s32i a13, a1, XT_STK_A13
|
||||
|
||||
/* Save return address in a safe place (free a0). */
|
||||
mov a12, a0
|
||||
|
||||
/* Save the rest of the interrupted context (preserves A12-13). */
|
||||
call0 _xt_context_save
|
||||
|
||||
/*
|
||||
Save interrupted task's SP in TCB only if not nesting.
|
||||
Manage nesting directly rather than call the generic IntEnter()
|
||||
(in windowed ABI we can't call a C function here anyway because PS.EXCM is still set).
|
||||
*/
|
||||
movi a2, port_xSchedulerRunning
|
||||
movi a3, port_interruptNesting
|
||||
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
||||
beqz a2, 1f /* scheduler not running, no tasks */
|
||||
l32i a2, a3, 0 /* a2 = port_interruptNesting */
|
||||
addi a2, a2, 1 /* increment nesting count */
|
||||
s32i a2, a3, 0 /* save nesting count */
|
||||
bnei a2, 1, .Lnested /* !=0 before incr, so nested */
|
||||
|
||||
movi a2, pxCurrentTCB
|
||||
l32i a2, a2, 0 /* a2 = current TCB */
|
||||
beqz a2, 1f
|
||||
s32i a1, a2, TCB_TOP_OF_STACK_OFF /* pxCurrentTCB->pxTopOfStack = SP */
|
||||
movi a1, xt_interrupt_stack_top /* a1 = top of intr stack */
|
||||
|
||||
.Lnested:
|
||||
1:
|
||||
mov a0, a12 /* restore return addr and return */
|
||||
ret
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* _frxt_int_exit
|
||||
* void _frxt_int_exit(void)
|
||||
*
|
||||
* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_EXIT function for
|
||||
* FreeRTOS. If required, calls vPortYieldFromInt() to perform task context
|
||||
* switching, restore the (possibly) new task's context, and return to the
|
||||
* exit dispatcher saved in the task's stack frame at XT_STK_EXIT.
|
||||
* May only be called from assembly code by the 'call0' instruction. Does not
|
||||
* return to caller.
|
||||
* See the description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
|
||||
*
|
||||
*******************************************************************************
|
||||
*/
|
||||
.globl _frxt_int_exit
|
||||
.type _frxt_int_exit,@function
|
||||
.align 4
|
||||
_frxt_int_exit:
|
||||
|
||||
movi a2, port_xSchedulerRunning
|
||||
movi a3, port_interruptNesting
|
||||
rsil a0, XT_IRQ_LOCK_LEVEL /* lock out interrupts */
|
||||
l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */
|
||||
beqz a2, .Lnoswitch /* scheduler not running, no tasks */
|
||||
l32i a2, a3, 0 /* a2 = port_interruptNesting */
|
||||
addi a2, a2, -1 /* decrement nesting count */
|
||||
s32i a2, a3, 0 /* save nesting count */
|
||||
bnez a2, .Lnesting /* !=0 after decr so still nested */
|
||||
|
||||
movi a2, pxCurrentTCB
|
||||
l32i a2, a2, 0 /* a2 = current TCB */
|
||||
beqz a2, 1f /* no task ? go to dispatcher */
|
||||
l32i a1, a2, TCB_TOP_OF_STACK_OFF /* SP = pxCurrentTCB->pxTopOfStack */
|
||||
|
||||
movi a2, port_switch_flag /* address of switch flag */
|
||||
l32i a3, a2, 0 /* a3 = port_switch_flag */
|
||||
beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */
|
||||
movi a3, 0
|
||||
s32i a3, a2, 0 /* zero out the flag for next time */
|
||||
|
||||
1:
|
||||
/*
|
||||
Call0 ABI callee-saved regs a12-15 need to be saved before possible preemption.
|
||||
However a12-13 were already saved by _frxt_int_enter().
|
||||
*/
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
s32i a14, a1, XT_STK_A14
|
||||
s32i a15, a1, XT_STK_A15
|
||||
#endif
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
call0 vPortYieldFromInt /* call dispatch inside the function; never returns */
|
||||
#else
|
||||
call4 vPortYieldFromInt /* this one returns */
|
||||
call0 _frxt_dispatch /* tail-call dispatcher */
|
||||
/* Never returns here. */
|
||||
#endif
|
||||
|
||||
.Lnoswitch:
|
||||
/*
|
||||
If we came here then about to resume the interrupted task.
|
||||
*/
|
||||
|
||||
.Lnesting:
|
||||
/*
|
||||
We come here only if there was no context switch, that is if this
|
||||
is a nested interrupt, or the interrupted task was not preempted.
|
||||
In either case there's no need to load the SP.
|
||||
*/
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
call0 _xt_mpu_restore
|
||||
#endif
|
||||
|
||||
/* Restore full context from interrupt stack frame */
|
||||
call0 _xt_context_restore
|
||||
|
||||
/*
|
||||
Must return via the exit dispatcher corresponding to the entry point from which
|
||||
this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
|
||||
stack frame is deallocated in the exit dispatcher.
|
||||
*/
|
||||
l32i a0, a1, XT_STK_EXIT
|
||||
ret
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
* DISPATCH THE HIGH READY TASK
|
||||
* void _frxt_dispatch(void)
|
||||
*
|
||||
* Switch context to the highest priority ready task, restore its state and dispatch control to it.
|
||||
*
|
||||
* This is a common dispatcher that acts as a shared exit path for all the context switch functions
|
||||
* including vPortYield() and vPortYieldFromInt(), all of which tail-call this dispatcher
|
||||
* (for windowed ABI vPortYieldFromInt() calls it indirectly via _frxt_int_exit() ).
|
||||
*
|
||||
* The Xtensa port uses different stack frames for solicited and unsolicited task suspension (see
|
||||
* comments on stack frames in xtensa_context.h). This function restores the state accordingly.
|
||||
* If restoring a task that solicited entry, restores the minimal state and leaves CPENABLE clear.
|
||||
* If restoring a task that was preempted, restores all state including the task's CPENABLE.
|
||||
*
|
||||
* Entry:
|
||||
* pxCurrentTCB points to the TCB of the task to suspend,
|
||||
* Because it is tail-called without a true function entrypoint, it needs no 'entry' instruction.
|
||||
*
|
||||
* Exit:
|
||||
* If incoming task called vPortYield() (solicited), this function returns as if from vPortYield().
|
||||
* If incoming task was preempted by an interrupt, this function jumps to exit dispatcher.
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
.globl _frxt_dispatch
|
||||
.type _frxt_dispatch,@function
|
||||
.align 4
|
||||
_frxt_dispatch:
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
/* Skip "entry" - nothing to save, never returns. */
|
||||
|
||||
movi a2, PS_STACK_KERNEL | PS_DI /* Set PS.STACK = Kernel and */
|
||||
movi a3, PS_STACK_MASK | PS_DI_MASK /* disable interrupts. */
|
||||
xps a2, a3
|
||||
|
||||
movi a2, port_yield_flag
|
||||
movi a3, 1
|
||||
s32i a3, a2, 0 /* Indicate thread yield. */
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
call0 vTaskSwitchContext // Get next TCB to resume
|
||||
movi a2, pxCurrentTCB
|
||||
#else
|
||||
movi a2, pxCurrentTCB
|
||||
call8 vTaskSwitchContext // Get next TCB to resume
|
||||
#endif
|
||||
|
||||
l32i a3, a2, 0 /* a3 = pxCurrentTCB */
|
||||
l32i a1, a3, TCB_TOP_OF_STACK_OFF /* SP = next_TCB->pxTopOfStack */
|
||||
addi a1, a1, XT_STK_FRMSZ /* Adjust for the dummy frame */
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
mov a15, a1 /* Dispatch code expects a15 = old SP */
|
||||
#endif
|
||||
|
||||
movi a0, _xt_dispatch + 3 /* Jump to dispatch code. It will */
|
||||
ret /* check for ready thread or idle */
|
||||
/* and handle accordingly. */
|
||||
|
||||
ill /* Should never get back here. */
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
call0 vTaskSwitchContext // Get next TCB to resume
|
||||
movi a2, pxCurrentTCB
|
||||
#else
|
||||
movi a2, pxCurrentTCB
|
||||
call4 vTaskSwitchContext // Get next TCB to resume
|
||||
#endif
|
||||
l32i a3, a2, 0
|
||||
l32i sp, a3, TCB_TOP_OF_STACK_OFF /* SP = next_TCB->pxTopOfStack */
|
||||
s32i a3, a2, 0
|
||||
|
||||
/* Determine the type of stack frame. */
|
||||
l32i a2, sp, XT_STK_EXIT /* exit dispatcher or solicited flag */
|
||||
bnez a2, .L_frxt_dispatch_stk
|
||||
|
||||
.L_frxt_dispatch_sol:
|
||||
|
||||
/* Solicited stack frame. Restore minimal context and return from vPortYield(). */
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
movi a2, SYSCALL_raise_priv
|
||||
syscall
|
||||
mov a9, a2
|
||||
call0 _xt_mpu_restore
|
||||
bnez a9, skip_lowering_priv;
|
||||
rsr.ps a2
|
||||
addi a2, a2, PS_RING(1)
|
||||
wsr.ps a2
|
||||
skip_lowering_priv:
|
||||
#endif
|
||||
|
||||
l32i a3, sp, XT_STK_PS
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
l32i a12, sp, XT_STK_A12
|
||||
l32i a13, sp, XT_STK_A13
|
||||
l32i a14, sp, XT_STK_A14
|
||||
l32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
l32i a0, sp, XT_STK_PC
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Ensure wsr.CPENABLE is complete (should be, it was cleared on entry). */
|
||||
rsync
|
||||
#endif
|
||||
/* As soons as PS is restored, interrupts can happen. No need to sync PS. */
|
||||
wsr a3, PS
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
addi sp, sp, XT_STK_FRMSZ
|
||||
ret
|
||||
#else
|
||||
retw
|
||||
#endif
|
||||
|
||||
.L_frxt_dispatch_stk:
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Restore CPENABLE from task's co-processor save area. */
|
||||
movi a3, pxCurrentTCB
|
||||
l32i a3, a3, 0
|
||||
l32i a2, a3, TCB_END_OF_STACK_OFF /* a2 = base of coproc save area */
|
||||
l16ui a3, a2, XT_CPENABLE /* a3 = saved CPENABLE value */
|
||||
wsr a3, CPENABLE
|
||||
#endif
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
call0 _xt_mpu_restore
|
||||
#endif
|
||||
|
||||
/* Interrupt stack frame. Restore full context and return to exit dispatcher. */
|
||||
call0 _xt_context_restore
|
||||
|
||||
/* In Call0 ABI, restore callee-saved regs (A12, A13 already restored). */
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
l32i a14, sp, XT_STK_A14
|
||||
l32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Ensure wsr.CPENABLE has completed. */
|
||||
rsync
|
||||
#endif
|
||||
|
||||
/*
|
||||
Must return via the exit dispatcher corresponding to the entrypoint from which
|
||||
this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
|
||||
stack frame is deallocated in the exit dispatcher.
|
||||
*/
|
||||
l32i a0, sp, XT_STK_EXIT
|
||||
ret
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
* PERFORM A SOLICTED CONTEXT SWITCH (from a task)
|
||||
* void vPortYield(void)
|
||||
*
|
||||
* This function saves the minimal state needed for a solicited task suspension, clears CPENABLE,
|
||||
* then tail-calls the dispatcher _frxt_dispatch() to perform the actual context switch
|
||||
*
|
||||
* At Entry:
|
||||
* pxCurrentTCB points to the TCB of the task to suspend
|
||||
* Callable from C (obeys ABI conventions on entry).
|
||||
*
|
||||
* Does not return to caller.
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
.globl vPortYield
|
||||
.type vPortYield,@function
|
||||
.align 4
|
||||
vPortYield:
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
addi sp, sp, -16
|
||||
s32i a0, sp, 0 /* save return address */
|
||||
#else
|
||||
entry sp, 48
|
||||
s32i a0, sp, 0 /* save return address */
|
||||
ssai 0
|
||||
spillw /* spill all registers */
|
||||
#endif
|
||||
|
||||
/*
|
||||
Save register state into exception frame. This is safe to do with
|
||||
interrupts enabled, and we will keep the frame allocated when we
|
||||
call the dispatch function.
|
||||
*/
|
||||
|
||||
movi a0, .Lret
|
||||
rsr.ps a2
|
||||
addi sp, sp, -XT_STK_XFRM_SZ
|
||||
s32i a0, sp, XT_STK_PC /* save return PC */
|
||||
s32i a2, sp, XT_STK_PS /* save PS */
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
s32i a12, sp, XT_STK_A12 /* callee-saved registers */
|
||||
s32i a13, sp, XT_STK_A13
|
||||
s32i a14, sp, XT_STK_A14
|
||||
s32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
|
||||
movi a2, PS_STACK_KERNEL | PS_DI /* Set PS.STACK = Kernel and */
|
||||
movi a8, PS_STACK_MASK | PS_DI_MASK /* disable interrupts. */
|
||||
xps a2, a8
|
||||
|
||||
movi a3, pxCurrentTCB
|
||||
l32i a4, a3, 0 /* a4 = pxCurrentTCB */
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Save coprocessor callee-saved state (if any). At this point CPENABLE */
|
||||
/* should still reflect which CPs were in use (enabled). */
|
||||
call0 _xt_coproc_savecs
|
||||
|
||||
/* Clear CPENABLE and give up all co-procs. */
|
||||
l32i a3, a4, TCB_END_OF_STACK_OFF /* a3 = pxCurrentTCB->cp_state */
|
||||
movi a5, 0
|
||||
s16i a5, a3, XT_CPENABLE
|
||||
wsr a5, CPENABLE /* disable all co-processors */
|
||||
#endif
|
||||
|
||||
addi a5, sp, XT_STK_XFRM_SZ - XT_STK_FRMSZ
|
||||
s32i a5, a4, TCB_TOP_OF_STACK_OFF /* pxCurrentTCB->pxTopOfStack = SP */
|
||||
|
||||
call0 _frxt_dispatch /* Does not return, see below */
|
||||
|
||||
/* Execution returns here. Interrupts should be disabled. */
|
||||
/* NOTE: we expect original SP to have been restored. */
|
||||
|
||||
.align 4
|
||||
|
||||
.Lret:
|
||||
addi sp, sp, -XT_STK_XFRM_SZ /* Prepare to restore state */
|
||||
l32i a2, sp, XT_STK_PS /* Retrieve PS value */
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
l32i a12, sp, XT_STK_A12 /* Callee-saved registers */
|
||||
l32i a13, sp, XT_STK_A13
|
||||
l32i a14, sp, XT_STK_A14
|
||||
l32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
addi sp, sp, XT_STK_XFRM_SZ
|
||||
wsr.ps a2 /* Safe to enable interrupts */
|
||||
rsync
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
l32i a0, sp, 0
|
||||
addi sp, sp, 16
|
||||
ret
|
||||
#else
|
||||
l32i a0, sp, 0
|
||||
retw
|
||||
#endif
|
||||
#endif /* XCHAL_HAVE_XEA3 */
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
addi a2, sp, -XT_STK_FRMSZ /* avoid addi/addmi relaxation that */
|
||||
mov sp, a2 /* might temporarily move sp up */
|
||||
#else
|
||||
entry sp, XT_STK_FRMSZ
|
||||
#endif
|
||||
|
||||
rsr a2, PS
|
||||
s32i a0, sp, XT_STK_PC
|
||||
s32i a2, sp, XT_STK_PS
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
s32i a12, sp, XT_STK_A12 /* save callee-saved registers */
|
||||
s32i a13, sp, XT_STK_A13
|
||||
s32i a14, sp, XT_STK_A14
|
||||
s32i a15, sp, XT_STK_A15
|
||||
#else
|
||||
/* Spill register windows. Calling xthal_window_spill() causes extra */
|
||||
/* spills and reloads, so we will set things up to call the _nw version */
|
||||
/* instead to save cycles. */
|
||||
movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK) /* spills a4-a7 if needed */
|
||||
and a2, a2, a6 /* clear WOE, INTLEVEL */
|
||||
addi a2, a2, XT_IRQ_LOCK_LEVEL /* set INTLEVEL */
|
||||
wsr a2, PS
|
||||
rsync
|
||||
call0 xthal_window_spill_nw
|
||||
l32i a2, sp, XT_STK_PS /* restore PS */
|
||||
wsr a2, PS
|
||||
#endif
|
||||
|
||||
rsil a2, XT_IRQ_LOCK_LEVEL /* disable low/med interrupts */
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Save coprocessor callee-saved state (if any). At this point CPENABLE */
|
||||
/* should still reflect which CPs were in use (enabled). */
|
||||
call0 _xt_coproc_savecs
|
||||
#endif
|
||||
|
||||
movi a2, pxCurrentTCB
|
||||
movi a3, 0
|
||||
l32i a2, a2, 0 /* a2 = pxCurrentTCB */
|
||||
s32i a3, sp, XT_STK_EXIT /* 0 to flag as solicited frame */
|
||||
s32i sp, a2, TCB_TOP_OF_STACK_OFF /* pxCurrentTCB->pxTopOfStack = SP */
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Clear CPENABLE, also in task's co-processor state save area. */
|
||||
l32i a2, a2, TCB_END_OF_STACK_OFF /* a2 = pxCurrentTCB->cp_state */
|
||||
movi a3, 0
|
||||
wsr a3, CPENABLE
|
||||
beqz a2, 1f
|
||||
s16i a3, a2, XT_CPENABLE /* clear saved cpenable */
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* Tail-call dispatcher. */
|
||||
call0 _frxt_dispatch
|
||||
/* Never reaches here. */
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
* PERFORM AN UNSOLICITED CONTEXT SWITCH (from an interrupt)
|
||||
* void vPortYieldFromInt(void)
|
||||
*
|
||||
* This calls the context switch hook (removed), saves and clears CPENABLE, then tail-calls the dispatcher
|
||||
* _frxt_dispatch() to perform the actual context switch.
|
||||
*
|
||||
* At Entry:
|
||||
* Interrupted task context has been saved in an interrupt stack frame at pxCurrentTCB->pxTopOfStack.
|
||||
* pxCurrentTCB points to the TCB of the task to suspend,
|
||||
* Callable from C (obeys ABI conventions on entry).
|
||||
*
|
||||
* At Exit:
|
||||
* Windowed ABI defers the actual context switch until the stack is unwound to interrupt entry.
|
||||
* Call0 ABI tail-calls the dispatcher directly (no need to unwind) so does not return to caller.
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
.globl vPortYieldFromInt
|
||||
.type vPortYieldFromInt,@function
|
||||
.align 4
|
||||
vPortYieldFromInt:
|
||||
|
||||
ENTRY(16)
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */
|
||||
movi a3, pxCurrentTCB /* cp_state = */
|
||||
l32i a3, a3, 0
|
||||
l32i a2, a3, TCB_END_OF_STACK_OFF
|
||||
|
||||
rsr a3, CPENABLE
|
||||
s16i a3, a2, XT_CPENABLE /* cp_state->cpenable = CPENABLE; */
|
||||
movi a3, 0
|
||||
wsr a3, CPENABLE /* disable all co-processors */
|
||||
#endif
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
/* Tail-call dispatcher. */
|
||||
call0 _frxt_dispatch
|
||||
/* Never reaches here. */
|
||||
#else
|
||||
RET(16)
|
||||
#endif
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------------------
|
||||
Task entry wrapper. Set up as the resume address in the initial stack frame.
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.global _xt_task_start
|
||||
.type _xt_task_start,@function
|
||||
.align 4
|
||||
|
||||
_xt_task_start:
|
||||
#if XCHAL_CP_NUM > 0
|
||||
movi a0, 0
|
||||
wsr a0, CPENABLE /* disable all coprocessors */
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
/* On entry, a8 = task entry point, a9 = top of stack / coproc save area */
|
||||
movi a0, pxCurrentTCB
|
||||
l32i a0, a0, 0
|
||||
s32i a9, a0, TCB_END_OF_STACK_OFF /* TCB->pxEndOfStack = CP save area */
|
||||
movi a0, 0 /* terminate call stack for gdb */
|
||||
jx a8
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
|
||||
wsr a0, PS
|
||||
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
|
||||
wsr a0, EPC_1
|
||||
movi a3, pxCurrentTCB
|
||||
l32i a3, a3, 0
|
||||
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
|
||||
l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
|
||||
s32i sp, a3, TCB_END_OF_STACK_OFF /* TCB->pxEndOfStack = CP save area */
|
||||
rsync /* ensure PS and EPC written */
|
||||
rfe /* PS.EXCM is cleared */
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
/*
|
||||
--------------------------------------------------------------------------------
|
||||
XEA3 User-mode task entry wrapper. Same as _xt_task_start but sets PS_RING
|
||||
bit after privileged init is complete.
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.global _xt_task_start_user
|
||||
.type _xt_task_start_user,@function
|
||||
.align 4
|
||||
|
||||
_xt_task_start_user:
|
||||
#if XCHAL_CP_NUM > 0
|
||||
movi a0, 0
|
||||
wsr a0, CPENABLE /* disable all coprocessors */
|
||||
#endif
|
||||
|
||||
/* On entry, a8 = task entry point, a9 = top of stack / coproc save area */
|
||||
movi a0, pxCurrentTCB
|
||||
l32i a0, a0, 0
|
||||
s32i a9, a0, TCB_END_OF_STACK_OFF /* TCB->pxEndOfStack = CP save area */
|
||||
rsr a0, PS
|
||||
movi a3, (1 << PS_RING_SHIFT)
|
||||
or a0, a0, a3
|
||||
wsr a0, PS
|
||||
movi a0, 0 /* terminate call stack for gdb */
|
||||
jx a8
|
||||
#endif
|
||||
|
||||
/*
|
||||
**********************************************************************************************************
|
||||
* _xt_task_coproc_state
|
||||
* void _xt_task_coproc_state(void)
|
||||
*
|
||||
* Implements the Xtensa RTOS porting layer's XT_RTOS_CP_STATE function for FreeRTOS.
|
||||
*
|
||||
* May only be called when a task is running, not within an interrupt handler (returns 0 in that case).
|
||||
* May only be called from assembly code by the 'call0' instruction. Does NOT obey ABI conventions.
|
||||
* Returns in a15 a pointer to the base of the co-processor state save area for the current task.
|
||||
* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
|
||||
*
|
||||
**********************************************************************************************************
|
||||
*/
|
||||
#if XCHAL_CP_NUM > 0
|
||||
|
||||
.globl _xt_task_coproc_state
|
||||
.type _xt_task_coproc_state,@function
|
||||
.align 4
|
||||
|
||||
_xt_task_coproc_state:
|
||||
|
||||
movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */
|
||||
l32i a15, a15, 0
|
||||
beqz a15, 2f
|
||||
movi a15, port_interruptNesting /* && port_interruptNesting == 0 */
|
||||
l32i a15, a15, 0
|
||||
bnez a15, 1f
|
||||
movi a15, pxCurrentTCB
|
||||
l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
|
||||
beqz a15, 2f
|
||||
l32i a15, a15, TCB_END_OF_STACK_OFF /* a15 = pxCurrentTCB->pxEndOfStack */
|
||||
ret
|
||||
1:
|
||||
movi a15, 0
|
||||
2:
|
||||
ret
|
||||
|
||||
#endif /* XCHAL_CP_NUM > 0 */
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This utility helps benchmarking interrupt latency and context switches.
|
||||
* In order to enable it, set configBENCHMARK to 1 in FreeRTOSConfig.h.
|
||||
* You will also need to download the FreeRTOS_trace patch that contains
|
||||
* portbenchmark.c and the complete version of portbenchmark.h
|
||||
*/
|
||||
|
||||
#ifndef PORTBENCHMARK_H
|
||||
#define PORTBENCHMARK_H
|
||||
|
||||
#if configBENCHMARK
|
||||
#error "You need to download the FreeRTOS_trace patch that overwrites this file"
|
||||
#endif
|
||||
|
||||
#define portbenchmarkINTERRUPT_DISABLE()
|
||||
#define portbenchmarkINTERRUPT_RESTORE(newstate)
|
||||
#define portbenchmarkIntLatency()
|
||||
#define portbenchmarkIntWait()
|
||||
#define portbenchmarkReset()
|
||||
#define portbenchmarkPrint()
|
||||
|
||||
#endif /* PORTBENCHMARK */
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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 "FreeRTOS.h"
|
||||
|
||||
#if XT_USE_THREAD_SAFE_CLIB
|
||||
|
||||
#if XSHAL_CLIB == XTHAL_CLIB_XCLIB
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/reent.h>
|
||||
|
||||
#include "semphr.h"
|
||||
|
||||
typedef SemaphoreHandle_t _Rmtx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Override this and set to nonzero to enable locking.
|
||||
//-----------------------------------------------------------------------------
|
||||
int32_t _xclib_use_mt = 1;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Init lock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_Mtxinit(_Rmtx * mtx)
|
||||
{
|
||||
// There is a little problem here with recursion. At startup _Initlocks()
|
||||
// is called (within xclib) which attempts to create all the locks which
|
||||
// comes here and can result in a call to malloc() which can try to lock
|
||||
// access to the heap which results in another call to _Initlocks(). This
|
||||
// infinite recursion must be avoided. What we do here is temporarily set
|
||||
// the _xclib_use_mt to zero so that recursive calls to _Initlocks() will
|
||||
// become nops. This allows the xSemaphoreCreateRecursiveMutex() function
|
||||
// to call malloc() safely.
|
||||
// Note that we could have used statically allocated mutexes instead but
|
||||
// that requires configSUPPORT_STATIC_ALLOCATION to be defined which in
|
||||
// turn requires other data such as idle task TCB/stack, timer task TCB/
|
||||
// stack to be statically defined.
|
||||
|
||||
_xclib_use_mt = 0;
|
||||
*mtx = xSemaphoreCreateRecursiveMutex();
|
||||
_xclib_use_mt = 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destroy lock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_Mtxdst(_Rmtx * mtx)
|
||||
{
|
||||
if ((mtx != NULL) && (*mtx != NULL)) {
|
||||
vSemaphoreDelete(*mtx);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_Mtxlock(_Rmtx * mtx)
|
||||
{
|
||||
if ((mtx != NULL) && (*mtx != NULL)) {
|
||||
xSemaphoreTakeRecursive(*mtx, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Unlock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_Mtxunlock(_Rmtx * mtx)
|
||||
{
|
||||
if ((mtx != NULL) && (*mtx != NULL)) {
|
||||
xSemaphoreGiveRecursive(*mtx);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by malloc() to allocate blocks of memory from the heap.
|
||||
//-----------------------------------------------------------------------------
|
||||
void *
|
||||
_sbrk_r (struct _reent * reent, int32_t incr)
|
||||
{
|
||||
extern char _end[];
|
||||
extern char _heap_sentry;
|
||||
static char * _heap_sentry_ptr = &_heap_sentry;
|
||||
static char * heap_ptr;
|
||||
char * base;
|
||||
|
||||
if (!heap_ptr)
|
||||
heap_ptr = (char *) &_end[0];
|
||||
|
||||
base = heap_ptr;
|
||||
if (heap_ptr + incr >= _heap_sentry_ptr) {
|
||||
reent->_errno = ENOMEM;
|
||||
return (char *) -1;
|
||||
}
|
||||
|
||||
heap_ptr += incr;
|
||||
return base;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global initialization for C library.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
vPortClibInit(void)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Per-thread cleanup stub provided for linking, does nothing.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_reclaim_reent(struct _reent * ptr)
|
||||
{
|
||||
(void ) ptr; /* Avoid compiler warning */
|
||||
}
|
||||
|
||||
#endif /* XSHAL_CLIB == XTHAL_CLIB_XCLIB */
|
||||
|
||||
#if XSHAL_CLIB == XTHAL_CLIB_NEWLIB
|
||||
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "semphr.h"
|
||||
|
||||
static SemaphoreHandle_t xClibMutex;
|
||||
static uint32_t ulClibInitDone = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get C library lock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
__malloc_lock(struct _reent * ptr)
|
||||
{
|
||||
// Suppress compiler warning.
|
||||
(void) ptr;
|
||||
|
||||
if (!ulClibInitDone)
|
||||
return;
|
||||
|
||||
xSemaphoreTakeRecursive(xClibMutex, portMAX_DELAY);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Release C library lock.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
__malloc_unlock(struct _reent * ptr)
|
||||
{
|
||||
// Suppress compiler warning.
|
||||
(void) ptr;
|
||||
|
||||
if (!ulClibInitDone)
|
||||
return;
|
||||
|
||||
xSemaphoreGiveRecursive(xClibMutex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Lock for environment. Since we have only one global lock we can just call
|
||||
// the malloc() lock function.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
__env_lock(struct _reent * ptr)
|
||||
{
|
||||
__malloc_lock(ptr);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Unlock environment.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
__env_unlock(struct _reent * ptr)
|
||||
{
|
||||
__malloc_unlock(ptr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called by malloc() to allocate blocks of memory from the heap.
|
||||
//-----------------------------------------------------------------------------
|
||||
void *
|
||||
_sbrk_r (struct _reent * reent, int32_t incr)
|
||||
{
|
||||
extern char _end[];
|
||||
extern char _heap_sentry;
|
||||
static char * _heap_sentry_ptr = &_heap_sentry;
|
||||
static char * heap_ptr;
|
||||
char * base;
|
||||
|
||||
if (!heap_ptr)
|
||||
heap_ptr = (char *) &_end[0];
|
||||
|
||||
base = heap_ptr;
|
||||
if (heap_ptr + incr >= _heap_sentry_ptr) {
|
||||
reent->_errno = ENOMEM;
|
||||
return (char *) -1;
|
||||
}
|
||||
|
||||
heap_ptr += incr;
|
||||
return base;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global initialization for C library.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
vPortClibInit(void)
|
||||
{
|
||||
configASSERT(!ulClibInitDone);
|
||||
|
||||
xClibMutex = xSemaphoreCreateRecursiveMutex();
|
||||
ulClibInitDone = 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Per-thread cleanup stub provided for linking, does nothing.
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
_reclaim_reent(struct _reent * ptr)
|
||||
{
|
||||
(void ) ptr; /* Avoid compiler warning */
|
||||
}
|
||||
|
||||
#endif /* XSHAL_CLIB == XTHAL_CLIB_NEWLIB */
|
||||
|
||||
#endif /* XT_USE_THREAD_SAFE_CLIB */
|
||||
+447
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PORTMACRO_H
|
||||
#define PORTMACRO_H
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include "xtensa_rtos.h"
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <xtensa/tie/xt_core.h>
|
||||
#include <xtensa/hal.h>
|
||||
#include <xtensa/config/system.h> /* required for XSHAL_CLIB */
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Port specific definitions.
|
||||
*
|
||||
* The settings in this file configure FreeRTOS correctly for the
|
||||
* given hardware and compiler.
|
||||
*
|
||||
* These settings should not be altered.
|
||||
*-----------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Type definitions. */
|
||||
|
||||
#define portCHAR int8_t
|
||||
#define portFLOAT float
|
||||
#define portDOUBLE double
|
||||
#define portLONG int32_t
|
||||
#define portSHORT int16_t
|
||||
#define portSTACK_TYPE uint32_t
|
||||
#define portBASE_TYPE int
|
||||
|
||||
typedef portSTACK_TYPE StackType_t;
|
||||
typedef portBASE_TYPE BaseType_t;
|
||||
typedef unsigned portBASE_TYPE UBaseType_t;
|
||||
|
||||
#if( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
|
||||
typedef uint16_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffff
|
||||
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
|
||||
typedef uint32_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||
#else
|
||||
#error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
// portbenchmark
|
||||
#include "portbenchmark.h"
|
||||
|
||||
// Critical section management. These cannot be nested. They should be used
|
||||
// with a lot of care and cannot be called from interrupt context.
|
||||
static inline void
|
||||
portDISABLE_INTERRUPTS(void)
|
||||
{
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#if XCHAL_HAVE_XEA2
|
||||
xthal_intlevel_set_min (XT_IRQ_LOCK_LEVEL);
|
||||
#else
|
||||
xthal_disable_interrupts ();
|
||||
#endif
|
||||
#endif
|
||||
portbenchmarkINTERRUPT_DISABLE ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
portENABLE_INTERRUPTS(void)
|
||||
{
|
||||
portbenchmarkINTERRUPT_RESTORE (0);
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#if XCHAL_HAVE_XEA2
|
||||
xthal_intlevel_set (0);
|
||||
#else
|
||||
xthal_enable_interrupts ();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Nested critical sections. Nesting managed by FreeRTOS.
|
||||
// This is fine for a single core. TODO: revisit for SMP support.
|
||||
// NOTE: consider Espressif solution: GCC/Xtensa_ESP32/include/portmacro.h
|
||||
|
||||
#define portCRITICAL_NESTING_IN_TCB 1
|
||||
|
||||
extern void vTaskEnterCritical(void);
|
||||
extern void vTaskExitCritical(void);
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
|
||||
extern void vPortEnterCritical(void);
|
||||
extern void vPortExitCritical(void);
|
||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||
|
||||
#define portSTACK_ALIGNMENT XCHAL_MPU_ALIGN
|
||||
#define portPRIVILEGE_BIT 0x80000000UL
|
||||
#define portIS_PRIVILEGED() (int) \
|
||||
({ \
|
||||
register unsigned code __asm("a2") = SYSCALL_is_priv; \
|
||||
__asm volatile ("syscall\n" \
|
||||
: "+a"(code) :: "memory"); \
|
||||
code; \
|
||||
})
|
||||
#define portRAISE_PRIVILEGE() \
|
||||
do { \
|
||||
register unsigned code __asm("a2") = SYSCALL_raise_priv; \
|
||||
__asm volatile ("syscall\n" \
|
||||
: "+a"(code) :: "memory"); \
|
||||
} while (0)
|
||||
#if XCHAL_HAVE_XEA2
|
||||
#define portRESET_PRIVILEGE() (XT_WSR_PS(XT_RSR_PS() | PS_RING(1)))
|
||||
#else
|
||||
#define portRESET_PRIVILEGE() (XT_WSR_PS(XT_RSR_PS() | PS_RING))
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define portENTER_CRITICAL() vTaskEnterCritical()
|
||||
#define portEXIT_CRITICAL() vTaskExitCritical()
|
||||
#define portPRIVILEGE_BIT 0UL
|
||||
|
||||
#endif
|
||||
|
||||
// These allow nested interrupt disabling and restoring via local registers or stack.
|
||||
// They can be called from interrupts context.
|
||||
static inline uint32_t
|
||||
portENTER_CRITICAL_NESTED(void)
|
||||
{
|
||||
uint32_t state;
|
||||
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#if XCHAL_HAVE_XEA2
|
||||
state = xthal_intlevel_set_min (XT_IRQ_LOCK_LEVEL);
|
||||
#else
|
||||
state = xthal_disable_interrupts ();
|
||||
#endif
|
||||
#else
|
||||
state = 0;
|
||||
#endif
|
||||
portbenchmarkINTERRUPT_DISABLE ();
|
||||
return state;
|
||||
}
|
||||
|
||||
static inline void
|
||||
portEXIT_CRITICAL_NESTED(uint32_t state)
|
||||
{
|
||||
portbenchmarkINTERRUPT_RESTORE (state);
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#if XCHAL_HAVE_XEA2
|
||||
xthal_intlevel_set (state);
|
||||
#else
|
||||
xthal_restore_interrupts (state);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// These FreeRTOS versions are similar to the nested versions above
|
||||
#define portSET_INTERRUPT_MASK_FROM_ISR() portENTER_CRITICAL_NESTED()
|
||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state)
|
||||
BaseType_t xPortRaisePrivilege( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Architecture specifics. */
|
||||
#define portSTACK_GROWTH ( -1 )
|
||||
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
|
||||
#ifdef configBYTE_ALIGNMENT
|
||||
#define portBYTE_ALIGNMENT configBYTE_ALIGNMENT
|
||||
#elif XCHAL_DATA_WIDTH < 16
|
||||
#define portBYTE_ALIGNMENT XCHAL_DATA_WIDTH
|
||||
#else
|
||||
#define portBYTE_ALIGNMENT 16
|
||||
#endif
|
||||
#define portNOP() XT_NOP()
|
||||
#define portMEMORY_BARRIER() XT_MEMW()
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Fine resolution time */
|
||||
#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount()
|
||||
|
||||
/* No need to do anything for the ccount timer. */
|
||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() do {} while (0)
|
||||
|
||||
/* Kernel utilities. */
|
||||
void vPortYield( void );
|
||||
void _frxt_setup_switch( void );
|
||||
#define portYIELD() vPortYield()
|
||||
#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken ) \
|
||||
if ( ( xHigherPriorityTaskWoken ) != 0 ) { \
|
||||
_frxt_setup_switch(); \
|
||||
}
|
||||
|
||||
/* Tickless idle */
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
|
||||
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) \
|
||||
vPortSuppressTicksAndSleep( xExpectedIdleTime )
|
||||
#endif
|
||||
|
||||
#endif //__ASSEMBLER__
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Attributes for all the possible regions */
|
||||
|
||||
#define portDFLT_MEM_TYPE (XTHAL_MEM_BUFFERABLE | XTHAL_MEM_WRITEBACK)
|
||||
|
||||
#define portDFLT_STACK_TYPE portDFLT_MEM_TYPE
|
||||
#define portDFLT_STACK_ACCESS XTHAL_AR_RWrw
|
||||
|
||||
#define portDFLT_USERDEV_TYPE XTHAL_MEM_DEVICE
|
||||
#define portDFLT_USERDEV_ACCESS XTHAL_AR_RWXrwx
|
||||
|
||||
#define portDFLT_KERNDEV_TYPE XTHAL_MEM_DEVICE
|
||||
#define portDFLT_KERNDEV_ACCESS XTHAL_AR_RWX
|
||||
|
||||
#define portDFLT_SHARED_TYPE portDFLT_MEM_TYPE
|
||||
#define portDFLT_SHARED_ACCESS XTHAL_AR_RWXrwx
|
||||
|
||||
#define portDFLT_KERNCODE_TYPE portDFLT_MEM_TYPE
|
||||
#define portDFLT_KERNCODE_ACCESS XTHAL_AR_RX
|
||||
|
||||
#define portDFLT_KERNDATA_TYPE portDFLT_MEM_TYPE
|
||||
#define portDFLT_KERNDATA_ACCESS XTHAL_AR_RW
|
||||
|
||||
#define portDFLT_UNUSED_MEM_TYPE portDFLT_MEM_TYPE
|
||||
#define portDFLT_UNUSED_MEM_ACCESS XTHAL_AR_RWXrx
|
||||
|
||||
#define portNUM_CONFIGURABLE_REGIONS configNUM_CONFIGURABLE_REGIONS
|
||||
|
||||
#define portLEGACY_TASK_STACK_START (((uint32_t)_bss_start) & -XCHAL_MPU_ALIGN)
|
||||
#define portLEGACY_TASK_STACK_END (((uint32_t)_bss_end + XCHAL_MPU_ALIGN - 1) & -XCHAL_MPU_ALIGN)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* vPortStoreTaskMPUSettings returns void instead of BaseType_t. Until it's fixed
|
||||
* errors from that function can be checked using this global variable
|
||||
*/
|
||||
extern volatile int xtMPUError;
|
||||
|
||||
/* xtMPUError values
|
||||
*/
|
||||
typedef enum {
|
||||
MPU_ERR_SETUP_MPU = 1,
|
||||
MPU_ERR_REGION_NOT_IN_RANGE,
|
||||
MPU_ERR_STACK_NOT_IN_RANGE,
|
||||
MPU_ERR_OVERLAP_OTHER_REGIONS,
|
||||
MPU_ERR_FIXED_REGION_NOT_ALIGNED,
|
||||
MPU_ERR_PRIVATE_NOT_ALIGNED,
|
||||
MPU_ERR_INIT_ENTRY,
|
||||
MPU_ERR_INIT_ENTRY_NOT_IN_MAP,
|
||||
MPU_ERR_INIT_MAP_NOT_VALID
|
||||
} mpu_err_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*---------- DO NOT EDIT MPU SETTINGS BELOW ----------------*/
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
|
||||
#ifndef XCHAL_HAVE_MPU
|
||||
# define XCHAL_HAVE_MPU 0
|
||||
#endif
|
||||
|
||||
#if (XCHAL_HAVE_MPU == 0)
|
||||
# error "MPU Hardware required!"
|
||||
#endif
|
||||
|
||||
#ifndef portNUM_CONFIGURABLE_REGIONS
|
||||
# define portNUM_CONFIGURABLE_REGIONS 0
|
||||
#endif
|
||||
|
||||
#if defined(configUSER_DEVICE_START) && defined(configUSER_DEVICE_END)
|
||||
# define portUSE_USER_DEVICE_SPACE 1
|
||||
# else
|
||||
# define portUSE_USER_DEVICE_SPACE 0
|
||||
#endif
|
||||
|
||||
#if defined(configSHARED_DATA_START) && defined(configSHARED_DATA_END) && (portUSE_FIXED_MPU_ENTRIES == 1)
|
||||
# define portUSE_SHARED_DATA 1
|
||||
# else
|
||||
# define portUSE_SHARED_DATA 0
|
||||
#endif
|
||||
|
||||
#if defined(configPRIVILEGE_DEVICE_START) && defined(configPRIVILEGE_DEVICE_END)
|
||||
# define portUSE_PRIVILEGED_DEVICE_SPACE 1
|
||||
# else
|
||||
# define portUSE_PRIVILEGED_DEVICE_SPACE 0
|
||||
#endif
|
||||
|
||||
#if defined(configLEGACY_TASK_STACK_START) && defined(configLEGACY_TASK_STACK_END)
|
||||
# define portLEGACY_UNPRIVILEGED_TASKS 1
|
||||
# else
|
||||
# define portLEGACY_UNPRIVILEGED_TASKS 0
|
||||
#endif
|
||||
|
||||
/* Number of MPU entries a restricted thread will use. */
|
||||
#define portNUM_USED_MPU_ENTRIES (1 /* entry zero*/ + \
|
||||
2* ( portNUM_CONFIGURABLE_REGIONS + \
|
||||
portUSE_USER_DEVICE_SPACE + \
|
||||
portUSE_PRIVILEGED_DEVICE_SPACE + \
|
||||
portUSE_SHARED_DATA + \
|
||||
portLEGACY_UNPRIVILEGED_TASKS + \
|
||||
1 /*stack*/ + \
|
||||
1 /*FreeRTOS code */ + \
|
||||
1 /*FreeRTOS data */ \
|
||||
))
|
||||
|
||||
#define portNUM_MAX_SWAPPED_MPU_PAIRS (portNUM_CONFIGURABLE_REGIONS + \
|
||||
portLEGACY_UNPRIVILEGED_TASKS + 1)
|
||||
|
||||
#if XCHAL_MPU_ENTRIES < 16
|
||||
# error "MPU entries < 16 is not supported"
|
||||
#endif
|
||||
#if XCHAL_MPU_ENTRIES < portNUM_USED_MPU_ENTRIES
|
||||
# error "Require MPU with at least portNUM_USED_MPU_ENTRIES foreground entries"
|
||||
#endif
|
||||
#if XCHAL_MPU_ALIGN > 16384
|
||||
# error "MPU region alignment > 16384 is not supported"
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
extern uint32_t privileged_data_start[];
|
||||
extern uint32_t privileged_data_end[];
|
||||
extern uint32_t privileged_functions_start[];
|
||||
extern uint32_t privileged_functions_end[];
|
||||
extern uint32_t _bss_start[];
|
||||
extern uint32_t _bss_end[];
|
||||
|
||||
#define portPRIVILEGED_CODE_START ((uint32_t)privileged_functions_start & (uint32_t)-XCHAL_MPU_ALIGN)
|
||||
#define portPRIVILEGED_CODE_END (((uint32_t)privileged_functions_end + (XCHAL_MPU_ALIGN - 1)) & (uint32_t)-XCHAL_MPU_ALIGN)
|
||||
#define portPRIVILEGED_DATA_START ((uint32_t)privileged_data_start & (uint32_t)-XCHAL_MPU_ALIGN)
|
||||
#define portPRIVILEGED_DATA_END (((uint32_t)privileged_data_end + (XCHAL_MPU_ALIGN - 1)) & (uint32_t)-XCHAL_MPU_ALIGN)
|
||||
|
||||
typedef struct {
|
||||
// Define here mpu_settings, which is port dependent
|
||||
xthal_MPU_entry mpumap[portNUM_MAX_SWAPPED_MPU_PAIRS][2];
|
||||
} xMPU_SETTINGS;
|
||||
|
||||
#endif //ASSEMBLER
|
||||
|
||||
#endif //portUSING_MPU_WRAPPERS
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* 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 )
|
||||
|
||||
// porttrace
|
||||
#if configUSE_TRACE_FACILITY_2
|
||||
#include "porttrace.h"
|
||||
#endif
|
||||
|
||||
// configASSERT_2 if requested
|
||||
#if configASSERT_2
|
||||
#include <stdio.h>
|
||||
void exit(int);
|
||||
#define configASSERT( x ) if (!(x)) { porttracePrint(-1); printf("\nAssertion failed in %s:%d\n", __FILE__, __LINE__); exit(-1); }
|
||||
#endif
|
||||
|
||||
/* Task delete hook for cleanup. May be an issue if tracing is also needed. */
|
||||
#define traceTASK_DELETE(pxTCB) portTaskDeleteHook(pxTCB->pxEndOfStack)
|
||||
|
||||
static inline void portTaskDeleteHook(void * ptr)
|
||||
{
|
||||
#if XCHAL_CP_NUM > 0
|
||||
/* Release any owned coprocessors. If the owner save area address
|
||||
matches the address in 'ptr' then we are the owner, set to NULL. */
|
||||
if (ptr != NULL) {
|
||||
extern void * _xt_coproc_owner_sa[XCHAL_CP_MAX];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < XCHAL_CP_MAX; i++) {
|
||||
if (_xt_coproc_owner_sa[i] == ptr) {
|
||||
_xt_coproc_owner_sa[i] = NULL;
|
||||
}
|
||||
#if (defined XT_DEBUG)
|
||||
/* Only for testing / debugging */
|
||||
if (_xt_coproc_owner_sa[i] == (void *)0xf1f1f1f1) {
|
||||
_xt_coproc_owner_sa[i] = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* C library support -- only XCLIB and NEWLIB are supported. */
|
||||
|
||||
/* To enable thread-safe C library support, XT_USE_THREAD_SAFE_CLIB must be
|
||||
defined to be > 0 somewhere above or on the command line. */
|
||||
|
||||
#if (XT_USE_THREAD_SAFE_CLIB > 0u) && ((XSHAL_CLIB == XTHAL_CLIB_XCLIB) || (XSHAL_CLIB == XTHAL_CLIB_NEWLIB))
|
||||
extern void vPortClibInit(void);
|
||||
#endif // XCLIB || NEWLIB support
|
||||
|
||||
#endif // __ASSEMBLER__
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* PORTMACRO_H */
|
||||
+618
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <xtensa/config/core.h>
|
||||
#include <xtensa/core-macros.h>
|
||||
#include "asm-offsets.h"
|
||||
#include "xtensa_rtos.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <xtensa/xtutil.h>
|
||||
# define XPRINT(...) \
|
||||
(xt_printf(__VA_ARGS__))
|
||||
#else
|
||||
# define XPRINT(...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
/* FIXME - this one is needed to spot the error from user threads until
|
||||
* FreeRTOS is fixed to return BaseType_t from functions here, not void.
|
||||
*/
|
||||
volatile int PRIVILEGED_DATA xtMPUError = 0;
|
||||
|
||||
/* Actual number of private regions that will be used
|
||||
*/
|
||||
volatile int PRIVILEGED_DATA g_num_used_mpu_entries = 0;
|
||||
|
||||
/* pdFAIL commented out until the function is fixed to return BaseType_t not void
|
||||
*/
|
||||
#define NAME(a) #a
|
||||
#define FAIL_VOID_RETURN(errnum) \
|
||||
do { \
|
||||
XPRINT("*FreeRTOS* Error: %s\n", NAME(errnum)); \
|
||||
xtMPUError = errnum; \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
typedef struct privateDetails_struct {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
uint32_t index;
|
||||
} privateDetails_t;
|
||||
|
||||
/* Stores initial private mappings allocated by MPUSetup thread. Must be global
|
||||
* as they'll be used later for old-style threads
|
||||
*/
|
||||
static volatile privateDetails_t
|
||||
g_privateDetails[portNUM_MAX_SWAPPED_MPU_PAIRS] PRIVILEGED_DATA;
|
||||
|
||||
#define PRIVATE_LEGACY_STACK_IDX 0
|
||||
#define PRIVATE_STACK_IDX (portLEGACY_UNPRIVILEGED_TASKS)
|
||||
#define PRIVATE_CONFIGURABLE_IDX (1 + PRIVATE_STACK_IDX)
|
||||
|
||||
#define MPU_ALIGN_DOWN(v) ((uint32_t)(v) & -XCHAL_MPU_ALIGN)
|
||||
#define MPU_ALIGN_UP(v) (((uint32_t)(v) + XCHAL_MPU_ALIGN - 1) & -XCHAL_MPU_ALIGN)
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Check if a region is aligned according to MPU requirements
|
||||
*/
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
region_mpu_aligned(uint32_t start, uint32_t end)
|
||||
{
|
||||
if ((start & (XCHAL_MPU_ALIGN - 1)) || (end & (XCHAL_MPU_ALIGN - 1))) {
|
||||
XPRINT("Region %x/%x not aligned\n", start, end);
|
||||
return pdFALSE;
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
region_within_region(uint32_t start, uint32_t end, uint32_t rstart, uint32_t rend)
|
||||
{
|
||||
return (start >= rstart) && (end <= rend);
|
||||
}
|
||||
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
region_overlaps_region(uint32_t start, uint32_t end, uint32_t rstart, uint32_t rend)
|
||||
{
|
||||
return (start < rend) && (end > rstart);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a private region/stack is overlapping any other region
|
||||
*/
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
private_overlap_other_regions(const struct xMEMORY_REGION * const xRegions,
|
||||
StackType_t *pxBottomOfStack, uint32_t stackSizeInBytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < portNUM_CONFIGURABLE_REGIONS + 1; i++) {
|
||||
uint32_t start, end;
|
||||
|
||||
if (!xRegions)
|
||||
i = portNUM_CONFIGURABLE_REGIONS;
|
||||
|
||||
if (i == portNUM_CONFIGURABLE_REGIONS) {
|
||||
start = (uint32_t)pxBottomOfStack;
|
||||
end = (uint32_t)pxBottomOfStack + stackSizeInBytes;
|
||||
} else {
|
||||
start = (uint32_t)xRegions[i].pvBaseAddress;
|
||||
end = (uint32_t)(xRegions[i].pvBaseAddress) + xRegions[i].ulLengthInBytes;
|
||||
}
|
||||
|
||||
if (start == 0 && end == 0) {
|
||||
/* Unused private entries - by design they are placed in MPU so they
|
||||
* don't affect the mapping. Check might fail for them so just don't do it.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (portUSE_SHARED_DATA == 1)
|
||||
if (region_overlaps_region(start, end,
|
||||
(uint32_t)configSHARED_DATA_START,
|
||||
(uint32_t)configSHARED_DATA_END)) {
|
||||
XPRINT("private region %d overlaps shared data!\n", i);
|
||||
return pdTRUE;
|
||||
}
|
||||
#endif
|
||||
#if (portUSE_PRIVILEGED_DEVICE_SPACE == 1)
|
||||
if (region_overlaps_region(start, end,
|
||||
(uint32_t)configPRIVILEGE_DEVICE_START,
|
||||
(uint32_t)configPRIVILEGE_DEVICE_END)) {
|
||||
XPRINT("private region %d overlaps privileged device space!\n", i);
|
||||
return pdTRUE;
|
||||
}
|
||||
#endif
|
||||
#if (portUSE_USER_DEVICE_SPACE == 1)
|
||||
if (region_overlaps_region(start, end,
|
||||
(uint32_t)configUSER_DEVICE_START,
|
||||
(uint32_t)configUSER_DEVICE_END)) {
|
||||
XPRINT("private region %d overlaps user device space!\n", i);
|
||||
return pdTRUE;
|
||||
}
|
||||
#endif
|
||||
#if (portLEGACY_UNPRIVILEGED_TASKS)
|
||||
if (region_overlaps_region(start, end,
|
||||
configLEGACY_TASK_STACK_START,
|
||||
configLEGACY_TASK_STACK_END)) {
|
||||
XPRINT("private region %d [%08x - %08x[ overlaps legacy tack stacks!\n", i, start, end);
|
||||
return pdTRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (region_overlaps_region(start, end,
|
||||
(uint32_t)portPRIVILEGED_CODE_START,
|
||||
(uint32_t)portPRIVILEGED_CODE_END)) {
|
||||
XPRINT("private region %d overlaps FreeRTOS code!\n", i);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
if (region_overlaps_region(start, end,
|
||||
(uint32_t)portPRIVILEGED_DATA_START,
|
||||
(uint32_t)portPRIVILEGED_DATA_END)) {
|
||||
XPRINT("private region %d overlaps FreeRTOS code!\n", i);
|
||||
return pdTRUE;
|
||||
}
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if all fixed regions are aligned according to MPU requirements
|
||||
*/
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
mpu_fixed_regions_aligned(void)
|
||||
{
|
||||
#if (portUSE_SHARED_DATA == 1)
|
||||
if (!region_mpu_aligned((uint32_t)configSHARED_DATA_START,
|
||||
(uint32_t)configSHARED_DATA_END)) {
|
||||
XPRINT("shared region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
#endif
|
||||
#if (portUSE_PRIVILEGED_DEVICE_SPACE == 1)
|
||||
if (!region_mpu_aligned((uint32_t)configPRIVILEGE_DEVICE_START,
|
||||
(uint32_t)configPRIVILEGE_DEVICE_END)) {
|
||||
XPRINT("priv device region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
#endif
|
||||
#if (portUSE_USER_DEVICE_SPACE == 1)
|
||||
if (!region_mpu_aligned((uint32_t)configUSER_DEVICE_START,
|
||||
(uint32_t)configUSER_DEVICE_END)) {
|
||||
XPRINT("user dev region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
#endif
|
||||
#if (portLEGACY_UNPRIVILEGED_TASKS)
|
||||
if (!region_mpu_aligned(configLEGACY_TASK_STACK_START,
|
||||
configLEGACY_TASK_STACK_END)) {
|
||||
XPRINT("legacy stacks region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!region_mpu_aligned((uint32_t)portPRIVILEGED_CODE_START,
|
||||
(uint32_t)portPRIVILEGED_CODE_END)) {
|
||||
XPRINT("priv code region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
if(!region_mpu_aligned((uint32_t)portPRIVILEGED_DATA_START,
|
||||
(uint32_t)portPRIVILEGED_DATA_END)) {
|
||||
XPRINT("priv data region not aligned\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
static void PRIVILEGED_FUNCTION
|
||||
add_mpu_entry_to_TCB(xthal_MPU_entry mpumap[], uint32_t addr, uint32_t attr,
|
||||
uint32_t type, uint32_t start)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
//first check if in order
|
||||
if (addr & (XCHAL_MPU_ALIGN - 1)) {
|
||||
XPRINT ("Entry addr:%x aligned to %x!\n", addr, XCHAL_MPU_ALIGN);
|
||||
addr &= (uint32_t)-XCHAL_MPU_ALIGN;
|
||||
}
|
||||
|
||||
for (index = XCHAL_MPU_ENTRIES - 1; index >= 0; index--) {
|
||||
|
||||
/* If already have the same entry check if we are start or end of a segment.
|
||||
* If start then simply override the matching entry.
|
||||
* If end, don't add new entry
|
||||
*/
|
||||
if ((addr >= (mpumap[index].as & ~0x1U) && start) ||
|
||||
(addr > (mpumap[index].as & ~0x1U) && !start)) {
|
||||
//move others down
|
||||
//FIXME - see not to move everything but only entries added so far
|
||||
memmove(mpumap, mpumap + 1, sizeof(xthal_MPU_entry) * (uint32_t)index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
mpumap[index] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(addr, 1, attr, type);
|
||||
}
|
||||
}
|
||||
|
||||
static int PRIVILEGED_FUNCTION
|
||||
find_addr_in_map(xthal_MPU_entry mpumap[], uint32_t addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = XCHAL_MPU_ENTRIES - 1; i >= 0; i--) {
|
||||
if (addr >= (mpumap[i].as & ~0x1U))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
/* Need to setup MPU so the lower, unused, entries have as=1.
|
||||
* The function is called from either vPortStoreTaskMPUSettings or prvSetupMPU,
|
||||
* whichever gets executed first. Former is called when thread is created which
|
||||
* might happen before the scheduler start (which calls the latter).
|
||||
*/
|
||||
static BaseType_t PRIVILEGED_FUNCTION
|
||||
setupMPU(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
xthal_MPU_entry mpumap[XCHAL_MPU_ENTRIES];
|
||||
|
||||
/* set all MPU entries to as=0x1,privileged */
|
||||
for (i = 0; i < XCHAL_MPU_ENTRIES; i++) {
|
||||
mpumap[i] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(0, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
}
|
||||
|
||||
XPRINT("PRIV FUNC SPACE defined:%x-%x (section:%x-%x)\n", portPRIVILEGED_CODE_START, portPRIVILEGED_CODE_END, (uint32_t)privileged_functions_start, (uint32_t)privileged_functions_end);
|
||||
XPRINT("PRIV DATA SPACE define:%x-%x (section:%x-%x)\n", portPRIVILEGED_DATA_START, portPRIVILEGED_DATA_END, (uint32_t)privileged_data_start, (uint32_t)privileged_data_end);
|
||||
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) portPRIVILEGED_CODE_START, portDFLT_KERNCODE_ACCESS, portDFLT_KERNCODE_TYPE, 1);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) portPRIVILEGED_CODE_END, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) portPRIVILEGED_DATA_START, portDFLT_KERNDATA_ACCESS, portDFLT_KERNDATA_TYPE, 1);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) portPRIVILEGED_DATA_END, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
|
||||
#if (portUSE_PRIVILEGED_DEVICE_SPACE == 1)
|
||||
XPRINT("PRIV Device Space %x - %x\n", configPRIVILEGE_DEVICE_START, configPRIVILEGE_DEVICE_END);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configPRIVILEGE_DEVICE_START, portDFLT_KERNDEV_ACCESS, portDFLT_KERNDEV_TYPE, 1);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configPRIVILEGE_DEVICE_END, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
#endif
|
||||
#if (portUSE_USER_DEVICE_SPACE == 1)
|
||||
XPRINT("USER Device Space %x - %x\n", configUSER_DEVICE_START, configUSER_DEVICE_END);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configUSER_DEVICE_START, portDFLT_USERDEV_ACCESS, portDFLT_USERDEV_TYPE, 1);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configUSER_DEVICE_END, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
#endif
|
||||
#if (portUSE_SHARED_DATA == 1)
|
||||
XPRINT("Shared Data Section: %x - %x\n", configSHARED_DATA_START, configSHARED_DATA_END);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configSHARED_DATA_START, portDFLT_SHARED_ACCESS, portDFLT_SHARED_TYPE, 1); //FIXME - check priv/type
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t) configSHARED_DATA_END, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
#endif
|
||||
|
||||
for(i = 0; i < g_num_used_mpu_entries; i++) {
|
||||
XPRINT("Private Data Section %d: %x - %x \n", i, g_privateDetails[i].start , g_privateDetails[i].end);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t)g_privateDetails[i].start, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 1);
|
||||
add_mpu_entry_to_TCB(mpumap, (uint32_t)g_privateDetails[i].end, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < XCHAL_MPU_ENTRIES; i++) {
|
||||
mpumap[i].at &= (uint32_t)-XCHAL_MPU_ENTRIES;
|
||||
mpumap[i].at |= (uint32_t)i;
|
||||
}
|
||||
|
||||
int map_status = xthal_check_map(mpumap, XCHAL_MPU_ENTRIES);
|
||||
if (map_status != XTHAL_SUCCESS) {
|
||||
xtMPUError = MPU_ERR_INIT_MAP_NOT_VALID;
|
||||
XPRINT("MPU Map Check FAILED: error:%d\n", map_status);
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
xthal_write_map(mpumap, XCHAL_MPU_ENTRIES);
|
||||
|
||||
#ifdef DEBUG
|
||||
xthal_read_map(mpumap);
|
||||
for (i = 0; i < XCHAL_MPU_ENTRIES; i++) {
|
||||
XPRINT("ORIG mpumap[%d]: as:%x, at:%x\n", i, mpumap[i].as, mpumap[i].at);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Find entries for private memories
|
||||
for(i = 0; i < g_num_used_mpu_entries; i++) {
|
||||
int index;
|
||||
|
||||
XPRINT("Look for addr %x\n", g_privateDetails[i].start);
|
||||
|
||||
// If MPU Setup decided not to use a region, it set it to 0-0. Then,
|
||||
// just swap entries 0,1. In the future, assign a variable telling how
|
||||
// much to swap and don't even swap those for zero.
|
||||
if (g_privateDetails[i].start == 0) {
|
||||
g_privateDetails[i].index = 0;
|
||||
continue;
|
||||
}
|
||||
index = find_addr_in_map(mpumap, g_privateDetails[i].start);
|
||||
if (index < 0) {
|
||||
XPRINT("Couldn't find index for addr %x\n", g_privateDetails[i].start);
|
||||
xtMPUError = MPU_ERR_INIT_ENTRY_NOT_IN_MAP;
|
||||
return pdFALSE;
|
||||
}
|
||||
g_privateDetails[i].index = (uint32_t)index;
|
||||
}
|
||||
|
||||
// Update range if not set by MPU thread, to be from the previous to the next entry
|
||||
#if DEBUG
|
||||
for(i = 0; i < g_num_used_mpu_entries; i++) {
|
||||
XPRINT("Entry %d index: %d, range: %x-%x\n", i, g_privateDetails[i].index, g_privateDetails[i].start, g_privateDetails[i].end);
|
||||
}
|
||||
#endif
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
/* Called from xPortStartScheduler. At that time, some threads might have
|
||||
* been created already, which required them creating the MPU map, as their
|
||||
* private regions must be checked against it. So, create MPU map is called
|
||||
* from either parts, but it'll run only once.
|
||||
* In this function, we also write the MPU with that map.
|
||||
*/
|
||||
BaseType_t PRIVILEGED_FUNCTION
|
||||
prvSetupMPU(void)
|
||||
{
|
||||
xthal_dcache_all_writeback_inv();
|
||||
xthal_icache_all_invalidate();
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
typedef void TCB_t;
|
||||
extern volatile TCB_t * volatile pxCurrentTCB;
|
||||
|
||||
static void PRIVILEGED_FUNCTION
|
||||
init_private_mpu_regions(const struct xMEMORY_REGION * const xRegions,
|
||||
StackType_t *pxBottomOfStack, uint32_t stackSizeInBytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First do checks - if there is overlap or fixed regions not aligned */
|
||||
if (mpu_fixed_regions_aligned() == pdFALSE) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_FIXED_REGION_NOT_ALIGNED);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
XPRINT("INITIAL MPU SETTINGS:\n"
|
||||
"stack: %08x - %08x\n",
|
||||
(uint32_t)pxBottomOfStack,
|
||||
(uint32_t)pxBottomOfStack + stackSizeInBytes);
|
||||
#if portLEGACY_UNPRIVILEGED_TASKS
|
||||
XPRINT("legacy stack: %08x - %08x\n",
|
||||
configLEGACY_TASK_STACK_START,
|
||||
configLEGACY_TASK_STACK_END);
|
||||
#endif
|
||||
XPRINT("REGIONS:\n");
|
||||
for (i = 0; i < portNUM_CONFIGURABLE_REGIONS; i++) {
|
||||
XPRINT(" %08x - %08x\n",
|
||||
(uint32_t)xRegions[i].pvBaseAddress,
|
||||
(uint32_t)(xRegions[i].pvBaseAddress + xRegions[i].ulLengthInBytes));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if portLEGACY_UNPRIVILEGED_TASKS
|
||||
g_privateDetails[PRIVATE_LEGACY_STACK_IDX].start = configLEGACY_TASK_STACK_START;
|
||||
g_privateDetails[PRIVATE_LEGACY_STACK_IDX].end = configLEGACY_TASK_STACK_END;
|
||||
#endif
|
||||
|
||||
if (stackSizeInBytes) {
|
||||
/* Have addresses ready - update private entries - index comes later */
|
||||
g_privateDetails[PRIVATE_STACK_IDX].start = (uint32_t)pxBottomOfStack;
|
||||
g_privateDetails[PRIVATE_STACK_IDX].end = (uint32_t)pxBottomOfStack + stackSizeInBytes;
|
||||
|
||||
for (i = 0; i < portNUM_CONFIGURABLE_REGIONS; i++) {
|
||||
if(xRegions[i].pvBaseAddress == 0 && xRegions[i].ulLengthInBytes == 0) {
|
||||
break;
|
||||
}
|
||||
g_privateDetails[i + PRIVATE_CONFIGURABLE_IDX].start = (uint32_t)(xRegions[i].pvBaseAddress);
|
||||
g_privateDetails[i + PRIVATE_CONFIGURABLE_IDX].end = (uint32_t)(xRegions[i].pvBaseAddress) + xRegions[i].ulLengthInBytes;
|
||||
}
|
||||
g_num_used_mpu_entries = i + PRIVATE_CONFIGURABLE_IDX;
|
||||
} else {
|
||||
g_num_used_mpu_entries = portLEGACY_UNPRIVILEGED_TASKS;
|
||||
}
|
||||
|
||||
XPRINT("Will use %d regions out of %d allowed\n",
|
||||
g_num_used_mpu_entries < PRIVATE_CONFIGURABLE_IDX ?
|
||||
0 : g_num_used_mpu_entries - PRIVATE_CONFIGURABLE_IDX,
|
||||
portNUM_CONFIGURABLE_REGIONS);
|
||||
|
||||
if (setupMPU() == pdFAIL) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_SETUP_MPU);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void PRIVILEGED_FUNCTION
|
||||
init_task_mpu(xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions,
|
||||
StackType_t *pxBottomOfStack, uint32_t stackSizeInBytes)
|
||||
{
|
||||
int i;
|
||||
xthal_MPU_entry (*mpumap)[2] = xMPUSettings->mpumap;
|
||||
|
||||
#ifdef DEBUG
|
||||
int name_offset = TCB_TASK_NAME_OFF - TCB_MPU_SETTINGS_OFF;
|
||||
XPRINT("\n\nTASK NAME: '%s'\n", (char*)xMPUSettings + name_offset);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
XPRINT("PRIVATE: stackBottom:%p, stackSizeBytes:%d, REGIONS (%p):\n",
|
||||
pxBottomOfStack, stackSizeInBytes, xRegions);
|
||||
if (xRegions) {
|
||||
for (i = 0; i < portNUM_CONFIGURABLE_REGIONS; i++)
|
||||
XPRINT(" %x-%x\n",
|
||||
(uint32_t)xRegions[i].pvBaseAddress,
|
||||
(uint32_t)(xRegions[i].pvBaseAddress + xRegions[i].ulLengthInBytes));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (xRegions) {
|
||||
|
||||
/* first check if private regions are aligned or overlap fixed regions. */
|
||||
if (private_overlap_other_regions(xRegions, pxBottomOfStack, stackSizeInBytes) == pdTRUE) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_OVERLAP_OTHER_REGIONS);
|
||||
}
|
||||
|
||||
if (region_mpu_aligned((uint32_t)pxBottomOfStack,
|
||||
(uint32_t)pxBottomOfStack + stackSizeInBytes) == pdFALSE) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_PRIVATE_NOT_ALIGNED);
|
||||
}
|
||||
|
||||
for (i = 0; i < g_num_used_mpu_entries - PRIVATE_CONFIGURABLE_IDX; i++) {
|
||||
if (region_mpu_aligned((uint32_t)(xRegions[i].pvBaseAddress),
|
||||
(uint32_t)(xRegions[i].pvBaseAddress) + xRegions[i].ulLengthInBytes) == pdFALSE) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_PRIVATE_NOT_ALIGNED);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set stack MPU mapping */
|
||||
|
||||
if (region_within_region((uint32_t)pxBottomOfStack,
|
||||
(uint32_t)pxBottomOfStack + stackSizeInBytes,
|
||||
g_privateDetails[PRIVATE_STACK_IDX].start,
|
||||
g_privateDetails[PRIVATE_STACK_IDX].end) == pdFALSE) {
|
||||
FAIL_VOID_RETURN(MPU_ERR_STACK_NOT_IN_RANGE);
|
||||
}
|
||||
|
||||
for (i = 0; i < g_num_used_mpu_entries - PRIVATE_CONFIGURABLE_IDX; i++) {
|
||||
if (region_within_region((uint32_t)xRegions[i].pvBaseAddress,
|
||||
(uint32_t)xRegions[i].pvBaseAddress + xRegions[i].ulLengthInBytes,
|
||||
g_privateDetails[i + PRIVATE_CONFIGURABLE_IDX].start,
|
||||
g_privateDetails[i + PRIVATE_CONFIGURABLE_IDX].end) == pdFALSE)
|
||||
FAIL_VOID_RETURN(MPU_ERR_REGION_NOT_IN_RANGE);
|
||||
}
|
||||
|
||||
mpumap[PRIVATE_STACK_IDX][0] = (xthal_MPU_entry)XTHAL_MPU_ENTRY((uint32_t)pxBottomOfStack, 1, portDFLT_STACK_ACCESS, portDFLT_STACK_TYPE);
|
||||
mpumap[PRIVATE_STACK_IDX][1] = (xthal_MPU_entry)XTHAL_MPU_ENTRY((uint32_t)pxBottomOfStack + stackSizeInBytes, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[PRIVATE_STACK_IDX][0].at |= g_privateDetails[PRIVATE_STACK_IDX].index;
|
||||
mpumap[PRIVATE_STACK_IDX][1].at |= g_privateDetails[PRIVATE_STACK_IDX].index + 1;
|
||||
|
||||
#if portLEGACY_UNPRIVILEGED_TASKS
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][0] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(configLEGACY_TASK_STACK_START, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][1] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(configLEGACY_TASK_STACK_END , 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][0].at |= g_privateDetails[PRIVATE_LEGACY_STACK_IDX].index;
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][1].at |= g_privateDetails[PRIVATE_LEGACY_STACK_IDX].index + 1;
|
||||
#endif
|
||||
/* Set MPU mappings for private memories */
|
||||
|
||||
for (i = PRIVATE_CONFIGURABLE_IDX; i < g_num_used_mpu_entries; i++) {
|
||||
int region_i = i - PRIVATE_CONFIGURABLE_IDX;
|
||||
|
||||
uint32_t start = (uint32_t)(xRegions[region_i].pvBaseAddress);
|
||||
uint32_t end = (uint32_t)(xRegions[region_i].pvBaseAddress) + xRegions[region_i].ulLengthInBytes;
|
||||
|
||||
uint32_t privType = xRegions[region_i].ulParameters & 0xFFFFE000; // FIXME - use hal functions for these 2
|
||||
uint32_t privAccess = xRegions[region_i].ulParameters & 0x00000FFF;
|
||||
|
||||
if (start == 0 && end == 0) {
|
||||
start = g_privateDetails[i].start;
|
||||
end = g_privateDetails[i].end;
|
||||
privAccess = portDFLT_UNUSED_MEM_ACCESS;
|
||||
privType = portDFLT_UNUSED_MEM_TYPE;
|
||||
}
|
||||
mpumap[i][0] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(start, 1, privAccess, privType);
|
||||
mpumap[i][1] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(end, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[i][0].at |= g_privateDetails[i].index;
|
||||
mpumap[i][1].at |= g_privateDetails[i].index + 1;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < g_num_used_mpu_entries; i++) {
|
||||
mpumap[i][0] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(g_privateDetails[i].start, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[i][0].at |= g_privateDetails[i].index;
|
||||
mpumap[i][1] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(g_privateDetails[i].end, 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[i][1].at |= g_privateDetails[i].index + 1;
|
||||
}
|
||||
#if portLEGACY_UNPRIVILEGED_TASKS
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][0] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(MPU_ALIGN_DOWN(pxBottomOfStack), 1, portDFLT_STACK_ACCESS, portDFLT_STACK_TYPE);
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][1] = (xthal_MPU_entry)XTHAL_MPU_ENTRY(MPU_ALIGN_UP((uint32_t)pxBottomOfStack + stackSizeInBytes), 1, portDFLT_UNUSED_MEM_ACCESS, portDFLT_UNUSED_MEM_TYPE);
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][0].at |= g_privateDetails[PRIVATE_LEGACY_STACK_IDX].index;
|
||||
mpumap[PRIVATE_LEGACY_STACK_IDX][1].at |= g_privateDetails[PRIVATE_LEGACY_STACK_IDX].index + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < g_num_used_mpu_entries; i++) {
|
||||
XPRINT("mpumap[%d]: as:%x, at:%x\n", i * 2 + 0, mpumap[i][0].as, mpumap[i][0].at);
|
||||
XPRINT("mpumap[%d]: as:%x, at:%x\n", i * 2 + 1, mpumap[i][1].as, mpumap[i][1].at);
|
||||
}
|
||||
XPRINT("\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.
|
||||
*/
|
||||
void PRIVILEGED_FUNCTION
|
||||
vPortStoreTaskMPUSettings(xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions,
|
||||
StackType_t *pxBottomOfStack, uint32_t ulStackDepth)
|
||||
{
|
||||
static int PRIVILEGED_DATA mpu_init_done = 0;
|
||||
uint32_t stackSizeInBytes = ulStackDepth * sizeof(int);
|
||||
|
||||
/* if !xMPUSettings this is initial call to set private region ranges */
|
||||
|
||||
if (!mpu_init_done) {
|
||||
mpu_init_done = 1;
|
||||
if (!xMPUSettings) {
|
||||
init_private_mpu_regions(xRegions, pxBottomOfStack, stackSizeInBytes);
|
||||
} else {
|
||||
MemoryRegion_t mpuPrivRegions[portNUM_CONFIGURABLE_REGIONS] = {
|
||||
#if portNUM_CONFIGURABLE_REGIONS > 0
|
||||
{0, 0, 0},
|
||||
#endif
|
||||
};
|
||||
init_private_mpu_regions(mpuPrivRegions, 0, 0);
|
||||
}
|
||||
}
|
||||
if (xMPUSettings) {
|
||||
init_task_mpu(xMPUSettings, xRegions, pxBottomOfStack, stackSizeInBytes);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This utility helps tracing the entering and exiting from tasks.
|
||||
* It maintains a circular buffer of tasks in the order they execute,
|
||||
* and their execution time. To enable it, set configUSE_TRACE_FACILITY_2
|
||||
* to 1 in FreeRTOSConfig.h. You will also need to download the
|
||||
* FreeRTOS_trace patch that contains porttrace.c and the complete version
|
||||
* of porttrace.h.
|
||||
*/
|
||||
|
||||
#ifndef PORTTRACE_H
|
||||
#define PORTTRACE_H
|
||||
|
||||
#if configUSE_TRACE_FACILITY_2
|
||||
#error "You need to download the FreeRTOS_trace patch that overwrites this file"
|
||||
#endif
|
||||
|
||||
#define porttracePrint(nelements)
|
||||
#define porttraceStamp(stamp, count_incr)
|
||||
|
||||
#endif /* PORTTRACE_H */
|
||||
+769
@@ -0,0 +1,769 @@
|
||||
FreeRTOS Port for Xtensa Configurable Processors
|
||||
================================================
|
||||
|
||||
FreeRTOS Kernel Version 11.0.0
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This document describes the Xtensa port for FreeRTOS multitasking RTOS.
|
||||
For an introduction to FreeRTOS itself, please refer to FreeRTOS
|
||||
documentation.
|
||||
|
||||
This port currently works with FreeRTOS kernel version 11.0.0.
|
||||
|
||||
|
||||
Xtensa Configuration Requirements and Restrictions
|
||||
--------------------------------------------------
|
||||
|
||||
The Xtensa configurable architecture supports a vast space of processor
|
||||
features. This port supports all of them, including custom processor
|
||||
extensions defined in the TIE language, with certain minimum
|
||||
requirements. You must use Xtensa Tools to compile and link FreeRTOS and
|
||||
your application for your Xtensa configuration. The port uses the Xtensa
|
||||
Hardware Abstraction Layer (HAL) to adapt to your Xtensa configuration.
|
||||
NOTE: It may be possible to build and run this with the open-source
|
||||
xtensa-linux tools provided you have the correct overlay for your Xtensa
|
||||
configuration. However, this has not been tested and is currently not
|
||||
supported by Cadence.
|
||||
|
||||
This port includes optional reentrancy support for the 'newlib' and
|
||||
'xclib' C runtime libraries distributed with Xtensa Tools, providing
|
||||
thread-safety on a per task basis (for use in tasks only, not interrupt
|
||||
handlers).
|
||||
|
||||
This port also includes a simple example application that may run on
|
||||
a supported board or the Xtensa instruction set simulator (ISS). There
|
||||
are also a couple of test programs used in maintaining the port, which
|
||||
serve as additional examples.
|
||||
|
||||
FreeRTOS for Xtensa configurable processors requires the following minimum
|
||||
processor configuration options:
|
||||
|
||||
- Timer interrupt option with at least one timer.
|
||||
- Interrupt option (implied by the timer interrupt option).
|
||||
- Exception Architecture Version 2 (XEA2) or Version 3 (XEA3).
|
||||
- Little-endian byte ordering (XEA2 cores).
|
||||
|
||||
Minimal support for certain evaluation boards is provided via a board
|
||||
independent XTBSP API implemented by a board specific library distributed
|
||||
with the Xtensa Tools. This provides the board clock frequency and basic
|
||||
polled drivers for the display and console device. Note that XTBSP
|
||||
is not a tradtional RTOS "board support package" with RTOS specific
|
||||
interrupt-driven drivers - it is not specific to any RTOS. Note that
|
||||
FreeRTOS can run on any Xtensa board without this board support
|
||||
(a "raw" platform), but you will have to provide the clock frequency
|
||||
and drivers for any on-board devices you want to use.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The Xtensa port of FreeRTOS v11 is available at this location:
|
||||
|
||||
https://github.com/foss-xtensa/FreeRTOS-Kernel-Partner-Supported-Ports
|
||||
|
||||
and is submoduled into the following FreeRTOS repos:
|
||||
|
||||
https://github.com/foss-xtensa/FreeRTOS-Kernel
|
||||
https://github.com/foss-xtensa/FreeRTOS
|
||||
|
||||
This download includes the core FreeRTOS source and include files needed
|
||||
to build the port. You can also download the official releases of FreeRTOS
|
||||
kernel from:
|
||||
|
||||
https://github.com/FreeRTOS/FreeRTOS-Kernel
|
||||
https://www.freertos.org/
|
||||
|
||||
The Xtensa port files are included in the official package under the
|
||||
"Partner-Supported-Ports" and "Partner-Supported-Demos" submodules, but
|
||||
may not be the latest versions available.
|
||||
|
||||
All source is provided along with a Makefile that works for any host
|
||||
platform supported by Xtensa Tools (Windows, Linux). These instructions
|
||||
are written for Windows users, but can easily be understood and adapted
|
||||
to other host platforms.
|
||||
|
||||
First install the FreeRTOS common package in a directory of your choosing.
|
||||
The structure of that package will look like this:
|
||||
|
||||
<install directory>
|
||||
|-- Demo/ThirdParty/Partner-Supported-Demos/ (submodule)
|
||||
| `-- Cadence_Xtensa_ISS_xt-clang/
|
||||
| |-- common
|
||||
| | |-- application_code
|
||||
| | | `-- cadence_code
|
||||
| | `-- config_files
|
||||
| `-- stress
|
||||
`-- Source/ (submodule)
|
||||
`-- portable/ThirdParty/Partner-Supported-Ports/ (submodule)
|
||||
`-- Cadence
|
||||
`-- Xtensa
|
||||
|
||||
The Xtensa Tools are available from Cadence as part of a processor
|
||||
license. Be sure you have installed the Xtensa Tools and your processor
|
||||
configuration.
|
||||
|
||||
|
||||
Building FreeRTOS for Xtensa
|
||||
----------------------------
|
||||
|
||||
To build the FreeRTOS library and the example programs, go into the
|
||||
directory 'Demo/.../Cadence_Xtensa_ISS_xt-clang' and use the makefile
|
||||
in that directory. "make all" will build all the examples. There is
|
||||
another makefile in the 'portable/.../Cadence/Xtensa' directory that
|
||||
builds just the FreeRTOS library.
|
||||
|
||||
By default, you will build for the Xtensa instruction set simulator. If
|
||||
you have a supported emulation board, you can build to run on that. You
|
||||
can also build to run on a raw Xtensa core with no board support, a
|
||||
good starting point for supporting your own target platform. Cadence
|
||||
recommends doing functional development on the simulator because it
|
||||
is easier to debug with, then move to a board if/when you need to test
|
||||
hardware drivers or real-time performance.
|
||||
|
||||
The provided makefile simplifies building FreeRTOS and the example
|
||||
for your Xtensa configuration and platform (ISS, board, etc.). There
|
||||
are detailed instructions in the comments at the top of the makefile.
|
||||
|
||||
The makefiles work on Windows and Linux and support incremental builds.
|
||||
The build for each Xtensa configuration and target platform is placed in
|
||||
a subdirectory so several core and platform builds can co-exist even with
|
||||
incremental rebuilds. You may specify the root of the build area (if tou
|
||||
want it to be elsewhere than under the source tree) by defining BLDROOT
|
||||
either in the make command or your shell environment.
|
||||
|
||||
|
||||
Building the FreeRTOS Library
|
||||
-----------------------------
|
||||
|
||||
First, be sure you have installed Xtensa Tools and your processor
|
||||
configuration, and be sure that Xtensa Tools are in your search path.
|
||||
You can use xt-make, which comes with the Xtensa Tools, to run the
|
||||
makefiles.
|
||||
|
||||
Change directories to the Xtensa port directory:
|
||||
|
||||
> cd portable/ThirdParty/Partner-Supported-Ports/Cadence/Xtensa
|
||||
|
||||
Now build the FreeRTOS RTOS as a library (libfreertos.a) as follows:
|
||||
|
||||
> xt-make
|
||||
|
||||
which by default builds for the simulator (TARGET=sim), or:
|
||||
|
||||
> xt-make TARGET=board
|
||||
|
||||
which builds for a supported board. Note that the board type does not
|
||||
need to be specified when building the FreeRTOS library.
|
||||
|
||||
If you are building for an Xtensa processor configuration that is not the
|
||||
default you selected when you installed Xtensa Tools, you need to define the
|
||||
environment variable XTENSA_CORE. If your configuration is not in the
|
||||
default registry you selected when you installed Xtensa Tools, you also
|
||||
need to define the environment variable XTENSA_SYSTEM. See tools manuals.
|
||||
You can avoid defining these in your environment if you pass the variables
|
||||
you need to redefine into xt-make as follows:
|
||||
|
||||
> xt-make XTENSA_CORE=<your_config_name> XTENSA_SYSTEM=<your_registry> ...
|
||||
|
||||
There are more details about build options in the comment in the Makefile.
|
||||
|
||||
After the library has been built, you must link your application with this
|
||||
library in order to use FreeRTOS.
|
||||
|
||||
|
||||
Building the FreeRTOS Examples
|
||||
------------------------------
|
||||
|
||||
The provided examples are designed to run on the Xtensa instruction set
|
||||
simulator (ISS) or a supported evaluation board programmed with your
|
||||
Xtensa processor configuration.
|
||||
|
||||
To build the examples for the default platform (simulator):
|
||||
|
||||
> cd Demo/ThirdParty/Partner-Supported-Demos/Cadence_Xtensa_ISS_xt-clang
|
||||
|
||||
> xt-make all
|
||||
|
||||
which is the same as
|
||||
|
||||
> xt-make all TARGET=sim
|
||||
|
||||
The boards currently supported are the Xilinx ML605 and KC705 FPGA
|
||||
development boards. To target these boards, type
|
||||
|
||||
> xt-make all TARGET=ml605
|
||||
|
||||
or
|
||||
|
||||
> xt-make all TARGET=kc705
|
||||
|
||||
To build in a location other than the default, specify the new location
|
||||
using the BLDROOT variable. Note that this makefile will invoke the
|
||||
FreeRTOS library build makefile automatically, passing on the relevant
|
||||
parameters based on what you specified.
|
||||
|
||||
You can override the default compilation options by specifying the new
|
||||
options via CFLAGS. For example:
|
||||
|
||||
> xt-make all TARGET=sim CFLAGS="-Os -g"
|
||||
|
||||
This compiles the examples and links them with the FreeRTOS library
|
||||
libfreertos.a and the appropriate linker-support package (LSP) for your
|
||||
target platform (you can override the LSP by adding LSP=<lsp> to the
|
||||
xt-make command line). The resulting ELF files can be downloaded and
|
||||
executed on the target. The example binaries appear in the platform
|
||||
specific subdirectory described earlier.
|
||||
|
||||
To build your application with thread-safe C library support, you
|
||||
need to make certain modifications to the application to plug in and
|
||||
invoke the reentrancy support. This allows each task to use the library
|
||||
without interference with other tasks (it is not safe for interrupt
|
||||
handlers to call the C library).
|
||||
|
||||
First, you must define
|
||||
|
||||
XT_USE_THREAD_SAFE_CLIB
|
||||
|
||||
to a nonzero value either in xtensa_config.h or on the compiler's command
|
||||
line. Note that the default xtensa_config.h provided with this port does
|
||||
define this to 1 if either newlib or xclib is detected.
|
||||
|
||||
The space for the per-thread C library context data is allocated within
|
||||
the FreeRTOS TCB structure.
|
||||
|
||||
The MPU example must be built separately since it requires the FreeRTOS
|
||||
library to be rebuilt with -DportUSING_MPU_WRAPPERS=1 -DportALIGN_SECTIONS
|
||||
which is handled by the makefile if you do the following:
|
||||
|
||||
> xt-make clean
|
||||
> xt-make MPU=1
|
||||
|
||||
The code overlay example must be built separately since it requires the
|
||||
FreeRTOS library to be rebuilt. XT_USE_OVLY must be defined at build time,
|
||||
this is handled by the makefile if you do the following:
|
||||
|
||||
> xt-make clean
|
||||
> xt-make overlay
|
||||
|
||||
Note that the overlay example generates its own LSP from the 'sim' LSP.
|
||||
Overlay support works only with the windowed ABI option.
|
||||
|
||||
|
||||
IMPORTANT NOTE
|
||||
--------------
|
||||
|
||||
The header file FreeRTOS.h, which is a part of the core FreeRTOS sources,
|
||||
includes <reent.h> if thread safety for the C libraries is enabled. For
|
||||
xclib, this file exists in <sys/reent.h> and so is reported as missing.
|
||||
To work around this, the makefiles supplied with this port will copy the
|
||||
reent.h header into the build directory during the build process. If you
|
||||
use a different build process, then you must make sure to copy this file
|
||||
to a location that is included in the list of include paths. This can be
|
||||
the build directory or the directory that contains the Xtensa port source
|
||||
files.
|
||||
|
||||
|
||||
Running or Debugging an Application
|
||||
-----------------------------------
|
||||
|
||||
To execute the example application on the simulator:
|
||||
|
||||
> xt-run [options] example.exe
|
||||
|
||||
Consult the Xtensa simulator user manual for more information on options.
|
||||
|
||||
To execute the example using the command line debugger:
|
||||
|
||||
> xt-gdb example.exe
|
||||
|
||||
To execute on the simulator using the Xplorer GUI based debugger:
|
||||
|
||||
> xplorer --debug example.exe
|
||||
|
||||
|
||||
To execute on a supported evaluation board, download example.exe per
|
||||
instructions in the tools manuals. Be sure the board has been programmed
|
||||
with the correct configuration and is set up to boot from RAM and debug
|
||||
a downloaded program! Optionally you may connect a terminal or terminal
|
||||
emulator to the serial port on the board with settings as described in
|
||||
the board user manual, and see the output of printf on the terminal.
|
||||
|
||||
To obtain I/O on a "raw" platform such as an unsupported board, you need
|
||||
to provide low level I/O drivers (eg. inbyte() and outbyte() for character
|
||||
I/O if you want to use printf etc.). You can run "raw" executables on
|
||||
any Xtensa platform, including simulator and any board, but you will not
|
||||
see any behavior specific to the platform (eg. display, printed output,
|
||||
stopping simulation at end of program). You can, while debugging, use a
|
||||
debugger mechanism called GDBIO to obtain basic I/O. To use GDBIO, link
|
||||
with the gdbio library. Refer to Xtensa tools documentation for details.
|
||||
|
||||
|
||||
Task Stack Sizes
|
||||
----------------
|
||||
|
||||
The application must ensure that every task has enough space for its
|
||||
stack. Each task needs enough space for its own use, its own interrupt
|
||||
stack frame (defined in xtensa_context.h) and space to save coprocessor
|
||||
state, if any. Several factors influence the size of the stack required,
|
||||
including the compiler optimization level and the use of the C library.
|
||||
Calls to standard output functions such as printf() can use up a lot of
|
||||
stack space. The tool xt-stack-usage is helpful in determining safe stack
|
||||
sizes for your application.
|
||||
|
||||
Some macros are provided in xtensa_config.h to help determine the stack
|
||||
size for tasks that do and do not use the C library. Use these as the
|
||||
basis for each task's stack size. They are minimum requirements taking
|
||||
into account your configuration and use of the C library. In particular,
|
||||
the define
|
||||
|
||||
XT_STACK_MIN_SIZE
|
||||
|
||||
defines the minimum stack size for any task. Be very careful if you try
|
||||
to use a stack size smaller than this minimum. Stack overruns can cause
|
||||
all kinds of hard-to-debug errors. It is recommended that you enable the
|
||||
FreeRTOS stack checking features during development.
|
||||
|
||||
WARNING: The newlib printf() function uses a lot of stack space. Be very
|
||||
careful in using it. Optionally you can use the 'libxtutil' library for
|
||||
output - it implements a subset of printf() that has smaller code size
|
||||
and uses far less stack space. More information about this library is in
|
||||
the Xtensa Tools documentation.
|
||||
|
||||
|
||||
Interrupt Stack
|
||||
---------------
|
||||
|
||||
Beginning with port version 1.2, the port uses a separate interrupt stack
|
||||
for handling interrupts. Thus, it is no longer necessary for each task to
|
||||
reserve space on its stack to handle interrupts. The size of the interrupt
|
||||
stack is controlled by the parameter "configISR_STACK_SIZE" defined in
|
||||
FreeRTOSConfig.h. Define this carefully to match your system requirements.
|
||||
|
||||
|
||||
Assembler / Compiler Switches
|
||||
-----------------------------
|
||||
|
||||
The following are compiler switches are used by the provided
|
||||
Makefile in building the FreeRTOS library and example application.
|
||||
These can be modified by editing the Makefile or by overriding the
|
||||
CFLAGS variable in the make command line, for example:
|
||||
|
||||
> xt-make CFLAGS="-O2 -DXT_USE_THREAD_SAFE_CLIB"
|
||||
|
||||
-g Specifies debug information.
|
||||
-c Specifies object code generation.
|
||||
-On Sets compiler optimization level n (default -O0).
|
||||
-mlongcalls Allows assembler and linker to convert call
|
||||
instructions to longer indirect call sequences
|
||||
when target is out of range.
|
||||
-x assembler-with-cpp Passes .s and .S files through C preprocessor.
|
||||
-Dmacro Define a preprocessor macro with no value.
|
||||
-Dmacro=value Define a preprocessor macro with a value.
|
||||
|
||||
See the compiler / linker documentation for a full list of switches and
|
||||
their use.
|
||||
|
||||
Many definitions can be provided at compile-time via the -D option
|
||||
without editing the source code. Here are some of the more useful ones:
|
||||
|
||||
XT_USE_THREAD_SAFE_CLIB Enable support for the reentrancy to provide
|
||||
thread-safety for the newlib and xclib libraries
|
||||
supplied with Xtensa Tools. Default ON.
|
||||
|
||||
Note, the follwing defines are unique to the Xtensa port so have names
|
||||
beginning with "XT_".
|
||||
|
||||
XT_SIMULATOR Set this if building to run on the simulator.
|
||||
Takes advantage of certain simulator control
|
||||
and reporting facilities, and adjusts timing
|
||||
of periodic tick to provide a more acceptable
|
||||
performance in simulation (see XT_CLOCK_FREQ).
|
||||
Set by default unless PLATFORM is overridden.
|
||||
|
||||
XT_BOARD Set this if building for a supported board.
|
||||
Be sure to specify the correct LSP for the
|
||||
board. See the example makefile for usage.
|
||||
|
||||
XT_CLOCK_FREQ=freq Specifies the target processor's clock
|
||||
frequency in Hz. Used primarily to set the
|
||||
timer that generates the periodic interrupt.
|
||||
Defaults are provided and may be edited in
|
||||
xtensa_timer.h (see comments there also).
|
||||
Default for simulator provides more acceptable
|
||||
performance, but cannot provide real-time
|
||||
performance due to variation in simulation
|
||||
speed per host platform and insufficient
|
||||
cycles between interrupts to process them.
|
||||
Supported board platforms by default leave
|
||||
this undefined and compute the clock frequency
|
||||
at initialization unless this is explicitly
|
||||
defined.
|
||||
|
||||
XT_TICK_PER_SEC=n Specifies the frequency of the periodic tick.
|
||||
|
||||
XT_TIMER_INDEX=n Specifies which timer to use for periodic tick.
|
||||
Set this if your Xtensa processor configuration
|
||||
provides more than one suitable timer and you
|
||||
want to override the default. See xtensa_timer.h .
|
||||
|
||||
XT_INTEXC_HOOKS Enables hooks in interrupt vector handlers
|
||||
to support dynamic installation of exception
|
||||
and interrupt handlers. Disabled by default.
|
||||
|
||||
XT_USE_OVLY Enable code overlay support. It uses a mutex,
|
||||
hence configUSE_MUTEXES must be enabled.
|
||||
|
||||
XT_USE_SWPRI Enable software prioritization of interrupts.
|
||||
Enabling this will prioritize interrupts with
|
||||
higher bit numbers over those with lower bit
|
||||
numbers at the same level. This works only for
|
||||
low and medium priority interrupts that can be
|
||||
dispatched to C handlers, and only for XEA2
|
||||
when 32 or fewer interrupts are configured.
|
||||
|
||||
|
||||
Register Usage and Stack Frames
|
||||
-------------------------------
|
||||
|
||||
The Xtensa architecture specifies two ABIs that determine how the general
|
||||
purpose registers a0-a15 are used: the standard windowed ABI use with
|
||||
the Xtensa windowed register file architecture, and the optional and
|
||||
more conventional Call0 ABI (required for Xtensa configurations without
|
||||
a windowed register file).
|
||||
|
||||
Xtensa processors may have other special registers (including co-processor
|
||||
registers and other TIE "states") that are independent of this choice
|
||||
of ABI. See Xtensa documentation for more details.
|
||||
|
||||
In the windowed ABI the registers of the current window are used as follows:
|
||||
a0 = return address
|
||||
a1 = stack pointer (alias sp)
|
||||
a2 = first argument and result of call (in simple cases)
|
||||
a3-7 = second through sixth arguments of call (in simple cases).
|
||||
Note that complex or large arguments are passed on the
|
||||
stack. Details are in the Xtensa Tools manuals.
|
||||
a8-a15 = available for use as temporaries.
|
||||
There are no callee-save registers. The windowed hardware automatically
|
||||
saves registers a0-a3 on a call4, a0-a8 on a call8, a0-a12 on a call12,
|
||||
by rotating the register window. Hardware triggers window overflow and
|
||||
underflow exceptions as necessary when registers outside the current
|
||||
window need to be spilled to preallocated space in the stack frame, or
|
||||
restored. Complete details are in the Xtensa manuals. The entire windowed
|
||||
register file is saved and restored on interrupt or task context switch.
|
||||
|
||||
The Call0 ABI does not make use of register windows, relying instead
|
||||
on a fixed set of 16 registers without window rotation.
|
||||
The Call0 ABI is more conventional and uses registers as follows:
|
||||
a0 = return address
|
||||
a1 = stack pointer (alias sp)
|
||||
a2 = first argument and result of call (in simple cases)
|
||||
a3-7 = second through sixth arguments of call (in simple cases).
|
||||
Note that complex or large arguments are passed on the
|
||||
stack. Details are in the Xtensa Tools manuals.
|
||||
a8-a11 = scratch.
|
||||
a12-a15 = callee-save (a function must preserve these for its caller).
|
||||
On a FreeRTOS API call, callee-save registers are saved only when a task
|
||||
context switch occurs, and other registers are not saved at all (the caller
|
||||
does not expect them to be preserved). On an interrupt, callee-saved
|
||||
registers might only be saved and restored when a task context-switch
|
||||
occurs, but all other registers are always saved and restored.
|
||||
|
||||
An Xtensa processor has other special registers independent of the ABI,
|
||||
depending on the configuration (including co-processor registers and other
|
||||
TIE state) that are part of the task context. FreeRTOS preserves all such
|
||||
registers over an unsolicited context-switch triggered by an interrupt.
|
||||
However it does NOT preserve these over a solicited context-switch during
|
||||
a FreeRTOS API call. This bears some explanation. These special registers
|
||||
are either ignored by the compiler or treated as caller-saved, meaning
|
||||
that if kept "live" over a function call (ie. need to be preserved)
|
||||
they must be saved and restored by the caller. Since solicited entry to
|
||||
FreeRTOS is always made by a function call, FreeRTOS assumes the caller
|
||||
has saved any of these registers that are "live". FreeRTOS avoids a lot
|
||||
of overhead by not having to save and restore every special register
|
||||
(there can be many) on every solicited context switch.
|
||||
|
||||
As a consequence, the application developer should NOT assume that special
|
||||
registers are preserved over a FreeRTOS API call such as vTaskDelay().
|
||||
If multiple tasks use a register, the caller must save and restore it.
|
||||
|
||||
The saved context stack frames for context switches that occur as
|
||||
a result of interrupt handling (interrupt frame) or from task-level
|
||||
API calls (solicited frame) are described in human readable form in
|
||||
xtensa_context.h . All suspended tasks have one of these two types
|
||||
of stack frames. The top of the suspended task's stack is pointed to
|
||||
by pxCurrentTCB->pxTopOfStack. A special location common to both stack
|
||||
frames differentiates solicited and interrupt stack frames.
|
||||
|
||||
|
||||
Improving Performance, Footprint, or Ease of Debugging
|
||||
------------------------------------------------------
|
||||
|
||||
To make FreeRTOS run faster you can change the Makefile to enable the
|
||||
desired optimizations or set a predefined optimization level (-O<level>).
|
||||
|
||||
Maximum performance is achieved with -O3 -ipa, but that might increase
|
||||
the footprint substantially. A good compromise is -O2. See the compiler
|
||||
manual for details.
|
||||
|
||||
Minimal footprint is achieved by optimizing for space with -Os, at the
|
||||
cost of some performance. See the compiler manual for details.
|
||||
|
||||
The Xtensa architecture port-specific assembly files are coded with no
|
||||
file-scope labels inside functions (all labels inside functions begin with
|
||||
".L"). This allows a profiler to accurately associate an address with a
|
||||
function, and also allows the debugger's stack trace to show the correct
|
||||
function wherever the program counter is within that function. However
|
||||
there are some tradeoffs in debugging. Local (".L") labels are not
|
||||
visible to the debugger, so the following limitations may be observed
|
||||
during debugging:
|
||||
- You cannot set a breakpoint on a local label inside a function.
|
||||
- Disassembly will show the entire function, but will get out of sync and
|
||||
show incorrect opcodes if it crosses any padding before an aligned local
|
||||
branch target (".L" label, not ".Ln"). Restart disassembly specifying an
|
||||
address range explicitly between points where there is padding.
|
||||
Since FreeRTOS is provided in source form, it is not difficult to remove
|
||||
the ".L" and ".Ln" prefixes from local labels if you want them visible.
|
||||
They can also be made visible by passing the '-L' option to the assembler
|
||||
and linker (see the assembler and linker manuals for details).
|
||||
|
||||
|
||||
Interrupt and Exception Handling
|
||||
--------------------------------
|
||||
|
||||
FreeRTOS provides a complete set of efficient exception and first-level
|
||||
interrupt handlers installed at the appropriate exception and interrupt
|
||||
vector locations. The Xtensa architecture supports several different
|
||||
classes of exceptions and interrupts. Being a configurable architecture,
|
||||
many of these are optional, and the vector locations are determined by
|
||||
your processor configuration. (Note that Diamond cores are pre-configured
|
||||
with specific vector locations.) The handlers provided use conditional
|
||||
compilation to adapt to your processor configuration and include only
|
||||
the code that is needed.
|
||||
|
||||
Xtensa vector locations may reside almost anywhere, including in ROM.
|
||||
The amount of code space available at each of these locations is
|
||||
often very small (e.g. due to following vectors). A small stub of
|
||||
code installed at the vector jumps to the corresponding handler,
|
||||
usually in RAM. The exception and interrupt handlers are defined in
|
||||
xtensa_vectors.S. They are not specific to FreeRTOS, but call into
|
||||
FreeRTOS where appropriate via macros defined in xtensa_rtos.h .
|
||||
|
||||
The handlers provided for low and medium priority interrupts are just
|
||||
dispatchers that save relevant state and call user-definable handlers.
|
||||
See the files xtensa_vectors.S and xtensa_api.h for more details of how
|
||||
to create and install application-specific user interrupt handlers.
|
||||
Similarly, user-defined handlers can be installed for exceptions (other
|
||||
than a few which are always handled by the OS).
|
||||
|
||||
The high priority interrupt handlers provided may be considered templates
|
||||
into which the application adds code to service specific interrupts.
|
||||
The places where application handlers should be inserted are tagged with
|
||||
the comment "USER_EDIT" in xtensa_vectors.S.
|
||||
|
||||
This FreeRTOS port supports strict priority-based nesting of interrupts.
|
||||
An interrupt may only nest on top of one of strictly lower priority.
|
||||
Equal priority interrupts concurrently pending are handled in an
|
||||
application-defined sequence before any lower priority interrupts
|
||||
are handled. During interrupt and exception handling, the processor's
|
||||
interrupt level (PS.INTLEVEL) is used to control the interrupt priority
|
||||
level that can be accepted; interrupt sources are not controlled
|
||||
individually by FreeRTOS (the application is free to access the INTENABLE
|
||||
register directly to enable/disable individual interrupts, eg. using
|
||||
Xtensa HAL services). This approach provides the most deterministic
|
||||
bounds on interrupt latency (for a given priority) and stack depth.
|
||||
|
||||
Software prioritization of interrupts at the same priority is controlled
|
||||
by the definition of XT_USE_SWPRI. See above for a description of this
|
||||
parameter.
|
||||
|
||||
The following subsections describe the handling of each class of exception
|
||||
and interrupt in more detail. Many have nothing to do with FreeRTOS but
|
||||
are mentioned because there is code to handle them in xtensa_vectors.S.
|
||||
|
||||
Note that the concept of software prioritization and the low/medium/high
|
||||
priority discussion applies only to XEA2.
|
||||
|
||||
User Exception and Interrupt Handler (Low/Medium Priority):
|
||||
|
||||
All Xtensa 'general exceptions' come to the user, kernel, or double
|
||||
exception vector. The exception type is identified by the EXCCAUSE
|
||||
special register (level 1 interrupts are one particular cause of a
|
||||
general exception). This port sets up PS to direct all such exceptions
|
||||
to the user vector. Exceptions taken at the other two vectors usually
|
||||
indicate a kernel or application bug.
|
||||
|
||||
Level 1 interrupts are identified at the beginning of the handler
|
||||
and are dispatched to a dedicated handler. Then, syscall and alloca
|
||||
exceptions are identified and dispatched to special handlers described
|
||||
below. After this, coprocessor exceptions are identified and dispatched
|
||||
to the coprocessor handler.
|
||||
|
||||
Any remaining exceptions are processed as follows:
|
||||
|
||||
Having allocated the exception stack frame, the user exception handler
|
||||
saves the current task state and sets up a C environment and enables
|
||||
the high-priority class of interrupts (which do not interact with
|
||||
FreeRTOS), then reads EXCCAUSE and uses the cause (number) to index
|
||||
into a table of user-specified handlers. The correct handler is then
|
||||
called. If the handler returns, the context is restored and control is
|
||||
returned to the code that caused the exception. The user-defined handler
|
||||
may alter the saved context, or any other system state, that allows the
|
||||
faulting instruction to be retried.
|
||||
|
||||
If the cause is a level 1 (low-priority) or medium-priority interrupt,
|
||||
the handler enables all interrupts above that priority level after
|
||||
saving the task context. It then sets up the environment for C code
|
||||
and then calls the handler (found in the handler table) for the
|
||||
interrupt number. If the user has not specified a handler, then the
|
||||
default handler will be called, which will terminate the program.
|
||||
|
||||
If the interrupt is for the system timer, it calls a special interrupt
|
||||
handler for the system timer tick, which handles timer tick processing.
|
||||
|
||||
Finally, the handler calls _frxt_int_exit to allow FreeRTOS to perform
|
||||
any scheduling necessary and return either to the interrupted task
|
||||
or another.
|
||||
|
||||
If software prioritization is enabled, the handler will re-enable all
|
||||
interrupts at the same level that are numerically higher than the current
|
||||
one, before calling the user handler. This allows a higher priority
|
||||
interrupt to pre-empt the lower priority handler.
|
||||
|
||||
Medium Priority Interrupt Handlers:
|
||||
|
||||
Medium priority interrupts are those at levels 2 up to XCHAL_EXCM_LEVEL,
|
||||
a configuration-specific maximum interrupt level affected by the global
|
||||
'exception mode' bit in the processor status word (PS.EXCM).
|
||||
Interrupt levels above XCHAL_EXCM_LEVEL are of the high-priority class.
|
||||
The Xtensa hardware documentation considers medium priority interrupts
|
||||
to be a special case of high-priority interrupts, but from a software
|
||||
perspective they are very different.
|
||||
|
||||
Dispatch of medium-priority interrupts is discussed in the section
|
||||
above.
|
||||
|
||||
High Priority Interrupt Handlers:
|
||||
|
||||
High priority interrupts are those strictly above XCHAL_EXCM_LEVEL,
|
||||
a configuration-specific maximum interrupt level affected by the
|
||||
global 'exception mode' bit in the processor status word (PS.EXCM).
|
||||
High priority handlers may not directly interact with FreeRTOS at all,
|
||||
and are described here only for the sake of completeness. They must
|
||||
be coded in assembler (may not be coded in C) and are intended to be
|
||||
used for handling extremely high frequency hardware events that need
|
||||
to be handled in only a few cycles. A high priority interrupt handler
|
||||
may trigger a software interrupt at a medium or low priority level to
|
||||
occasionally signal FreeRTOS. Please see Xtensa documentation.
|
||||
|
||||
There is a separate vector and a few special registers for each high
|
||||
priority interrupt, providing for fast dispatch and efficient nesting
|
||||
on top of lower priority interrupts. Handlers are templates included
|
||||
only for the vectors that exist in your Xtensa processor configuration.
|
||||
These templates are written for only one interrupt per high priority
|
||||
level to minimize latency servicing very fast time-critical interrupts.
|
||||
The vector code jumps to the corresponding first-level interrupt handler,
|
||||
which then executes application-provided assembler code before returning
|
||||
quickly to the interrupted task or lower priority handler.
|
||||
|
||||
Kernel Exception Handler:
|
||||
|
||||
Kernel mode is not used in this port of FreeRTOS, and therefore kernel
|
||||
exceptions should not happen. A stub is provided for the vector that
|
||||
triggers the debugger (if connected) or calls _xt_panic to freeze the
|
||||
processor should a kernel exception occur.
|
||||
|
||||
Alloca Exception Handler:
|
||||
|
||||
Alloca exceptions are generated by the 'movsp' instruction, which
|
||||
is used only in the windowed ABI. Its purpose is to allocate some
|
||||
space on top of the stack. Because the window hardware may have
|
||||
spilled some registers to the 16 byte "base save" area below the
|
||||
stack pointer, it is necessary to protect those values. The alloca
|
||||
handler accomplishes this quickly without setting up an interrupt
|
||||
frame or entering FreeRTOS, by emulating a register underflow and
|
||||
re-executing 'movsp'.
|
||||
|
||||
Syscall Exception Handler:
|
||||
|
||||
Syscall exceptions are generated by a 'syscall' instruction.
|
||||
The windowed ABI specifies that executing this instruction with
|
||||
a value of zero in register a2 must spill any unsaved registers
|
||||
in the windowed register file to their pre-determined locations
|
||||
on the caller's stack. The handler does exactly that, and skips
|
||||
over the 'syscall' instruction before returning to the caller.
|
||||
If a2 is non-zero, the handler returns a2 == -1 to the caller.
|
||||
|
||||
Co-Processor Exception Handler:
|
||||
|
||||
A co-processor exception is generated when a task accesses a
|
||||
co-processor that it does not "own". Ownership represents which
|
||||
task's state is currently in the co-processor. Co-processors are
|
||||
context-switched "lazily" (on demand) only when a non-owning task
|
||||
uses a co-processor instruction, otherwise a task retains ownership
|
||||
even when it is preempted from the main processor. The co-processor
|
||||
exception handler performs the context-switch and manages ownership.
|
||||
|
||||
Co-processors may not be used by any code outside the context of a
|
||||
task. A co-processor exception triggered by code that is not part
|
||||
of a running task is a fatal error and FreeRTOS for Xtensa will panic.
|
||||
This restriction is intended to reduce the overhead of saving and
|
||||
restoring co-processor state (which can be quite large) and in
|
||||
particular remove that overhead from interrupt handlers.
|
||||
|
||||
Debug Exception Handler:
|
||||
|
||||
A debug exception is caused as a result of running code, such as by
|
||||
a 'break' instruction or hardware breakpoints and watchpoints, or
|
||||
as a result of an external debug interrupt, such as from an OCD based
|
||||
debugger or multiprocessor debug events ("breakin/breakout"). If the
|
||||
processor is running in OCD mode under control of an OCD-based debugger,
|
||||
the trigger event immediately halts the processor and gives control to
|
||||
the OCD debugger. Otherwise control is transferred to the debug vector.
|
||||
The debug vector handler calls the simulator if running on the ISS,
|
||||
which then takes control and interacts with any attached debugger.
|
||||
If running on hardware and not in OCD mode, debug exceptions are not
|
||||
expected, so the debug handler calls _xt_panic to freeze the processor.
|
||||
|
||||
Double Exception Handler:
|
||||
|
||||
A double exception is a general exception that happens while the
|
||||
processor is in exception mode (PS.EXCM set), and thus indicates a
|
||||
bug in kernel code. The double exception vector handler triggers
|
||||
the debugger (if connected) or calls _xt_panic to freeze the
|
||||
processor.
|
||||
|
||||
Window Overflow and Underflow Exception Handlers:
|
||||
|
||||
Window overflow and underflow handlers are required for use of the
|
||||
windowed ABI. Each has its own dedicated vector and highly optimized
|
||||
code that is independent of OS. See Xtensa documentation for details.
|
||||
|
||||
Hooks for Dynamic Installation of Handlers:
|
||||
|
||||
Optional hooks are provided in the user exception and low level
|
||||
interrupt handler and all medium and high priority interrupt handlers,
|
||||
to dynamically install a handler function (which may be coded in C,
|
||||
unless in a high-priority interrupt handler). These hooks are enabled
|
||||
and used by automatic regression tests, they are not part of a normal
|
||||
FreeRTOS build. However an application is free to take advantage of
|
||||
them. The interrupt/exception hooks are described in xtensa_rtos.h .
|
||||
|
||||
It is recommended that the application not make use of these hooks, but
|
||||
rather use xt_set_interrupt_handler() and xt_set_exception_handler()
|
||||
to install application-specific handlers. This method is more convenient
|
||||
and allows arguments to be passed to the handlers. Software prioritization
|
||||
of interrupts works only with this method. See xtensa_api.h for details.
|
||||
|
||||
Overlay Support
|
||||
|
||||
Code overlays are supported as of version 2.30 for Xtensa LX processors
|
||||
only. This is enabled by defining XT_USE_OVLY when building FreeRTOS and
|
||||
the application code, and requires liboverlay.a to be specified at link
|
||||
time. See the overlay example and the Xtensa system SW reference manual
|
||||
for more details.
|
||||
|
||||
|
||||
-End-
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
Notes for Version 3.00
|
||||
----------------------
|
||||
|
||||
- This version supports FreeRTOS version 11.0.0.
|
||||
|
||||
- The directory structure and makefiles have been reorganized to conform
|
||||
to the structure of FreeRTOS version 11.0.0.
|
||||
|
||||
|
||||
Notes for Version 2.40
|
||||
----------------------
|
||||
|
||||
- Now supports Xtensa LX processors with up to 128 interrupts.
|
||||
Note: XT_USE_SWPRI only supported on LX processors with <= 32 interrupts.
|
||||
|
||||
|
||||
Notes for Version 2.30
|
||||
----------------------
|
||||
|
||||
- Code overlay support enabled (for Xtensa LX only). An example
|
||||
is provided in the demos/cadence/sim directory. Code overlay
|
||||
support requires mutexes.
|
||||
|
||||
|
||||
Notes for Version 2.20
|
||||
----------------------
|
||||
|
||||
- FreeRTOS kernel version updated to 10.4.4.
|
||||
|
||||
- XAF config defaults brought back into 10.4.4-stable branch.
|
||||
Variable frequency support is merged into this branch as well.
|
||||
|
||||
|
||||
Notes for Version 2.10
|
||||
----------------------
|
||||
|
||||
- Now supports Xtensa NX processors.
|
||||
|
||||
|
||||
Notes for Version 2.01
|
||||
----------------------
|
||||
|
||||
- Modified debug exception handling to allow user-supplied handler to
|
||||
be installed. The user handler can be a C function and is installed
|
||||
like so -
|
||||
|
||||
xt_set_exception_handler( EXCCAUSE_DEBUG, dbg_handler );
|
||||
|
||||
|
||||
Notes for version 2.0
|
||||
---------------------
|
||||
|
||||
- Extensive refactor of code to eliminate use of MPU struct for saving
|
||||
coprocessor state. Coprocessor exception handling has been redone.
|
||||
|
||||
- Low power sleep support (tickless idle) added.
|
||||
|
||||
- Removed use of XTOS header files and macros. Renamed port macros to
|
||||
avoid name conflicts with XTOS macros.
|
||||
|
||||
- More compiler warnings enabled for build (-Werror -Wextra -std=c99).
|
||||
|
||||
- Interrupt and exception API reworked. Timer setup and handling mostly
|
||||
converted to C code and simplified.
|
||||
|
||||
|
||||
Notes for version 1.7
|
||||
---------------------
|
||||
|
||||
- portSTACK_TYPE changed to uint32_t from uint8_t. Stack size definitions
|
||||
adjusted accordingly.
|
||||
|
||||
- portYIELD_FROM_ISR changed to call _frxt_setup_switch conditionally.
|
||||
|
||||
- Tick handler calls xTaskIncrementTick inside critical region to prevent
|
||||
interrupt nesting issues.
|
||||
|
||||
|
||||
Notes for version 1.6
|
||||
---------------------
|
||||
|
||||
- This version supports FreeRTOS version 10.0.0.
|
||||
|
||||
- The directory structure and makefiles have been reorganized to conform
|
||||
to the structure of FreeRTOS version 10.0.0.
|
||||
|
||||
|
||||
Notes for version 1.5
|
||||
---------------------
|
||||
|
||||
- This version supports FreeRTOS version 9.0.0.
|
||||
|
||||
- This version supports thread safe operation with the Xtensa C Library
|
||||
(xclib) in addition to the Newlib C library (newlib).
|
||||
The xtensa_config.h file is set up to enable thread safe operation by
|
||||
default if xclib or newlib is detected. Use -D XT_USE_THREAD_SAFE_CLIB=0
|
||||
on the command line or in the project definition to disable this.
|
||||
|
||||
- Incorrect function prototypes for xt_ints_on/xt_ints_off have been fixed.
|
||||
|
||||
|
||||
Notes for version 1.4.2
|
||||
-----------------------
|
||||
|
||||
- This version implements a bugfix. The bug was that even when the
|
||||
config parameter "configUSE_TIME_SLICING" was set to zero, time
|
||||
slicing would still occur due to a problem in the Xtensa interrupt
|
||||
processing code.
|
||||
|
||||
- The "small_test" test has been added to illustrate how FreeRTOS
|
||||
can be configured to reduce the memory footprint.
|
||||
|
||||
|
||||
Notes for version 1.4
|
||||
---------------------
|
||||
|
||||
- This version supports FreeRTOS version 8.2.0.
|
||||
|
||||
- This version adds a new test xt_intr.c for interrupts testing.
|
||||
|
||||
- This version separates the trace and benchmark facilities into a
|
||||
separate downloadable.
|
||||
|
||||
|
||||
Notes for version 1.3
|
||||
---------------------
|
||||
|
||||
- This version implements a separate interrupt stack. The interrupt
|
||||
dispatch code saves the current task's state on to the task's own
|
||||
stack and then switches to the interrupt stack for the interrupt
|
||||
processing. Nested interrupts will continue to use the interrupt
|
||||
stack. This helps to reduce the sizes of task stacks, since task
|
||||
stacks no longer have to account for space to accommodate possible
|
||||
nested interrupts. The size of the interrupt stack is controlled
|
||||
by a config parameter.
|
||||
|
||||
|
||||
Notes for version 1.2
|
||||
---------------------
|
||||
|
||||
- This version supports FreeRTOS version 8.1.2.
|
||||
|
||||
- This version supports both CALL0 and windowed Xtensa configurations.
|
||||
|
||||
- This version supports thread safe operation for the Newlib C library.
|
||||
|
||||
- This version introduces an API for installing low/medium priority
|
||||
interrupt handlers and exception handlers, which can be written in C.
|
||||
See xtensa_api.h for details.
|
||||
|
||||
- This version supports software prioritization of interrupts at the
|
||||
same level. Define XT_USE_SWPRI to use this feature. Higher-numbered
|
||||
interrupts are handled at a higher priority than lower-numbered ones.
|
||||
|
||||
- The FreeRTOS demo application requires a stack size of at least 4 KB.
|
||||
The standalone tests should be able to run with smaller stack sizes.
|
||||
The minimum stack size depends on the specific Xtensa configuration.
|
||||
Adjust the stack size of your application as required.
|
||||
|
||||
- The examples are all defined with a heap size of 256 KB. This could
|
||||
be a problem with Xtensa configurations that have only small amounts
|
||||
of memory. Adjust the heap size to suit your platform and application.
|
||||
There is an example of a small-footprint configuration in the directory
|
||||
Xtensa_XCC_small.
|
||||
|
||||
- NOTE: Code overlay support is not yet enabled for this port, even though
|
||||
the support code is present. This feature is not enabled nor tested.
|
||||
Do not define XT_USE_OVLY when building.
|
||||
|
||||
-End-
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xtensa-specific API for RTOS ports.
|
||||
*/
|
||||
|
||||
#ifndef __XTENSA_API_H__
|
||||
#define __XTENSA_API_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <xtensa/hal.h>
|
||||
|
||||
#include "mpu_wrappers.h"
|
||||
#include "xtensa_context.h"
|
||||
|
||||
|
||||
/* Typedef for C-callable interrupt handler function */
|
||||
typedef void (*xt_handler)(void *);
|
||||
|
||||
/* Typedef for C-callable exception handler function */
|
||||
typedef void (*xt_exc_handler)(XtExcFrame *);
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to set a handler for the specified exception.
|
||||
|
||||
n - Exception number (type)
|
||||
f - Handler function address, NULL to uninstall handler.
|
||||
|
||||
The handler will be passed a pointer to the exception frame, which is created
|
||||
on the stack of the thread that caused the exception.
|
||||
|
||||
If the handler returns, the thread context will be restored and the faulting
|
||||
instruction will be retried. Any values in the exception frame that are
|
||||
modified by the handler will be restored as part of the context. For details
|
||||
of the exception frame structure see xtensa_context.h.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern xt_exc_handler xt_set_exception_handler( uint32_t n, xt_exc_handler f ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to set a handler for the specified interrupt.
|
||||
|
||||
n - Interrupt number.
|
||||
f - Handler function address, NULL to uninstall handler.
|
||||
arg - Argument to be passed to handler.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern xt_handler xt_set_interrupt_handler( uint32_t n, xt_handler f, void * arg ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to enable the specified interrupt.
|
||||
|
||||
intnum - Interrupt number to be enabled.
|
||||
|
||||
Returns: Nothing.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern void xt_interrupt_enable( uint32_t intnum ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to disable the specified interrupt.
|
||||
|
||||
intnum - Interrupt number to be disabled.
|
||||
|
||||
Returns: Nothing.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern void xt_interrupt_disable( uint32_t intnum ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to check the enable state of the specified interrupt.
|
||||
|
||||
intnum - Interrupt number to be checked.
|
||||
|
||||
Returns: 1 if the specified interrupt is enabled, zero if the interrupt is
|
||||
disabled, zero if the interrupt number is invalid.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
uint32_t
|
||||
xt_interrupt_enabled( uint32_t intnum ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to trigger the specified (s/w) interrupt.
|
||||
|
||||
intnum - Interrupt number to be triggered.
|
||||
|
||||
Returns: Nothing.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern void xt_interrupt_trigger( uint32_t intnum ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Call this function to clear the specified (s/w or edge-triggered)
|
||||
interrupt.
|
||||
|
||||
intnum - Interrupt number to be cleared.
|
||||
|
||||
Returns: Nothing.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern void xt_interrupt_clear( uint32_t intnum ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Update CPU core/timer frequency.
|
||||
|
||||
This is implemented when configUSE_TICKLESS_IDLE is set to 1.
|
||||
XT_CLOCK_FREQ or xtbsp_clock_freq_hz must return new clock frequency
|
||||
when this function is called.
|
||||
|
||||
This function should be called as soon as the core frequency has changed.
|
||||
It is safe to call it from an interrupt service routine.
|
||||
It will update deadline of the internal tick timer and cache new core
|
||||
frequency.
|
||||
|
||||
Returns: Nothing
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
extern void xt_update_clock_frequency( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* These map directly to HAL functions.
|
||||
*/
|
||||
#define xt_get_ccount xthal_get_ccount
|
||||
#define xt_get_ccompare(t) xthal_get_ccompare(t)
|
||||
#define xt_set_ccompare(t,v) xthal_set_ccompare(t,v)
|
||||
|
||||
|
||||
#endif /* __XTENSA_API_H__ */
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration-specific information for Xtensa build. This file must be
|
||||
* included in FreeRTOSConfig.h to properly set up the config-dependent
|
||||
* parameters correctly.
|
||||
*
|
||||
* NOTE: To enable thread-safe C library support, XT_USE_THREAD_SAFE_CLIB must
|
||||
* be defined to be > 0 somewhere above or on the command line.
|
||||
*/
|
||||
|
||||
#ifndef XTENSA_CONFIG_H
|
||||
#define XTENSA_CONFIG_H
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#include <xtensa/hal.h>
|
||||
#include <xtensa/config/core.h>
|
||||
#include <xtensa/config/system.h> /* required for XSHAL_CLIB */
|
||||
|
||||
#include "xtensa_context.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* STACK REQUIREMENTS
|
||||
*
|
||||
* This section defines the minimum stack size, and the extra space required to
|
||||
* be allocated for saving coprocessor state on the stack when needed. The sizes
|
||||
* are in bytes.
|
||||
*
|
||||
* Stack sizes for individual tasks should be derived from these minima based on
|
||||
* the maximum call depth of the task. A minimum stack size is defined by the
|
||||
* XT_STACK_MIN_SIZE value. This minimum is based on the requirement for a task
|
||||
* that calls nothing else but can be interrupted.
|
||||
*
|
||||
* If the Xtensa processor configuration includes coprocessors, then space is
|
||||
* allocated to save the coprocessor state on the stack.
|
||||
*
|
||||
* If thread safety is enabled for the C runtime library, (XT_USE_THREAD_SAFE_CLIB
|
||||
* is defined) then space is allocated to save the C library context in the TCB.
|
||||
*
|
||||
* Allocating insufficient stack space is a common source of hard-to-find errors.
|
||||
* During development, it is best to enable the FreeRTOS stack checking features.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* XT_USE_THREAD_SAFE_CLIB -- Define this to a nonzero value to enable thread-safe
|
||||
* use of the C library.
|
||||
*
|
||||
* NOTE: The Xtensa toolchain supports multiple C libraries and not all of them
|
||||
* support thread safety. Check your core configuration to see which C library
|
||||
* was chosen for your system.
|
||||
*
|
||||
* XT_STACK_MIN_SIZE -- The minimum stack size for any task. It is recommended
|
||||
* that you do not use a stack smaller than this for any
|
||||
* task. In case you want to use stacks smaller than this
|
||||
* size, you must verify that the smaller size(s) will work
|
||||
* under all operating conditions.
|
||||
*
|
||||
* XT_STACK_EXTRA -- The amount of extra stack space to be allocated for the
|
||||
* system overhead (coprocessor state, exception frame etc.).
|
||||
* Add this to the amount of stack space required by the
|
||||
* task itself.
|
||||
*
|
||||
* XT_SYSTEM_STACK_SIZE -- The size of the system interrupt stack. You will need to
|
||||
* size this according to your system requirements.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
/* Extra space required for interrupt/exception hooks. */
|
||||
#ifdef XT_INTEXC_HOOKS
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
#define STK_INTEXC_EXTRA 0x200
|
||||
#else
|
||||
#define STK_INTEXC_EXTRA 0x180
|
||||
#endif
|
||||
#else
|
||||
#define STK_INTEXC_EXTRA 0
|
||||
#endif
|
||||
|
||||
/* Check C library thread safety support and compute size of C library save area.
|
||||
For the supported libraries, we enable thread safety by default, and this can
|
||||
be overridden from the compiler/make command line. */
|
||||
#if (XSHAL_CLIB == XTHAL_CLIB_NEWLIB) || (XSHAL_CLIB == XTHAL_CLIB_XCLIB)
|
||||
#ifndef XT_USE_THREAD_SAFE_CLIB
|
||||
#define XT_USE_THREAD_SAFE_CLIB 1
|
||||
#endif
|
||||
#else
|
||||
#define XT_USE_THREAD_SAFE_CLIB 0
|
||||
#endif
|
||||
|
||||
#if XT_USE_THREAD_SAFE_CLIB > 0u
|
||||
#if XSHAL_CLIB == XTHAL_CLIB_XCLIB
|
||||
#define XT_HAVE_THREAD_SAFE_CLIB 1
|
||||
#if !defined __ASSEMBLER__
|
||||
#include <sys/reent.h>
|
||||
#define XT_CLIB_CONTEXT_AREA_SIZE ((sizeof(struct _reent) + 15) + (-16))
|
||||
#define XT_CLIB_GLOBAL_PTR _reent_ptr
|
||||
#define _REENT_INIT_PTR _init_reent
|
||||
#define _impure_ptr _reent_ptr
|
||||
|
||||
void _reclaim_reent(struct _reent * ptr);
|
||||
#endif
|
||||
#elif XSHAL_CLIB == XTHAL_CLIB_NEWLIB
|
||||
#define XT_HAVE_THREAD_SAFE_CLIB 1
|
||||
#if !defined __ASSEMBLER__
|
||||
#include <sys/reent.h>
|
||||
#define XT_CLIB_CONTEXT_AREA_SIZE ((sizeof(struct _reent) + 15) + (-16))
|
||||
#define XT_CLIB_GLOBAL_PTR _impure_ptr
|
||||
|
||||
void _reclaim_reent(struct _reent * ptr);
|
||||
#endif
|
||||
#else
|
||||
#define XT_HAVE_THREAD_SAFE_CLIB 0
|
||||
#error The selected C runtime library is not thread safe.
|
||||
#endif
|
||||
#else
|
||||
#define XT_CLIB_CONTEXT_AREA_SIZE 0
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
Extra size -- interrupt frame plus coprocessor save area plus hook space.
|
||||
NOTE: Make sure XT_INTEXC_HOOKS is undefined unless you really need the hooks.
|
||||
------------------------------------------------------------------------------*/
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
#define XT_XTRA_SIZE (XT_STK_FRMSZ + STK_INTEXC_EXTRA + 0x10 + XT_CP_SIZE)
|
||||
#else
|
||||
#define XT_XTRA_SIZE (XT_STK_FRMSZ + STK_INTEXC_EXTRA + 0x20 + XT_CP_SIZE)
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
Space allocated for user code -- function calls and local variables.
|
||||
NOTE: This number can be adjusted to suit your needs. You must verify that the
|
||||
amount of space you reserve is adequate for the worst-case conditions in your
|
||||
application.
|
||||
NOTE: The windowed ABI requires more stack, since space has to be reserved
|
||||
for spilling register windows.
|
||||
------------------------------------------------------------------------------*/
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
#define XT_USER_SIZE 0x200
|
||||
#else
|
||||
#define XT_USER_SIZE 0x400
|
||||
#endif
|
||||
|
||||
/* Minimum recommended stack size. */
|
||||
#define XT_STACK_MIN_SIZE ((XT_XTRA_SIZE + XT_USER_SIZE) / sizeof(unsigned char))
|
||||
|
||||
/* OS overhead. */
|
||||
#define XT_STACK_EXTRA (XT_XTRA_SIZE)
|
||||
|
||||
/* Default system (interrupt) stack size */
|
||||
#define XT_SYSTEM_STACK_SIZE 0x400
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* XTENSA_CONFIG_H */
|
||||
+457
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* XTENSA CONTEXT SAVE AND RESTORE ROUTINES
|
||||
*
|
||||
* Low-level Call0 functions for handling generic context save and restore of
|
||||
* registers not specifically addressed by the interrupt vectors and handlers.
|
||||
* Those registers (not handled by these functions) are PC, PS, A0, A1 (SP).
|
||||
* Except for the calls to RTOS functions, this code is generic to Xtensa.
|
||||
*
|
||||
* Note that in Call0 ABI, interrupt handlers are expected to preserve the callee-
|
||||
* save regs (A12-A15), which is always the case if the handlers are coded in C.
|
||||
* However A12, A13 are made available as scratch registers for interrupt dispatch
|
||||
* code, so are presumed saved anyway, and are always restored even in Call0 ABI.
|
||||
* Only A14, A15 are truly handled as callee-save regs.
|
||||
*
|
||||
* Because Xtensa is a configurable architecture, this port supports all user
|
||||
* generated configurations (except restrictions stated in the release notes).
|
||||
* This is accomplished by conditional compilation using macros and functions
|
||||
* defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
|
||||
* Only the processor state included in your configuration is saved and restored,
|
||||
* including any processor state added by user configuration options or TIE.
|
||||
*/
|
||||
|
||||
/* Warn nicely if this file gets named with a lowercase .s instead of .S: */
|
||||
#define NOERROR #
|
||||
NOERROR: .error "C preprocessor needed for this file: make sure its filename\
|
||||
ends in uppercase .S, or use the compiler's -x assembler-with-cpp option."
|
||||
|
||||
|
||||
#include "xtensa_rtos.h"
|
||||
#include "portmacro.h"
|
||||
#include <xtensa/core-macros.h>
|
||||
|
||||
#ifdef XT_USE_OVLY
|
||||
#if (XCHAL_SW_VERSION >= 1504000)
|
||||
#include <xtensa/overlay.h>
|
||||
#else
|
||||
#warning liboverlay bugfixes in RJ.4 tools are recommended
|
||||
#endif
|
||||
#include <xtensa/overlay_os_asm.h>
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
.section "privileged_functions"
|
||||
#else
|
||||
.text
|
||||
.literal_position
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
_xt_context_save
|
||||
|
||||
!! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
|
||||
|
||||
Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the
|
||||
interrupt stack frame defined in xtensa_rtos.h.
|
||||
Its counterpart is _xt_context_restore (which also restores A12, A13).
|
||||
|
||||
Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame.
|
||||
This function preserves A12 & A13 in order to provide the caller with 2 scratch
|
||||
regs that need not be saved over the call to this function. The choice of which
|
||||
2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw,
|
||||
to avoid moving data more than necessary. Caller can assign regs accordingly.
|
||||
|
||||
Entry Conditions:
|
||||
A0 = Return address in caller.
|
||||
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
||||
Original A12, A13 have already been saved in the interrupt stack frame.
|
||||
Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the
|
||||
point of interruption.
|
||||
If windowed ABI, PS.EXCM = 1 (exceptions disabled).
|
||||
|
||||
Exit conditions:
|
||||
A0 = Return address in caller.
|
||||
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
||||
A12, A13 as at entry (preserved).
|
||||
If windowed ABI, PS.EXCM = 1 (exceptions disabled).
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
.global _xt_context_save
|
||||
.type _xt_context_save,@function
|
||||
.align 4
|
||||
_xt_context_save:
|
||||
|
||||
s32i a2, sp, XT_STK_A2
|
||||
s32i a3, sp, XT_STK_A3
|
||||
s32i a4, sp, XT_STK_A4
|
||||
s32i a5, sp, XT_STK_A5
|
||||
s32i a6, sp, XT_STK_A6
|
||||
s32i a7, sp, XT_STK_A7
|
||||
s32i a8, sp, XT_STK_A8
|
||||
s32i a9, sp, XT_STK_A9
|
||||
s32i a10, sp, XT_STK_A10
|
||||
s32i a11, sp, XT_STK_A11
|
||||
|
||||
/*
|
||||
Call0 ABI callee-saved regs a12-15 do not need to be saved here.
|
||||
a12-13 are the caller's responsibility so it can use them as scratch.
|
||||
So only need to save a14-a15 here for Windowed ABI (not Call0).
|
||||
*/
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
s32i a14, sp, XT_STK_A14
|
||||
s32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
|
||||
rsr a3, SAR
|
||||
s32i a3, sp, XT_STK_SAR
|
||||
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
rsr a3, LBEG
|
||||
s32i a3, sp, XT_STK_LBEG
|
||||
rsr a3, LEND
|
||||
s32i a3, sp, XT_STK_LEND
|
||||
rsr a3, LCOUNT
|
||||
s32i a3, sp, XT_STK_LCOUNT
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_EXCLUSIVE
|
||||
/* Save and clear state of ATOMCTL */
|
||||
movi a3, 0
|
||||
getex a3
|
||||
s32i a3, sp, XT_STK_ATOMCTL
|
||||
#endif
|
||||
|
||||
#ifdef XT_USE_SWPRI
|
||||
/* Save virtual priority mask */
|
||||
movi a3, xt_vpri_mask
|
||||
l32i a3, a3, 0
|
||||
s32i a3, sp, XT_STK_VPRI
|
||||
#endif
|
||||
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
|
||||
mov a9, a0 /* preserve ret addr */
|
||||
#endif
|
||||
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
/*
|
||||
To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
|
||||
Need to save a9,12,13 temporarily (in frame temps) and recover originals.
|
||||
Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow
|
||||
and underflow exceptions disabled (assured by PS.EXCM == 1).
|
||||
*/
|
||||
s32i a12, sp, XT_STK_TMP0 /* temp. save stuff in stack frame */
|
||||
s32i a13, sp, XT_STK_TMP1
|
||||
s32i a9, sp, XT_STK_TMP2
|
||||
|
||||
/*
|
||||
Save the overlay state if we are supporting overlays. Since we just saved
|
||||
three registers, we can conveniently use them here. Note that as of now,
|
||||
overlays only work for windowed calling ABI.
|
||||
*/
|
||||
#ifdef XT_USE_OVLY
|
||||
l32i a9, sp, XT_STK_PC /* recover saved PC */
|
||||
_xt_overlay_get_state a9, a12, a13
|
||||
s32i a9, sp, XT_STK_OVLY /* save overlay state */
|
||||
#if (defined XT_OV_SCRATCH) /* In newer liboverlay versions */
|
||||
rsr a9, XT_OV_SCRATCH /* save XT_OV_SCRATCH register */
|
||||
s32i a9, sp, XT_STK_OVLY_SCRATCH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */
|
||||
l32i a13, sp, XT_STK_A13
|
||||
l32i a9, sp, XT_STK_A9
|
||||
addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */
|
||||
call0 xthal_window_spill_nw /* preserves only a4,5,8,9,12,13 */
|
||||
addi sp, sp, -XT_STK_FRMSZ
|
||||
l32i a12, sp, XT_STK_TMP0 /* recover stuff from stack frame */
|
||||
l32i a13, sp, XT_STK_TMP1
|
||||
l32i a9, sp, XT_STK_TMP2
|
||||
#endif
|
||||
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0
|
||||
/*
|
||||
NOTE: Normally the xthal_save_extra_nw macro only affects address
|
||||
registers a2-a5. It is theoretically possible for Xtensa processor
|
||||
designers to write TIE that causes more address registers to be
|
||||
affected, but it is generally unlikely. If that ever happens,
|
||||
more registers need to be saved/restored around this macro invocation.
|
||||
Here we assume a9,12,13 are preserved.
|
||||
Future Xtensa tools releases might limit the regs that can be affected.
|
||||
*/
|
||||
addi a2, sp, XT_STK_EXTRA /* where to save it */
|
||||
# if XCHAL_EXTRA_SA_ALIGN > 16
|
||||
movi a3, -XCHAL_EXTRA_SA_ALIGN
|
||||
and a2, a2, a3 /* align dynamically >16 bytes */
|
||||
# endif
|
||||
call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */
|
||||
#endif
|
||||
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
|
||||
mov a0, a9 /* retrieve ret addr */
|
||||
#endif
|
||||
|
||||
ret
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
_xt_context_restore
|
||||
|
||||
!! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
|
||||
|
||||
Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0
|
||||
ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt
|
||||
stack frame defined in xtensa_rtos.h .
|
||||
Its counterpart is _xt_context_save (whose caller saved A12, A13).
|
||||
|
||||
Caller is responsible to restore PC, PS, A0, A1 (SP).
|
||||
|
||||
Entry Conditions:
|
||||
A0 = Return address in caller.
|
||||
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
||||
|
||||
Exit conditions:
|
||||
A0 = Return address in caller.
|
||||
A1 = Stack pointer of interrupted thread or handler ("interruptee").
|
||||
Other processor state except PC, PS, A0, A1 (SP), is as at the point
|
||||
of interruption.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
.global _xt_context_restore
|
||||
.type _xt_context_restore,@function
|
||||
.align 4
|
||||
_xt_context_restore:
|
||||
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0
|
||||
/*
|
||||
NOTE: Normally the xthal_restore_extra_nw macro only affects address
|
||||
registers a2-a5. It is theoretically possible for Xtensa processor
|
||||
designers to write TIE that causes more address registers to be
|
||||
affected, but it is generally unlikely. If that ever happens,
|
||||
more registers need to be saved/restored around this macro invocation.
|
||||
Here we only assume a13 is preserved.
|
||||
Future Xtensa tools releases might limit the regs that can be affected.
|
||||
*/
|
||||
mov a13, a0 /* preserve ret addr */
|
||||
addi a2, sp, XT_STK_EXTRA /* where to find it */
|
||||
# if XCHAL_EXTRA_SA_ALIGN > 16
|
||||
movi a3, -XCHAL_EXTRA_SA_ALIGN
|
||||
and a2, a2, a3 /* align dynamically >16 bytes */
|
||||
# endif
|
||||
call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */
|
||||
mov a0, a13 /* retrieve ret addr */
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
l32i a2, sp, XT_STK_LBEG
|
||||
l32i a3, sp, XT_STK_LEND
|
||||
wsr a2, LBEG
|
||||
l32i a2, sp, XT_STK_LCOUNT
|
||||
wsr a3, LEND
|
||||
wsr a2, LCOUNT
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_EXCLUSIVE
|
||||
/* Restore state of ATOMCTL */
|
||||
l32i a2, sp, XT_STK_ATOMCTL
|
||||
getex a2
|
||||
#endif
|
||||
|
||||
#ifdef XT_USE_OVLY
|
||||
/*
|
||||
If we are using overlays, this is a good spot to check if we need
|
||||
to restore an overlay for the incoming task. Here we have a bunch
|
||||
of registers to spare. Note that this step is going to use a few
|
||||
bytes of storage below SP (SP-20 to SP-32) if an overlay is going
|
||||
to be restored.
|
||||
*/
|
||||
l32i a2, sp, XT_STK_PC /* retrieve PC */
|
||||
l32i a3, sp, XT_STK_PS /* retrieve PS */
|
||||
l32i a4, sp, XT_STK_OVLY /* retrieve overlay state */
|
||||
l32i a5, sp, XT_STK_A1 /* retrieve stack ptr */
|
||||
_xt_overlay_check_map a2, a3, a4, a5, a6
|
||||
s32i a2, sp, XT_STK_PC /* save updated PC */
|
||||
s32i a3, sp, XT_STK_PS /* save updated PS */
|
||||
#if (defined XT_OV_SCRATCH) /* In newer liboverlay versions */
|
||||
l32i a6, sp, XT_STK_OVLY_SCRATCH
|
||||
wsr a6, XT_OV_SCRATCH /* restore XT_OV_SCRATCH register */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef XT_USE_SWPRI
|
||||
/* Restore virtual interrupt priority and interrupt enable */
|
||||
movi a3, xt_intdata
|
||||
l32i a4, a3, 0 /* a4 = xt_intenable */
|
||||
l32i a5, sp, XT_STK_VPRI /* a5 = saved xt_vpri_mask */
|
||||
and a4, a4, a5
|
||||
wsr a4, INTENABLE /* update INTENABLE */
|
||||
s32i a5, a3, 4 /* restore xt_vpri_mask */
|
||||
#endif
|
||||
|
||||
l32i a3, sp, XT_STK_SAR
|
||||
l32i a2, sp, XT_STK_A2
|
||||
wsr a3, SAR
|
||||
l32i a3, sp, XT_STK_A3
|
||||
l32i a4, sp, XT_STK_A4
|
||||
l32i a5, sp, XT_STK_A5
|
||||
l32i a6, sp, XT_STK_A6
|
||||
l32i a7, sp, XT_STK_A7
|
||||
l32i a8, sp, XT_STK_A8
|
||||
l32i a9, sp, XT_STK_A9
|
||||
l32i a10, sp, XT_STK_A10
|
||||
l32i a11, sp, XT_STK_A11
|
||||
|
||||
/*
|
||||
Call0 ABI callee-saved regs a12-15 do not need to be restored here.
|
||||
However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(),
|
||||
so need to be restored anyway, despite being callee-saved in Call0.
|
||||
*/
|
||||
l32i a12, sp, XT_STK_A12
|
||||
l32i a13, sp, XT_STK_A13
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
l32i a14, sp, XT_STK_A14
|
||||
l32i a15, sp, XT_STK_A15
|
||||
#endif
|
||||
|
||||
ret
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
_xt_coproc_init
|
||||
|
||||
Initializes global co-processor management data, setting all co-processors
|
||||
to "unowned". Leaves CPENABLE as it found it (does NOT clear it).
|
||||
|
||||
Called during initialization of the RTOS, before any threads run.
|
||||
|
||||
This may be called from normal Xtensa single-threaded application code which
|
||||
might use co-processors. The Xtensa run-time initialization enables all
|
||||
co-processors. They must remain enabled here, else a co-processor exception
|
||||
might occur outside of a thread, which the exception handler doesn't expect.
|
||||
|
||||
Entry Conditions:
|
||||
Xtensa single-threaded run-time environment is in effect.
|
||||
No thread is yet running.
|
||||
|
||||
Exit conditions:
|
||||
None.
|
||||
|
||||
Obeys ABI conventions per prototype:
|
||||
void _xt_coproc_init(void)
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
|
||||
.global _xt_coproc_init
|
||||
.type _xt_coproc_init,@function
|
||||
.align 4
|
||||
_xt_coproc_init:
|
||||
ENTRY0
|
||||
|
||||
/* Initialize thread co-processor ownerships to 0 (unowned). */
|
||||
movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */
|
||||
addi a3, a2, XCHAL_CP_MAX << 2 /* a3 = top+1 of owner array */
|
||||
movi a4, 0 /* a4 = 0 (unowned) */
|
||||
1: s32i a4, a2, 0
|
||||
addi a2, a2, 4
|
||||
bltu a2, a3, 1b
|
||||
|
||||
RET0
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
_xt_coproc_release
|
||||
|
||||
Releases any and all co-processors owned by a given thread. The thread is
|
||||
identified by it's co-processor state save area defined in xtensa_context.h .
|
||||
|
||||
Must be called before a thread's co-proc save area is deleted to avoid
|
||||
memory corruption when the exception handler tries to save the state.
|
||||
May be called when a thread terminates or completes but does not delete
|
||||
the co-proc save area, to avoid the exception handler having to save the
|
||||
thread's co-proc state before another thread can use it (optimization).
|
||||
|
||||
Entry Conditions:
|
||||
A2 = Pointer to base of co-processor state save area.
|
||||
|
||||
Exit conditions:
|
||||
None.
|
||||
|
||||
Obeys ABI conventions per prototype:
|
||||
void _xt_coproc_release(void * coproc_sa_base)
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
|
||||
.global _xt_coproc_release
|
||||
.type _xt_coproc_release,@function
|
||||
.align 4
|
||||
_xt_coproc_release:
|
||||
ENTRY0 /* a2 = base of save area */
|
||||
|
||||
movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */
|
||||
addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */
|
||||
movi a5, 0 /* a5 = 0 (unowned) */
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
movi a6, PS_DI
|
||||
xps a6, a6 /* lock interrupts */
|
||||
#else
|
||||
rsil a6, XT_IRQ_LOCK_LEVEL /* lock interrupts */
|
||||
#endif
|
||||
|
||||
1: l32i a7, a3, 0 /* a7 = owner at a3 */
|
||||
bne a2, a7, 2f /* if (coproc_sa_base == owner) */
|
||||
s32i a5, a3, 0 /* owner = unowned */
|
||||
2: addi a3, a3, 1<<2 /* a3 = next entry in owner array */
|
||||
bltu a3, a4, 1b /* repeat until end of array */
|
||||
|
||||
3:
|
||||
wsr a6, PS /* restore interrupts */
|
||||
rsync
|
||||
|
||||
RET0
|
||||
|
||||
#endif
|
||||
+571
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES
|
||||
*
|
||||
* This header contains definitions and macros for use primarily by Xtensa
|
||||
* RTOS assembly source files. It includes and uses the Xtensa hardware
|
||||
* abstraction layer (HAL) to deal with config specifics. It may also be
|
||||
* included in C source files.
|
||||
*
|
||||
* NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes.
|
||||
*/
|
||||
|
||||
#ifndef XTENSA_CONTEXT_H
|
||||
#define XTENSA_CONTEXT_H
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#include <xtensa/coreasm.h>
|
||||
#endif
|
||||
|
||||
#include <xtensa/config/tie.h>
|
||||
#include <xtensa/corebits.h>
|
||||
#include <xtensa/config/system.h>
|
||||
|
||||
|
||||
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
|
||||
#ifdef __ASSEMBLER__
|
||||
#define ALIGNUP(n, val) (((val) + (n)-1) & -(n))
|
||||
#else
|
||||
#define ALIGNUP(n, val) (((val) + (n)-1) & (unsigned)-(n))
|
||||
#endif
|
||||
|
||||
|
||||
/* SYSCALL definitions for privilige support */
|
||||
#define SYSCALL_raise_priv 10
|
||||
#define SYSCALL_is_priv 12
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Macros that help define structures for both C and assembler.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
|
||||
|
||||
#define XSTRUCT_BEGIN .pushsection .text; .struct 0
|
||||
#define XSTRUCT_FIELD(ctype,size,asname,name) asname: .space size
|
||||
#define XSTRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
|
||||
#define XSTRUCT_END(sname) sname##Size:; .popsection
|
||||
|
||||
#else
|
||||
|
||||
#define XSTRUCT_BEGIN typedef struct {
|
||||
#define XSTRUCT_FIELD(ctype,size,asname,name) ctype name;
|
||||
#define XSTRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
|
||||
#define XSTRUCT_END(sname) } sname;
|
||||
|
||||
#endif //_ASMLANGUAGE || __ASSEMBLER__
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
INTERRUPT/EXCEPTION STACK FRAME FOR A THREAD OR NESTED INTERRUPT
|
||||
|
||||
A stack frame of this structure is allocated for any interrupt or exception.
|
||||
It goes on the current stack. If the RTOS has a system stack for handling
|
||||
interrupts, every thread stack must allow space for just one interrupt stack
|
||||
frame, then nested interrupt stack frames go on the system stack.
|
||||
|
||||
The frame includes basic registers (explicit) and "extra" registers introduced
|
||||
by user TIE or the use of the MAC16 option in the user's Xtensa config.
|
||||
The frame size is minimized by omitting regs not applicable to user's config.
|
||||
|
||||
For Windowed ABI, this stack frame includes the interruptee's base save area,
|
||||
another base save area to manage gcc nested functions, and a little temporary
|
||||
space to help manage the spilling of the register windows.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
|
||||
XSTRUCT_BEGIN
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_EXIT, exit) /* exit point for dispatch */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_PC, pc) /* return PC */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_PS, ps) /* return PS */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A0, a0)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A1, a1) /* stack pointer before interrupt */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A2, a2)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A3, a3)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A4, a4)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A5, a5)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A6, a6)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A7, a7)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A8, a8)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A9, a9)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A10, a10)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A11, a11)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A12, a12)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A13, a13)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A14, a14)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A15, a15)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_SAR, sar)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LEND, lend)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
|
||||
#endif
|
||||
#if XCHAL_HAVE_EXCLUSIVE
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_ATOMCTL, atomctl)
|
||||
#endif
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
/* Temporary space for saving stuff during window spill */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2)
|
||||
#endif
|
||||
#ifdef XT_USE_SWPRI
|
||||
/* Storage for virtual priority mask */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_VPRI, vpri)
|
||||
#endif
|
||||
#ifdef XT_USE_OVLY
|
||||
/* Storage for overlay state */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_OVLY, ovly)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_OVLY_SCRATCH, ovly_scratch)
|
||||
#endif
|
||||
XSTRUCT_END(XtExcFrame)
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA2 */
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
|
||||
XSTRUCT_BEGIN
|
||||
#if defined(__XTENSA_WINDOWED_ABI__) && portUSING_MPU_WRAPPERS
|
||||
/* Temporary space for syscall argument/return value */
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A2, a2)
|
||||
#endif
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_ATOMCTL, atomctl)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LEND, lend)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_PC, pc)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_PS, ps)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A0, a0)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A1, a1)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A2, a2)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A3, a3)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A4, a4)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A5, a5)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A6, a6)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A7, a7)
|
||||
#endif
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A8, a8)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A9, a9)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A10, a10)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A11, a11)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A12, a12)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A13, a13)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A14, a14)
|
||||
XSTRUCT_FIELD (long, 4, XT_STK_A15, a15)
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
XSTRUCT_AFIELD(long, 4, XT_STK_SPILL, spill, 8)
|
||||
#endif
|
||||
XSTRUCT_END(XtExcFrame)
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA3 */
|
||||
|
||||
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
|
||||
#define XT_STK_NEXT1 XtExcFrameSize
|
||||
#else
|
||||
#define XT_STK_NEXT1 sizeof(XtExcFrame)
|
||||
#endif
|
||||
|
||||
|
||||
/* Allocate extra storage if needed for non-CP TIE state. Allow for alignment
|
||||
padding as needed.
|
||||
*/
|
||||
#if XCHAL_EXTRA_SA_SIZE != 0
|
||||
|
||||
#if XCHAL_EXTRA_SA_ALIGN <= 16
|
||||
#define XT_STK_EXTRA ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1)
|
||||
#else
|
||||
/* If need more alignment than stack, add space for dynamic alignment */
|
||||
#define XT_STK_EXTRA (ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + XCHAL_EXTRA_SA_ALIGN)
|
||||
#endif
|
||||
#define XT_STK_NEXT2 (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE)
|
||||
|
||||
#else
|
||||
|
||||
/* No extra storage required */
|
||||
#define XT_STK_NEXT2 XT_STK_NEXT1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
|
||||
/* Total frame size */
|
||||
#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2))
|
||||
|
||||
/* Exception/interrupt frame size */
|
||||
#define XT_STK_XFRM_SZ XT_STK_NEXT1
|
||||
|
||||
/* Extra save area size (including alignment padding) */
|
||||
#define XT_STK_XTRA_SZ (XT_STK_FRMSZ - XT_STK_XFRM_SZ)
|
||||
|
||||
/* Alignment padding area size */
|
||||
#if XCHAL_EXTRA_SA_SIZE != 0
|
||||
#define XT_STK_ALIGN_SZ (XT_STK_EXTRA - XT_STK_NEXT1)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
This is the frame size. Add space for 4 registers (interruptee's base save
|
||||
area) and some space for gcc nested functions if any.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2) + 0x20)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
CO-PROCESSOR STATE SAVE AREA FOR A THREAD
|
||||
|
||||
The RTOS must provide an area per thread to save the state of co-processors
|
||||
when that thread does not have control. Co-processors are context-switched
|
||||
lazily (on demand) only when a new thread uses a co-processor instruction,
|
||||
otherwise a thread retains ownership of the co-processor even when it loses
|
||||
control of the processor. An Xtensa co-processor exception is triggered when
|
||||
any co-processor instruction is executed by a thread that is not the owner,
|
||||
and the context switch of that co-processor is then peformed by the handler.
|
||||
Ownership represents which thread's state is currently in the co-processor.
|
||||
|
||||
Co-processors may not be used by interrupt or exception handlers. If an
|
||||
co-processor instruction is executed by an interrupt or exception handler,
|
||||
the co-processor exception handler will trigger a kernel panic and freeze.
|
||||
This restriction is introduced to reduce the overhead of saving and restoring
|
||||
co-processor state (which can be quite large) and in particular remove that
|
||||
overhead from interrupt handlers.
|
||||
|
||||
The co-processor state save area may be in any convenient per-thread location
|
||||
such as in the thread control block or above the thread stack area. It need
|
||||
not be in the interrupt stack frame since interrupts don't use co-processors.
|
||||
|
||||
Along with the save area for each co-processor, two bitmasks with flags per
|
||||
co-processor (laid out as in the CPENABLE reg) help manage context-switching
|
||||
co-processors as efficiently as possible:
|
||||
|
||||
XT_CPENABLE
|
||||
The contents of a non-running thread's CPENABLE register.
|
||||
It represents the co-processors owned (and whose state is still needed)
|
||||
by the thread. When a thread is preempted, its CPENABLE is saved here.
|
||||
When a thread solicits a context-swtich, its CPENABLE is cleared - the
|
||||
compiler has saved the (caller-saved) co-proc state if it needs to.
|
||||
When a non-running thread loses ownership of a CP, its bit is cleared.
|
||||
When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg.
|
||||
Avoids co-processor exceptions when no change of ownership is needed.
|
||||
|
||||
XT_CPSTORED
|
||||
A bitmask with the same layout as CPENABLE, a bit per co-processor.
|
||||
Indicates whether the state of each co-processor is saved in the state
|
||||
save area. When a thread enters the kernel, only the state of co-procs
|
||||
still enabled in CPENABLE is saved. When the co-processor exception
|
||||
handler assigns ownership of a co-processor to a thread, it restores
|
||||
the saved state only if this bit is set, and clears this bit.
|
||||
|
||||
XT_CP_CS_ST
|
||||
A bitmask with the same layout as CPENABLE, a bit per co-processor.
|
||||
Indicates whether callee-saved state is saved in the state save area.
|
||||
Callee-saved state is saved by itself on a solicited context switch,
|
||||
and restored when needed by the coprocessor exception handler.
|
||||
Unsolicited switches will cause the entire coprocessor to be saved
|
||||
when necessary.
|
||||
|
||||
XT_CP_ASA
|
||||
Pointer to the aligned save area. Allows it to be aligned more than
|
||||
the overall save area (which might only be stack-aligned or TCB-aligned).
|
||||
Especially relevant for Xtensa cores configured with a very large data
|
||||
path that requires alignment greater than 16 bytes (ABI stack alignment).
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
|
||||
/* Offsets of each coprocessor save area within the 'aligned save area': */
|
||||
#define XT_CP0_SA 0
|
||||
#define XT_CP1_SA ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE)
|
||||
#define XT_CP2_SA ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE)
|
||||
#define XT_CP3_SA ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE)
|
||||
#define XT_CP4_SA ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE)
|
||||
#define XT_CP5_SA ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE)
|
||||
#define XT_CP6_SA ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE)
|
||||
#define XT_CP7_SA ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE)
|
||||
#define XT_CP_SA_SIZE ALIGNUP(16, XT_CP7_SA + XCHAL_CP7_SA_SIZE)
|
||||
|
||||
/* Offsets within the overall save area: */
|
||||
#define XT_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */
|
||||
#define XT_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */
|
||||
#define XT_CP_CS_ST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */
|
||||
#define XT_CP_ASA 8 /* (4 bytes) ptr to aligned save area */
|
||||
/* Overall size allows for dynamic alignment: */
|
||||
#define XT_CP_SIZE (12 + XT_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN)
|
||||
#else
|
||||
#define XT_CP_SIZE 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN
|
||||
|
||||
Convenient where the frame size requirements are the same for both ABIs.
|
||||
ENTRY(sz), RET(sz) are for framed functions (have locals or make calls).
|
||||
ENTRY0, RET0 are for frameless functions (no locals, no calls).
|
||||
|
||||
where size = size of stack frame in bytes (must be >0 and aligned to 16).
|
||||
For framed functions the frame is created and the return address saved at
|
||||
base of frame (Call0 ABI) or as determined by hardware (Windowed ABI).
|
||||
For frameless functions, there is no frame and return address remains in a0.
|
||||
Note: Because CPP macros expand to a single line, macros requiring multi-line
|
||||
expansions are implemented as assembler macros.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
/* Call0 */
|
||||
#define ENTRY(sz) entry1 sz
|
||||
.macro entry1 size=0x10
|
||||
addi sp, sp, -\size
|
||||
s32i a0, sp, 0
|
||||
.endm
|
||||
#define ENTRY0
|
||||
#define RET(sz) ret1 sz
|
||||
.macro ret1 size=0x10
|
||||
l32i a0, sp, 0
|
||||
addi sp, sp, \size
|
||||
ret
|
||||
.endm
|
||||
#define RET0 ret
|
||||
#else
|
||||
/* Windowed */
|
||||
#if XCHAL_HAVE_XEA3
|
||||
#define ENTRY(sz) entry sp, (sz + 0x20)
|
||||
#define ENTRY0 entry sp, 0x20
|
||||
#else
|
||||
#define ENTRY(sz) entry sp, (sz + 0x10)
|
||||
#define ENTRY0 entry sp, 0x10
|
||||
#endif
|
||||
#define RET(sz) retw
|
||||
#define RET0 retw
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
This flag is meant for internal use. Have all interrupts be dispatched via a
|
||||
common wrapper, which takes care of doing some OS-specific stuff common to
|
||||
all interrupt handlers. Said stuff cannot safely be handled in the RTOS_ENTER
|
||||
and RTOS_EXIT macros.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#if (defined XT_INTEXC_HOOKS)
|
||||
#define XT_USE_INT_WRAPPER 1
|
||||
#else
|
||||
#define XT_USE_INT_WRAPPER 0
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS > 32) && (defined XT_USE_SWPRI)
|
||||
#error "Software prioritization of interrupts (XT_USE_SWPRI) not supported for XEA2 with > 32 interrupts."
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
#ifdef XT_USE_SWPRI
|
||||
//#warning "Software prioritization of interrupts (XT_USE_SWPRI) not supported for XEA3."
|
||||
#endif
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
|
||||
#include "asm-offsets.h"
|
||||
|
||||
// RTOS-specific entry macro. Use only a8, a12-a14.
|
||||
|
||||
.macro XT_RTOS_INT_ENTER
|
||||
|
||||
.endm
|
||||
|
||||
// RTOS-specific exit macro. Use only a8-a14.
|
||||
// (In call0, a15 holds user SP, must be preserved)
|
||||
|
||||
.macro XT_RTOS_INT_EXIT
|
||||
|
||||
// Check scheduler state and interrupt nest state.
|
||||
|
||||
movi a8, port_xSchedulerRunning
|
||||
movi a9, port_interruptNesting
|
||||
l32i a8, a8, 0 // a8 <- port_xSchedulerRunning
|
||||
beqz a8, .Lnested // scheduler not running, no tasks
|
||||
l32i a8, a9, 0 // a8 <- port_interruptNesting
|
||||
bnez a8, .Lnested // != 0 means nested, skip ahead
|
||||
movi a8, port_yield_flag
|
||||
l32i a9, a8, 0 // a9 <- port_yield_flag
|
||||
beqz a9, 2f // no yield
|
||||
movi a9, 0
|
||||
s32i a9, a8, 0 // zero out for next time
|
||||
j .Lyield // no context save needed
|
||||
2:
|
||||
movi a8, pxCurrentTCB
|
||||
l32i a9, a8, 0 // a9 <- pxCurrentTCB
|
||||
beqz a9, .Lsched // no current, go to scheduler
|
||||
movi a10, port_switch_flag
|
||||
l32i a11, a10, 0 // a11 <- port_switch_flag
|
||||
beqz a11, .Lnested // = 0 means no switch
|
||||
movi a11, 0
|
||||
s32i a11, a10, 0 // zero out for next time
|
||||
|
||||
// Preemption, save remaining state of current (outgoing) thread
|
||||
|
||||
addi a10, a1, -XT_STK_FRMSZ
|
||||
s32i a10, a9, TCB_TOP_OF_STACK_OFF // pxCurrentTCB->pxTopOfStack <- SP
|
||||
|
||||
// Mark as preempted
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
l32i a10, a9, TCB_END_OF_STACK_OFF
|
||||
rsr a12, CPENABLE // Save and clear CPENABLE
|
||||
s16i a12, a10, XT_CPENABLE
|
||||
movi a12, 0
|
||||
wsr a12, CPENABLE
|
||||
#endif
|
||||
|
||||
// Save non-CP TIE state if any
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0
|
||||
addi a10, a1, -XT_STK_FRMSZ + XT_STK_ALIGN_SZ // where to save
|
||||
#if XCHAL_EXTRA_SA_ALIGN > 16
|
||||
movi a12, -XCHAL_EXTRA_SA_ALIGN
|
||||
and a10, a10, a12 // align dynamically >16 bytes
|
||||
#endif
|
||||
xchal_ncp_store a10, a11, a12, a13, a14
|
||||
#endif
|
||||
|
||||
// If windowed ABI, a0-a7 was not saved by dispatch code.
|
||||
// These don't go into the exception frame, but below the
|
||||
// exception frame pointer.
|
||||
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
addi a10, a1, -XT_STK_FRMSZ -32
|
||||
s32i a0, a10, 0
|
||||
s32i a2, a10, 8
|
||||
s32i a3, a10, 12
|
||||
s32i a4, a10, 16
|
||||
s32i a5, a10, 20
|
||||
s32i a6, a10, 24
|
||||
s32i a7, a10, 28
|
||||
#endif
|
||||
|
||||
.Lsched:
|
||||
// When we get here, interrupts are disabled. Also, we have saved
|
||||
// all registers if needed so all of a0-a15 are available to use.
|
||||
// Note we are using the existing stack to make the call below.
|
||||
|
||||
addi a1, a1, -XT_STK_FRMSZ -32
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
movi a10, vTaskSwitchContext
|
||||
callx8 a10
|
||||
#else
|
||||
movi a10, vTaskSwitchContext
|
||||
callx0 a10
|
||||
#endif
|
||||
|
||||
.Lyield:
|
||||
// Come here directly if the outgoing task yielded. pxCurrentTCB
|
||||
// has already been updated.
|
||||
|
||||
movi a9, pxCurrentTCB
|
||||
l32i a9, a9, 0 // a9 <- pxCurrentTCB
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
l32i a10, a9, TCB_END_OF_STACK_OFF
|
||||
l16ui a10, a10, XT_CPENABLE
|
||||
wsr a10, CPENABLE // restore CPENABLE
|
||||
#endif
|
||||
|
||||
l32i a1, a9, TCB_TOP_OF_STACK_OFF // a1 <- pxCurrentTCB->pxTopOfStack
|
||||
addi a10, a1, XT_STK_FRMSZ - XT_STK_XFRM_SZ
|
||||
j 1f //bbci a10, 31, 1f // Bit 31 = solicited flag
|
||||
|
||||
// Solicited restore
|
||||
addi a1, a1, XT_STK_FRMSZ // restore original SP
|
||||
addi a2, a1, -XT_STK_XFRM_SZ
|
||||
l32i a3, a2, XT_STK_PC // a3 = return PC
|
||||
|
||||
movi a2, PS_DI
|
||||
xps a2, a2 // disable interrupts
|
||||
movi a2, 0
|
||||
wsr.ms a2 // restore normal DISPST
|
||||
rsync
|
||||
jx a3 // return to yield point
|
||||
|
||||
1:
|
||||
// Preempt restore
|
||||
#if XCHAL_EXTRA_SA_SIZE > 0
|
||||
addi a10, a1, XT_STK_ALIGN_SZ // where to restore from
|
||||
#if XCHAL_EXTRA_SA_ALIGN > 16
|
||||
movi a12, -XCHAL_EXTRA_SA_ALIGN
|
||||
and a10, a10, a12 // align dynamically >16 bytes
|
||||
#endif
|
||||
xchal_ncp_load a10, a11, a12, a13, a14
|
||||
#endif
|
||||
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
// Restore a0-a7 for windowed ABI
|
||||
addi a8, a1, -32
|
||||
l32i a0, a8, 0
|
||||
l32i a2, a8, 8
|
||||
l32i a3, a8, 12
|
||||
l32i a4, a8, 16
|
||||
l32i a5, a8, 20
|
||||
l32i a6, a8, 24
|
||||
l32i a7, a8, 28
|
||||
#else
|
||||
// For call0, dispatch exit code expects a15 = original SP
|
||||
addi a15, a1, XT_STK_FRMSZ
|
||||
#endif
|
||||
|
||||
addi a1, a1, XT_STK_FRMSZ // set up SP for dispatch exit
|
||||
|
||||
.Lnested:
|
||||
// Return to the current saved context.
|
||||
|
||||
.endm
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* XCHAL_HAVE_XEA3 */
|
||||
|
||||
#endif /* XTENSA_CONTEXT_H */
|
||||
Vendored
+543
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
// xtensa_coproc_handler.S - Xtensa coprocessor exception handler.
|
||||
|
||||
#include <xtensa/config/specreg.h>
|
||||
#include <xtensa/coreasm.h>
|
||||
|
||||
#include "xtensa_context.h"
|
||||
#include "xtensa_rtos.h"
|
||||
|
||||
|
||||
#if XCHAL_CP_NUM > 0
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Coprocessor related state and precomputed values.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Table of coprocessor owners, identified by thread's CP save area pointer.
|
||||
// Zero means coprocessor is not owned.
|
||||
|
||||
.data
|
||||
.global _xt_coproc_owner_sa
|
||||
.align 16,,XCHAL_CP_MAX << 2 // minimize crossing cache boundaries
|
||||
_xt_coproc_owner_sa:
|
||||
.rept XCHAL_CP_MAX
|
||||
.word 0
|
||||
.endr
|
||||
|
||||
// Bitmask table for CP n's enable bit, indexed by coprocessor number.
|
||||
|
||||
.section .rodata, "a"
|
||||
.global _xt_coproc_mask
|
||||
.align 16,,8 // try to keep it all in one cache line
|
||||
.set i, 0
|
||||
_xt_coproc_mask:
|
||||
.rept XCHAL_CP_MAX
|
||||
.long (i<<16) | (1<<i) // upper 16-bits = i, lower = bitmask
|
||||
.set i, i+1
|
||||
.endr
|
||||
|
||||
// Offset to CP n save area in thread's CP save area.
|
||||
|
||||
.global _xt_coproc_sa_offset
|
||||
.align 16 // minimize crossing cache boundaries
|
||||
_xt_coproc_sa_offset:
|
||||
.word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA
|
||||
.word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// _xt_coproc_handler
|
||||
//
|
||||
// Handles coprocessor exceptions and manages lazy context switching between
|
||||
// multiple threads sharing the coprocessor(s).
|
||||
// Register use:
|
||||
// a0 - on entry, return address (must have been called via call0).
|
||||
// a1 - pointing to valid exception stack frame.
|
||||
// a2 - on entry, must hold coprocessor index. On exit, 0 if OK.
|
||||
// a3-a15 - may all be used and trashed by this routine.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.global _xt_coproc_handler
|
||||
|
||||
_xt_coproc_handler:
|
||||
|
||||
mov a7, a0 // a7 = return address
|
||||
mov a5, a2 // a5 = CP index n
|
||||
|
||||
// Get coprocessor state save area of new owner thread
|
||||
call0 XT_RTOS_CP_STATE // a15 = new owner's save area
|
||||
beqz a15, .L_xt_coproc_invalid // not in a thread (invalid)
|
||||
l32i a4, a15, XT_CP_ASA // actual save area address
|
||||
beqz a4, .L_xt_coproc_invalid // thread has no save area
|
||||
|
||||
// Enable the co-processor's bit in CPENABLE
|
||||
movi a0, _xt_coproc_mask
|
||||
rsr a4, CPENABLE // a4 = CPENABLE
|
||||
addx4 a0, a5, a0 // a0 = &_xt_coproc_mask[n]
|
||||
l32i a0, a0, 0 // a0 = (n << 16) | (1 << n)
|
||||
movi a3, _xt_coproc_owner_sa
|
||||
extui a2, a0, 0, 16 // coprocessor bitmask portion
|
||||
or a4, a4, a2 // a4 = CPENABLE | (1 << n)
|
||||
wsr a4, CPENABLE
|
||||
|
||||
// Get old coprocessor owner thread (save area ptr) and assign new one
|
||||
addx4 a3, a5, a3 // a3 = &_xt_coproc_owner_sa[n]
|
||||
l32i a2, a3, 0 // a2 = old owner's save area
|
||||
s32i a15, a3, 0 // _xt_coproc_owner_sa[n] = new
|
||||
rsync // ensure wsr.CPENABLE is complete
|
||||
|
||||
// Do we need to context-switch this coprocessor ?
|
||||
beq a15, a2, .L_xt_coproc_done // new owner == old, we're done
|
||||
|
||||
// if no old owner then nothing to save
|
||||
beqz a2, .L_check_new
|
||||
|
||||
// If old owner not actively using CP then nothing to save.
|
||||
l16ui a4, a2, XT_CPENABLE // a4 = old owner's CPENABLE
|
||||
bnone a4, a0, .L_check_new // old owner not using CP
|
||||
|
||||
.L_save_old:
|
||||
// We need to save old owner's coprocessor state
|
||||
movi a5, _xt_coproc_sa_offset
|
||||
|
||||
// Mark old owner state as no longer active (CPENABLE bit n clear)
|
||||
xor a4, a4, a0 // clear CP in old owner's CPENABLE
|
||||
s16i a4, a2, XT_CPENABLE // update old owner's CPENABLE
|
||||
|
||||
extui a4, a0, 16, 5 // a4 = CP index = n
|
||||
addx4 a5, a4, a5 // a5 = &_xt_coproc_sa_offset[n]
|
||||
|
||||
// Mark old owner state as saved (CPSTORED bit n set)
|
||||
l16ui a4, a2, XT_CPSTORED // a4 = old owner's CPSTORED
|
||||
l32i a5, a5, 0 // a5 = XT_CP[n]_SA offset
|
||||
or a4, a4, a0 // set CP in old owner's CPSTORED
|
||||
s16i a4, a2, XT_CPSTORED // update old owner's CPSTORED
|
||||
l32i a2, a2, XT_CP_ASA // ptr to actual (aligned) save area
|
||||
extui a3, a0, 16, 5 // a3 = CP index = n
|
||||
add a2, a2, a5 // a2 = old owner's area for CP n
|
||||
|
||||
// The config-specific HAL macro invoked below destroys a2-a6.
|
||||
// It is theoretically possible for Xtensa processor designers to write TIE
|
||||
// that causes more address registers to be affected, but it is generally
|
||||
// unlikely. If that ever happens, more registers needs to be saved/restored
|
||||
// around this macro invocation, and the value in a15 needs to be recomputed.
|
||||
|
||||
xchal_cpi_store_funcbody
|
||||
|
||||
.L_check_new:
|
||||
// Check if any state has to be restored for new owner.
|
||||
// NOTE: a15 = new owner's save area, cannot be zero when we get here.
|
||||
|
||||
l16ui a3, a15, XT_CPSTORED // a3 = new owner's CPSTORED
|
||||
movi a4, _xt_coproc_sa_offset
|
||||
bnone a3, a0, .L_check_cs // full CP not saved, check callee-saved
|
||||
xor a3, a3, a0 // CPSTORED bit is set, clear it
|
||||
s16i a3, a15, XT_CPSTORED // update new owner's CPSTORED
|
||||
|
||||
// Adjust new owner's save area pointers to area for CP n.
|
||||
extui a3, a0, 16, 5 // a3 = CP index = n
|
||||
addx4 a4, a3, a4 // a4 = &_xt_coproc_sa_offset[n]
|
||||
l32i a4, a4, 0 // a4 = XT_CP[n]_SA
|
||||
l32i a5, a15, XT_CP_ASA // ptr to actual (aligned) save area
|
||||
add a2, a4, a5 // a2 = new owner's area for CP
|
||||
|
||||
// The config-specific HAL macro invoked below destroys a2-a6.
|
||||
// It is theoretically possible for Xtensa processor designers to write TIE
|
||||
// that causes more address registers to be affected, but it is generally
|
||||
// unlikely. If that ever happens, more registers needs to be saved/restored
|
||||
// around this macro invocation.
|
||||
|
||||
xchal_cpi_load_funcbody
|
||||
|
||||
.L_xt_coproc_done:
|
||||
movi a2, 0 // a2 <- 0 == OK
|
||||
.L_xt_coproc_err:
|
||||
mov a0, a7 // return address
|
||||
ret
|
||||
|
||||
.L_check_cs:
|
||||
// a0 = CP mask in low bits, a15 = new owner's save area.
|
||||
l16ui a2, a15, XT_CP_CS_ST // a2 = mask of CPs saved
|
||||
bnone a2, a0, .L_xt_coproc_done // if no match then done
|
||||
and a2, a2, a0 // a2 = which CPs to restore
|
||||
extui a2, a2, 0, 8 // extract low 8 bits
|
||||
call0 _xt_coproc_restorecs // restore CP registers
|
||||
j .L_xt_coproc_done
|
||||
|
||||
.L_xt_coproc_invalid:
|
||||
// Coprocessor exception occurred outside a thread or the thread
|
||||
// did not allocate space to save coprocessor state. Return error.
|
||||
movi a2, 1
|
||||
j .L_xt_coproc_err
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// _xt_coproc_savecs
|
||||
//
|
||||
// If there is a current thread and it has a coprocessor state save area, then
|
||||
// save all callee-saved state into this area. This function is called from the
|
||||
// solicited context switch handler. It calls a system-specific function to get
|
||||
// the coprocessor save area base address.
|
||||
//
|
||||
// Entry conditions:
|
||||
// - The thread being switched out is still the current thread.
|
||||
// - CPENABLE state reflects which coprocessors are active.
|
||||
// - Registers have been saved/spilled already.
|
||||
//
|
||||
// Exit conditions:
|
||||
// - All necessary CP callee-saved state has been saved.
|
||||
// - Registers a7-a15 have been trashed.
|
||||
//
|
||||
// Must be called from assembly code only, using CALL0.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.global _xt_coproc_savecs
|
||||
.type _xt_coproc_savecs,@function
|
||||
.align 4
|
||||
_xt_coproc_savecs:
|
||||
|
||||
// At entry, CPENABLE should be showing which CPs are enabled.
|
||||
|
||||
rsr a11, CPENABLE // a11 = which CPs are enabled
|
||||
beqz a11, .Ldone // quick exit if none
|
||||
mov a14, a0 // save return address
|
||||
call0 XT_RTOS_CP_STATE // get address of CP save area
|
||||
mov a0, a14 // restore return address
|
||||
beqz a15, .Ldone // if none then nothing to do
|
||||
l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area
|
||||
beqz a14, .Ldone // no save area, nothing to do
|
||||
s16i a11, a15, XT_CP_CS_ST // save mask of CPs being stored
|
||||
movi a13, _xt_coproc_sa_offset // array of CP save offsets
|
||||
l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area
|
||||
|
||||
#if XCHAL_CP0_SA_SIZE
|
||||
bbci.l a11, 0, 2f // CP 0 not enabled
|
||||
l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0]
|
||||
add a12, a14, a15 // a12 = save area for CP 0
|
||||
xchal_cp0_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP1_SA_SIZE
|
||||
bbci.l a11, 1, 2f // CP 1 not enabled
|
||||
l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1]
|
||||
add a12, a14, a15 // a12 = save area for CP 1
|
||||
xchal_cp1_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP2_SA_SIZE
|
||||
bbci.l a11, 2, 2f
|
||||
l32i a14, a13, 8
|
||||
add a12, a14, a15
|
||||
xchal_cp2_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP3_SA_SIZE
|
||||
bbci.l a11, 3, 2f
|
||||
l32i a14, a13, 12
|
||||
add a12, a14, a15
|
||||
xchal_cp3_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP4_SA_SIZE
|
||||
bbci.l a11, 4, 2f
|
||||
l32i a14, a13, 16
|
||||
add a12, a14, a15
|
||||
xchal_cp4_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP5_SA_SIZE
|
||||
bbci.l a11, 5, 2f
|
||||
l32i a14, a13, 20
|
||||
add a12, a14, a15
|
||||
xchal_cp5_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP6_SA_SIZE
|
||||
bbci.l a11, 6, 2f
|
||||
l32i a14, a13, 24
|
||||
add a12, a14, a15
|
||||
xchal_cp6_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP7_SA_SIZE
|
||||
bbci.l a11, 7, 2f
|
||||
l32i a14, a13, 28
|
||||
add a12, a14, a15
|
||||
xchal_cp7_store a12, a7, a8, a9, a10 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
.Ldone:
|
||||
ret
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// _xt_coproc_restorecs
|
||||
//
|
||||
// Restore any callee-saved coprocessor state for the incoming thread.
|
||||
// This function is called from coprocessor exception handling, when giving
|
||||
// ownership to a thread that solicited a context switch earlier. It calls a
|
||||
// system-specific function to get the coprocessor save area base address.
|
||||
//
|
||||
// Entry conditions:
|
||||
// - The incoming thread is set as the current thread.
|
||||
// - CPENABLE is set up correctly for all required coprocessors.
|
||||
// - a2 = mask of coprocessors to be restored.
|
||||
//
|
||||
// Exit conditions:
|
||||
// - All necessary CP callee-saved state has been restored.
|
||||
// - CPENABLE - unchanged.
|
||||
// - Registers a2, a8-a15 have been trashed.
|
||||
//
|
||||
// Must be called from assembly code only, using CALL0.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.global _xt_coproc_restorecs
|
||||
.type _xt_coproc_restorecs,@function
|
||||
.align 4
|
||||
_xt_coproc_restorecs:
|
||||
|
||||
mov a14, a0 // save return address
|
||||
call0 XT_RTOS_CP_STATE // get address of CP save area
|
||||
mov a0, a14 // restore return address
|
||||
beqz a15, .Ldone2 // if none then nothing to do
|
||||
l32i a14, a15, XT_CP_ASA // a14 = base of aligned save area
|
||||
beqz a14, .Ldone2 // no save area, nothing to do
|
||||
l16ui a13, a15, XT_CP_CS_ST // a13 = which CPs have been saved
|
||||
xor a13, a13, a2 // clear the ones being restored
|
||||
s16i a13, a15, XT_CP_CS_ST // update saved CP mask
|
||||
movi a13, _xt_coproc_sa_offset // array of CP save offsets
|
||||
l32i a15, a15, XT_CP_ASA // a15 = base of aligned save area
|
||||
|
||||
#if XCHAL_CP0_SA_SIZE
|
||||
bbci.l a2, 0, 2f // CP 0 not enabled
|
||||
l32i a14, a13, 0 // a14 = _xt_coproc_sa_offset[0]
|
||||
add a12, a14, a15 // a12 = save area for CP 0
|
||||
xchal_cp0_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP1_SA_SIZE
|
||||
bbci.l a2, 1, 2f // CP 1 not enabled
|
||||
l32i a14, a13, 4 // a14 = _xt_coproc_sa_offset[1]
|
||||
add a12, a14, a15 // a12 = save area for CP 1
|
||||
xchal_cp1_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP2_SA_SIZE
|
||||
bbci.l a2, 2, 2f
|
||||
l32i a14, a13, 8
|
||||
add a12, a14, a15
|
||||
xchal_cp2_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP3_SA_SIZE
|
||||
bbci.l a2, 3, 2f
|
||||
l32i a14, a13, 12
|
||||
add a12, a14, a15
|
||||
xchal_cp3_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP4_SA_SIZE
|
||||
bbci.l a2, 4, 2f
|
||||
l32i a14, a13, 16
|
||||
add a12, a14, a15
|
||||
xchal_cp4_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP5_SA_SIZE
|
||||
bbci.l a2, 5, 2f
|
||||
l32i a14, a13, 20
|
||||
add a12, a14, a15
|
||||
xchal_cp5_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP6_SA_SIZE
|
||||
bbci.l a2, 6, 2f
|
||||
l32i a14, a13, 24
|
||||
add a12, a14, a15
|
||||
xchal_cp6_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
#if XCHAL_CP7_SA_SIZE
|
||||
bbci.l a2, 7, 2f
|
||||
l32i a14, a13, 28
|
||||
add a12, a14, a15
|
||||
xchal_cp7_load a12, a8, a9, a10, a11 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
|
||||
2:
|
||||
#endif
|
||||
|
||||
.Ldone2:
|
||||
ret
|
||||
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// For XEA3, coprocessor exceptions come here. This is a wrapper function that
|
||||
// calls _xt_coproc_handler() to do the actual work. We don't want the handler
|
||||
// to be interrupted because that might cause a round-robin switch and leave
|
||||
// coprocessor context in a confused state. So interrupts are disabled before
|
||||
// calling the handler. They will be re-enabled on return from exception.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.text
|
||||
.global _xt_coproc_exc
|
||||
.type _xt_coproc_exc,@function
|
||||
.align 4
|
||||
|
||||
_xt_coproc_exc:
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
addi a1, a1, -16 // reserve 16 bytes on stack
|
||||
s32i a0, a1, 0 // save return address
|
||||
s32i a15, a1, 8 // must save a15 (see dispatch)
|
||||
movi a3, PS_DI_MASK
|
||||
xps a3, a3 // set PS.DI, disable interrupts
|
||||
l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause
|
||||
extui a2, a3, 8, 4 // a2 <- CP index
|
||||
call0 _xt_coproc_handler
|
||||
l32i a0, a1, 0 // restore return address
|
||||
l32i a15, a1, 8 // restore a15
|
||||
addi a1, a1, 16
|
||||
ret
|
||||
#else
|
||||
entry a1, 48 // reserve 16 bytes on stack
|
||||
s32i a0, a1, 0 // save return address
|
||||
movi a3, PS_DI_MASK
|
||||
xps a3, a3 // set PS.DI, disable interrupts
|
||||
l32i a3, a2, XT_STK_EXCCAUSE // a3 <- exccause
|
||||
extui a2, a3, 8, 4 // a2 <- CP index
|
||||
call0 _xt_coproc_handler
|
||||
l32i a0, a1, 0 // restore return address
|
||||
retw
|
||||
#endif
|
||||
|
||||
#endif // XCHAL_HAVE_XEA3
|
||||
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// XEA2 coprocessor exception dispatcher. Save enough state to be able to call
|
||||
// the coprocessor handler, then restore and return.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
.section "privileged_functions"
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
.global _xt_coproc_exc
|
||||
.type _xt_coproc_exc,@function
|
||||
.align 4
|
||||
|
||||
_xt_coproc_exc:
|
||||
|
||||
mov a0, sp // Allocate stack frame
|
||||
addi sp, sp, -XT_STK_FRMSZ
|
||||
s32i a0, sp, XT_STK_A1 // save SP
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
s32e a0, sp, -12 // for debug backtrace
|
||||
#endif
|
||||
rsr a0, PS
|
||||
s32i a0, sp, XT_STK_PS // save PS
|
||||
rsr a0, EPC_1
|
||||
s32i a0, sp, XT_STK_PC // save PC
|
||||
rsr a0, EXCSAVE_1
|
||||
s32i a0, sp, XT_STK_A0 // retrieve and save a0
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
s32e a0, sp, -16 // for debug backtrace
|
||||
#endif
|
||||
s32i a2, sp, XT_STK_A2
|
||||
s32i a3, sp, XT_STK_A3
|
||||
s32i a4, sp, XT_STK_A4
|
||||
s32i a5, sp, XT_STK_A5
|
||||
s32i a6, sp, XT_STK_A6
|
||||
s32i a7, sp, XT_STK_A7
|
||||
s32i a8, sp, XT_STK_A8
|
||||
s32i a9, sp, XT_STK_A9
|
||||
s32i a10, sp, XT_STK_A10
|
||||
s32i a11, sp, XT_STK_A11
|
||||
s32i a12, sp, XT_STK_A12
|
||||
s32i a13, sp, XT_STK_A13
|
||||
s32i a14, sp, XT_STK_A14
|
||||
s32i a15, sp, XT_STK_A15
|
||||
|
||||
rsr a3, EXCCAUSE // a3 <- exccause
|
||||
addi a2, a3, -EXCCAUSE_CP0_DISABLED // a2 <- CP index
|
||||
call0 _xt_coproc_handler
|
||||
|
||||
mov a0, a2 // save return value
|
||||
l32i a2, sp, XT_STK_A2
|
||||
l32i a3, sp, XT_STK_A3
|
||||
l32i a4, sp, XT_STK_A4
|
||||
l32i a5, sp, XT_STK_A5
|
||||
l32i a6, sp, XT_STK_A6
|
||||
l32i a7, sp, XT_STK_A7
|
||||
l32i a8, sp, XT_STK_A8
|
||||
l32i a9, sp, XT_STK_A9
|
||||
l32i a10, sp, XT_STK_A10
|
||||
l32i a11, sp, XT_STK_A11
|
||||
l32i a12, sp, XT_STK_A12
|
||||
l32i a13, sp, XT_STK_A13
|
||||
l32i a14, sp, XT_STK_A14
|
||||
l32i a15, sp, XT_STK_A15
|
||||
bnez a0, .Lfail // abort if failure
|
||||
l32i a0, sp, XT_STK_PC
|
||||
wsr a0, EPC_1 // restore PC
|
||||
l32i a0, sp, XT_STK_PS
|
||||
wsr a0, PS // restore PS
|
||||
l32i a0, sp, XT_STK_A0
|
||||
addi a1, a1, XT_STK_FRMSZ // deallocate stack frame
|
||||
rfe
|
||||
|
||||
.Lfail:
|
||||
call0 _xt_panic
|
||||
|
||||
#endif // XCHAL_HAVE_XEA2
|
||||
|
||||
#endif // XCHAL_CP_NUM > 0
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xtensa-specific interrupt and exception functions for RTOS ports.
|
||||
* Also see xtensa_intr_asm.S.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xtensa/config/core.h>
|
||||
#include <xtensa/core-macros.h>
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
#include <xtensa/tie/xt_interrupt.h>
|
||||
#endif
|
||||
|
||||
#include "xtensa_api.h"
|
||||
|
||||
|
||||
#if XCHAL_HAVE_EXCEPTIONS
|
||||
|
||||
/* Handler table is in xtensa_intr_asm.S */
|
||||
extern xt_exc_handler xt_exception_table[XCHAL_EXCCAUSE_NUM];
|
||||
|
||||
|
||||
/*
|
||||
Default handler for unhandled exceptions.
|
||||
*/
|
||||
void
|
||||
xt_unhandled_exception( XtExcFrame * frame )
|
||||
{
|
||||
(void) frame;
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function registers a handler for the specified exception.
|
||||
The function returns the address of the previous handler.
|
||||
On error, it returns NULL.
|
||||
*/
|
||||
xt_exc_handler
|
||||
xt_set_exception_handler( uint32_t n, xt_exc_handler f )
|
||||
{
|
||||
xt_exc_handler old;
|
||||
|
||||
if ( n >= (uint32_t) XCHAL_EXCCAUSE_NUM )
|
||||
{
|
||||
// Invalid exception number.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
old = xt_exception_table[n];
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
xt_exception_table[n] = f;
|
||||
}
|
||||
else
|
||||
{
|
||||
xt_exception_table[n] = &xt_unhandled_exception;
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS <= 32)
|
||||
/* Defined in xtensa_intr_asm.S */
|
||||
extern uint32_t xt_intenable;
|
||||
extern uint32_t xt_vpri_mask;
|
||||
#endif
|
||||
|
||||
/* Handler table is in xtensa_intr_asm.S */
|
||||
typedef struct xt_handler_table_entry {
|
||||
xt_handler handler;
|
||||
void * arg;
|
||||
} xt_handler_table_entry;
|
||||
|
||||
#if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3)
|
||||
extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS + 1];
|
||||
#else
|
||||
extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS];
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Default handler for unhandled interrupts.
|
||||
*/
|
||||
void
|
||||
xt_unhandled_interrupt( void * arg )
|
||||
{
|
||||
(void) arg;
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function registers a handler for the specified interrupt. The "arg"
|
||||
parameter specifies the argument to be passed to the handler when it is
|
||||
invoked. The function returns the address of the previous handler.
|
||||
On error, it returns NULL.
|
||||
*/
|
||||
xt_handler
|
||||
xt_set_interrupt_handler( uint32_t n, xt_handler f, void * arg )
|
||||
{
|
||||
xt_handler_table_entry * entry;
|
||||
xt_handler old;
|
||||
|
||||
if ( n >= (uint32_t) XCHAL_NUM_INTERRUPTS )
|
||||
{
|
||||
// Invalid interrupt number.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if XCHAL_HAVE_XEA2
|
||||
if ( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL )
|
||||
{
|
||||
// Priority level too high to safely handle in C.
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3)
|
||||
entry = _xt_interrupt_table + n + 1;
|
||||
#else
|
||||
entry = _xt_interrupt_table + n;
|
||||
#endif
|
||||
old = entry->handler;
|
||||
|
||||
if ( f != NULL )
|
||||
{
|
||||
entry->handler = f;
|
||||
entry->arg = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->handler = &xt_unhandled_interrupt;
|
||||
entry->arg = (void*)n;
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function enables the interrupt whose number is specified as
|
||||
the argument.
|
||||
*/
|
||||
void
|
||||
xt_interrupt_enable( uint32_t intnum )
|
||||
{
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS <= 32)
|
||||
if ( intnum < (uint32_t) XCHAL_NUM_INTERRUPTS )
|
||||
{
|
||||
int ps = XT_RSIL( 15 );
|
||||
|
||||
// New INTENABLE = (xt_intenable | mask) & xt_vpri_mask.
|
||||
xt_intenable |= ( 1U << intnum );
|
||||
XT_WSR_INTENABLE( xt_intenable & xt_vpri_mask );
|
||||
XT_WSR_PS( ps );
|
||||
XT_RSYNC();
|
||||
}
|
||||
#else
|
||||
xthal_interrupt_enable( intnum );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function disables the interrupt whose number is specified as
|
||||
the argument.
|
||||
*/
|
||||
void
|
||||
xt_interrupt_disable( uint32_t intnum )
|
||||
{
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS <= 32)
|
||||
if ( intnum < (uint32_t) XCHAL_NUM_INTERRUPTS )
|
||||
{
|
||||
int ps = XT_RSIL( 15 );
|
||||
|
||||
// New INTENABLE = (xt_intenable & ~mask) & xt_vpri_mask.
|
||||
xt_intenable &= ~( 1U << intnum );
|
||||
XT_WSR_INTENABLE( xt_intenable & xt_vpri_mask );
|
||||
XT_WSR_PS( ps );
|
||||
XT_RSYNC();
|
||||
}
|
||||
#else
|
||||
xthal_interrupt_disable( intnum );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function returns : 1 if the specified interrupt is enabled, zero
|
||||
if the interrupt is disabled, zero if the interrupt number is invalid.
|
||||
*/
|
||||
uint32_t
|
||||
xt_interrupt_enabled( uint32_t intnum )
|
||||
{
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS <= 32)
|
||||
if ( intnum < (uint32_t) XCHAL_NUM_INTERRUPTS )
|
||||
{
|
||||
return ( (xt_intenable & (1U << intnum)) != 0 ) ? 1U : 0;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return xthal_interrupt_enabled( intnum );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function triggers the specified interrupt.
|
||||
*/
|
||||
void
|
||||
xt_interrupt_trigger( uint32_t intnum )
|
||||
{
|
||||
xthal_interrupt_trigger( intnum );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function clears the specified interrupt.
|
||||
*/
|
||||
void
|
||||
xt_interrupt_clear( uint32_t intnum )
|
||||
{
|
||||
xthal_interrupt_clear( intnum );
|
||||
}
|
||||
|
||||
|
||||
#endif /* XCHAL_HAVE_INTERRUPTS */
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Xtensa interrupt handling data and assembly routines.
|
||||
* Also see xtensa_intr.c and xtensa_vectors.S.
|
||||
*/
|
||||
|
||||
#include <xtensa/hal.h>
|
||||
#include <xtensa/config/core.h>
|
||||
|
||||
#include <FreeRTOSConfig.h>
|
||||
|
||||
#include "xtensa_context.h"
|
||||
#include "xtensa_config.h"
|
||||
|
||||
#if XCHAL_HAVE_INTERRUPTS
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
INTENABLE virtualization information.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS <= 32)
|
||||
|
||||
.data
|
||||
.global xt_intdata
|
||||
.align 8
|
||||
xt_intdata:
|
||||
.global xt_intenable
|
||||
.type xt_intenable,@object
|
||||
.size xt_intenable,4
|
||||
.global xt_vpri_mask
|
||||
.type xt_vpri_mask,@object
|
||||
.size xt_vpri_mask,4
|
||||
|
||||
xt_intenable: .word 0 /* Virtual INTENABLE */
|
||||
xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
System interrupt stack.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if (XCHAL_HAVE_XEA2 || XCHAL_HAVE_ISB)
|
||||
.data
|
||||
#else
|
||||
.section .intr.top, "aw"
|
||||
#endif
|
||||
|
||||
.global xt_interrupt_stack
|
||||
.global xt_interrupt_stack_top
|
||||
.align 16
|
||||
|
||||
xt_interrupt_stack:
|
||||
.space configISR_STACK_SIZE
|
||||
xt_interrupt_stack_top:
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Table of C-callable interrupt handlers for each interrupt. For XEA2 configs,
|
||||
not all slots can be filled, because interrupts at level > EXCM_LEVEL will
|
||||
not be dispatched to a C handler by default.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if (XCHAL_HAVE_XEA2 || XCHAL_HAVE_ISB)
|
||||
.data
|
||||
#else
|
||||
.section .intr.data, "aw"
|
||||
#endif
|
||||
|
||||
.global _xt_interrupt_table
|
||||
.align 16
|
||||
|
||||
_xt_interrupt_table:
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
If using the interrupt wrapper, make the first entry in the interrupt table
|
||||
point to the wrapper (XEA3) or leave it empty (XEA2).
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#if XCHAL_HAVE_XEA3
|
||||
.word xt_interrupt_wrapper
|
||||
.word 0
|
||||
#elif XT_USE_INT_WRAPPER
|
||||
.word 0
|
||||
.word 0
|
||||
#endif
|
||||
|
||||
.set i, 0
|
||||
.rept XCHAL_NUM_INTERRUPTS
|
||||
.word xt_unhandled_interrupt /* handler address */
|
||||
.word i /* handler arg (default: intnum) */
|
||||
.set i, i+1
|
||||
.endr
|
||||
|
||||
#endif /* XCHAL_HAVE_INTERRUPTS */
|
||||
|
||||
|
||||
#if XCHAL_HAVE_EXCEPTIONS
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
Table of C-callable exception handlers for each exception. Note that not all
|
||||
slots will be active, because some exceptions (e.g. coprocessor exceptions)
|
||||
are always handled by the OS and cannot be hooked by user handlers.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.data
|
||||
.global xt_exception_table
|
||||
.align 4
|
||||
|
||||
xt_exception_table:
|
||||
.rept XCHAL_EXCCAUSE_NUM
|
||||
.word xt_unhandled_exception /* handler address */
|
||||
.endr
|
||||
|
||||
#endif
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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 <xtensa/config/core.h>
|
||||
#include <xtensa/core-macros.h>
|
||||
|
||||
#include "xtensa_rtos.h"
|
||||
#include "xtensa_api.h"
|
||||
#include "portmacro.h"
|
||||
|
||||
|
||||
#if (XCHAL_HAVE_XEA3 && XCHAL_HAVE_INTERRUPTS)
|
||||
|
||||
/* Handler table is in xtensa_intr_asm.S */
|
||||
|
||||
typedef struct xt_handler_table_entry {
|
||||
void * handler;
|
||||
void * arg;
|
||||
} xt_handler_table_entry;
|
||||
|
||||
extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS + 1];
|
||||
|
||||
extern int32_t xt_sw_intnum;
|
||||
extern int32_t port_switch_flag;
|
||||
extern uint32_t port_interruptNesting;
|
||||
|
||||
static int32_t xt_wflag;
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* Wrapper for interrupt handlers. Argument is (intnum << 2). */
|
||||
/* Execution comes here from the dispatch code if the wrapper is */
|
||||
/* enabled. */
|
||||
/**************************************************************************/
|
||||
void
|
||||
xt_interrupt_wrapper(void * arg)
|
||||
{
|
||||
uint32_t intnum = (uint32_t)(arg) >> 2;
|
||||
uint32_t state;
|
||||
xt_handler_table_entry * entry;
|
||||
xt_handler handler;
|
||||
|
||||
state = portENTER_CRITICAL_NESTED();
|
||||
port_interruptNesting++;
|
||||
portEXIT_CRITICAL_NESTED(state);
|
||||
|
||||
/* Load handler address and argument from table. Note that the
|
||||
first entry in the table points to this wrapper, so we have
|
||||
to skip ahead one.
|
||||
*/
|
||||
entry = _xt_interrupt_table + intnum + 1;
|
||||
handler = (xt_handler) entry->handler;
|
||||
|
||||
(*handler)(entry->arg);
|
||||
|
||||
/* If a context switch is pending, trigger the SW interrupt
|
||||
to process the switch. Set an internal flag so we don't
|
||||
trigger the sw interrupt again when handling it.
|
||||
*/
|
||||
if (xt_wflag != 0) {
|
||||
xt_wflag = 0;
|
||||
}
|
||||
else if (port_switch_flag) {
|
||||
xt_wflag = 1;
|
||||
xt_interrupt_trigger(xt_sw_intnum);
|
||||
}
|
||||
|
||||
state = portENTER_CRITICAL_NESTED();
|
||||
port_interruptNesting--;
|
||||
portEXIT_CRITICAL_NESTED(state);
|
||||
}
|
||||
|
||||
#endif /* XCHAL_HAVE_XEA3 && XCHAL_HAVE_INTERRUPTS */
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* xtensa_overlay_os_hook.c -- Overlay manager OS hooks for FreeRTOS.
|
||||
*/
|
||||
|
||||
#ifdef XT_USE_OVLY
|
||||
|
||||
#include <xtensa/overlay.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
#error "Windowed ABI is required for overlays"
|
||||
#elif !XCHAL_HAVE_XEA2
|
||||
#error "Overlays supported only on Xtensa LX"
|
||||
#endif
|
||||
|
||||
#if configUSE_MUTEXES
|
||||
|
||||
/* Mutex object that controls access to the overlay. Currently only one
|
||||
* overlay region is supported so one mutex suffices.
|
||||
*/
|
||||
static SemaphoreHandle_t xt_overlay_mutex;
|
||||
|
||||
|
||||
/* This function should be overridden to provide OS specific init such
|
||||
* as the creation of a mutex lock that can be used for overlay locking.
|
||||
* Typically this mutex would be set up with priority inheritance. See
|
||||
* overlay manager documentation for more details.
|
||||
*/
|
||||
void xt_overlay_init_os(void)
|
||||
{
|
||||
/* Create the mutex for overlay access. Priority inheritance is
|
||||
* required.
|
||||
*/
|
||||
xt_overlay_mutex = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
|
||||
/* This function locks access to shared overlay resources, typically
|
||||
* by acquiring a mutex.
|
||||
*/
|
||||
void xt_overlay_lock(void)
|
||||
{
|
||||
xSemaphoreTake(xt_overlay_mutex, portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
||||
/* This function releases access to shared overlay resources, typically
|
||||
* by unlocking a mutex.
|
||||
*/
|
||||
void xt_overlay_unlock(void)
|
||||
{
|
||||
xSemaphoreGive(xt_overlay_mutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Mutex support is required for overlays"
|
||||
|
||||
#endif /* configUSE_MUTEXES */
|
||||
|
||||
#endif /* XT_USE_OVLY */
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTOS-SPECIFIC INFORMATION FOR XTENSA RTOS ASSEMBLER SOURCES
|
||||
* (FreeRTOS Port)
|
||||
*
|
||||
* This header is the primary glue between generic Xtensa RTOS support
|
||||
* sources and a specific RTOS port for Xtensa. It contains definitions
|
||||
* and macros for use primarily by Xtensa assembly coded source files.
|
||||
*
|
||||
* Macros in this header map callouts from generic Xtensa files to specific
|
||||
* RTOS functions. It may also be included in C source files.
|
||||
*
|
||||
* Xtensa RTOS ports support all RTOS-compatible configurations of the Xtensa
|
||||
* architecture, using the Xtensa hardware abstraction layer (HAL) to deal
|
||||
* with configuration specifics.
|
||||
*
|
||||
* Should be included by all Xtensa generic and RTOS port-specific sources.
|
||||
*/
|
||||
|
||||
#ifndef XTENSA_RTOS_H
|
||||
#define XTENSA_RTOS_H
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#include <xtensa/coreasm.h>
|
||||
#else
|
||||
#include <xtensa/config/core.h>
|
||||
#endif
|
||||
|
||||
#include <xtensa/corebits.h>
|
||||
#include <xtensa/config/system.h>
|
||||
#include <xtensa/simcall.h>
|
||||
|
||||
/*
|
||||
Include any RTOS specific definitions that are needed by this header.
|
||||
*/
|
||||
#include <FreeRTOSConfig.h>
|
||||
|
||||
/*
|
||||
Convert FreeRTOSConfig definitions to XTENSA definitions.
|
||||
However these can still be overridden from the command line.
|
||||
*/
|
||||
|
||||
#ifndef XT_SIMULATOR
|
||||
#if configXT_SIMULATOR
|
||||
#define XT_SIMULATOR 1 /* Simulator mode */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef XT_BOARD
|
||||
#if defined (configXT_BOARD) && (configXT_BOARD != 0)
|
||||
#define XT_BOARD 1 /* Board mode */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef XT_TIMER_INDEX
|
||||
#if defined configXT_TIMER_INDEX
|
||||
#define XT_TIMER_INDEX configXT_TIMER_INDEX /* Index of hardware timer to be used */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef XT_INTEXC_HOOKS
|
||||
#if configXT_INTEXC_HOOKS
|
||||
#define XT_INTEXC_HOOKS 1 /* Enables exception hooks */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if XCHAL_HAVE_XEA2 && (XCHAL_NUM_INTERRUPTS > 32) && (defined XT_INTEXC_HOOKS)
|
||||
#error "FreeRTOS/XTENSA XEA2 interrupt/exception hooks require <= 32 interrupts."
|
||||
#endif
|
||||
|
||||
#if (!XT_SIMULATOR) && (!XT_BOARD)
|
||||
#error Either XT_SIMULATOR or XT_BOARD must be defined.
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Name of RTOS (for messages).
|
||||
*/
|
||||
#define XT_RTOS_NAME FreeRTOS
|
||||
|
||||
#define UNUSED(x) ((void)(x))
|
||||
/*
|
||||
Check some Xtensa configuration requirements and report error if not met.
|
||||
Error messages can be customize to the RTOS port.
|
||||
*/
|
||||
|
||||
#if !XCHAL_HAVE_XEA2 && !XCHAL_HAVE_XEA3
|
||||
#error "FreeRTOS/Xtensa requires XEA2 or XEA3 exception architecture."
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
RTOS CALLOUT MACROS MAPPED TO RTOS PORT-SPECIFIC FUNCTIONS.
|
||||
|
||||
Define callout macros used in generic Xtensa code to interact with the RTOS.
|
||||
The macros are simply the function names for use in calls from assembler code.
|
||||
Some of these functions may call back to generic functions in xtensa_context.h .
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
Inform RTOS of entry into an interrupt handler that will affect it.
|
||||
Allows RTOS to manage switch to any system stack and count nesting level.
|
||||
Called after minimal context has been saved, with interrupts disabled.
|
||||
RTOS port can call0 _xt_context_save to save the rest of the context.
|
||||
May only be called from assembly code by the 'call0' instruction.
|
||||
*/
|
||||
// void XT_RTOS_INT_ENTER(void)
|
||||
#define XT_RTOS_INT_ENTER _frxt_int_enter
|
||||
|
||||
/*
|
||||
Inform RTOS of completion of an interrupt handler, and give control to
|
||||
RTOS to perform thread/task scheduling, switch back from any system stack
|
||||
and restore the context, and return to the exit dispatcher saved in the
|
||||
stack frame at XT_STK_EXIT. RTOS port can call0 _xt_context_restore
|
||||
to save the context saved in XT_RTOS_INT_ENTER via _xt_context_save,
|
||||
leaving only a minimal part of the context to be restored by the exit
|
||||
dispatcher. This function does not return to the place it was called from.
|
||||
May only be called from assembly code by the 'call0' instruction.
|
||||
*/
|
||||
// void XT_RTOS_INT_EXIT(void)
|
||||
#define XT_RTOS_INT_EXIT _frxt_int_exit
|
||||
|
||||
/*
|
||||
Inform RTOS of the occurrence of a tick timer interrupt.
|
||||
If RTOS has no tick timer, leave XT_RTOS_TIMER_INT undefined.
|
||||
May be coded in or called from C or assembly, per ABI conventions.
|
||||
RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro).
|
||||
*/
|
||||
// void XT_RTOS_TIMER_INT(void)
|
||||
#define XT_RTOS_TIMER_INT _frxt_timer_int
|
||||
#define XT_TICK_PER_SEC configTICK_RATE_HZ
|
||||
|
||||
/*
|
||||
Return in a15 the base address of the co-processor state save area for the
|
||||
thread that triggered a co-processor exception, or 0 if no thread was running.
|
||||
The state save area is structured as defined in xtensa_context.h and has size
|
||||
XT_CP_SIZE. Co-processor instructions should only be used in thread code, never
|
||||
in interrupt handlers or the RTOS kernel. May only be called from assembly code
|
||||
and by the 'call0' instruction. A result of 0 indicates an unrecoverable error.
|
||||
The implementation may use only a2-4, a15 (all other regs must be preserved).
|
||||
*/
|
||||
// void* XT_RTOS_CP_STATE(void)
|
||||
#define XT_RTOS_CP_STATE _xt_task_coproc_state
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
HOOKS TO DYNAMICALLY INSTALL INTERRUPT AND EXCEPTION HANDLERS PER LEVEL.
|
||||
|
||||
This Xtensa RTOS port provides hooks for dynamically installing exception
|
||||
and interrupt handlers to facilitate automated testing where each test
|
||||
case can install its own handler for user exceptions and each interrupt
|
||||
priority (level). This consists of an array of function pointers indexed
|
||||
by interrupt priority, with index 0 being the user exception handler hook.
|
||||
Each entry in the array is initially 0, and may be replaced by a function
|
||||
pointer of type XT_INTEXC_HOOK. A handler may be uninstalled by installing 0.
|
||||
|
||||
The handler for low and medium priority obeys ABI conventions so may be coded
|
||||
in C. For the exception handler, the cause is the contents of the EXCCAUSE
|
||||
reg, and the result is -1 if handled, else the cause (still needs handling).
|
||||
For interrupt handlers, the cause is a mask of pending enabled interrupts at
|
||||
that level, and the result is the same mask with the bits for the handled
|
||||
interrupts cleared (those not cleared still need handling). This allows a test
|
||||
case to either pre-handle or override the default handling for the exception
|
||||
or interrupt level (see xtensa_vectors.S).
|
||||
|
||||
High priority handlers (including NMI) must be coded in assembly, are always
|
||||
called by 'call0' regardless of ABI, must preserve all registers except a0,
|
||||
and must not use or modify the interrupted stack. The hook argument 'cause'
|
||||
is not passed and the result is ignored, so as not to burden the caller with
|
||||
saving and restoring a2 (it assumes only one interrupt per level - see the
|
||||
discussion in high priority interrupts in xtensa_vectors.S). The handler
|
||||
therefore should be coded to prototype 'void h(void)' even though it plugs
|
||||
into an array of handlers of prototype 'unsigned h(unsigned)'.
|
||||
|
||||
To enable interrupt/exception hooks, compile the RTOS with '-DXT_INTEXC_HOOKS'.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#define XT_INTEXC_HOOK_NUM (1 + XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
typedef unsigned (*XT_INTEXC_HOOK)(unsigned cause);
|
||||
extern volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM];
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Define a debug exception cause for XEA2. This is needed to reserve an entry
|
||||
in the exception table for a user-defined handler, and also for registering
|
||||
a user handler. Must use one of the unused/reserved exception causes.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef EXCCAUSE_DEBUG
|
||||
#define EXCCAUSE_DEBUG 21
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
CONVENIENCE INCLUSIONS.
|
||||
|
||||
Ensures RTOS specific files need only include this one Xtensa-generic header.
|
||||
These headers are included last so they can use the RTOS definitions above.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "xtensa_context.h"
|
||||
|
||||
#ifdef XT_RTOS_TIMER_INT
|
||||
#include "xtensa_timer.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Xtensa Port Version.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#define XTENSA_PORT_VERSION 3.00
|
||||
#define XTENSA_PORT_VERSION_STRING "3.00"
|
||||
|
||||
#define XT_IRQ_LOCK_LEVEL XCHAL_EXCM_LEVEL
|
||||
|
||||
#endif /* XTENSA_RTOS_H */
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* XTENSA INFORMATION FOR RTOS TICK TIMER AND CLOCK FREQUENCY
|
||||
*
|
||||
* This header contains definitions and macros for use primarily by Xtensa
|
||||
* RTOS assembly coded source files. It includes and uses the Xtensa hardware
|
||||
* abstraction layer (HAL) to deal with config specifics. It may also be
|
||||
* included in C source files.
|
||||
*
|
||||
* Edit this file to modify timer selection and to specify clock frequency and
|
||||
* tick duration to match timer interrupt to the real-time tick duration.
|
||||
*
|
||||
* If the RTOS has no timer interrupt, then there is no tick timer and the
|
||||
* clock frequency is irrelevant, so all of these macros are left undefined
|
||||
* and the Xtensa core configuration need not have a timer.
|
||||
*/
|
||||
|
||||
#ifndef XTENSA_TIMER_H
|
||||
#define XTENSA_TIMER_H
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
#include <xtensa/coreasm.h>
|
||||
#endif
|
||||
|
||||
#include <xtensa/corebits.h>
|
||||
#include <xtensa/config/system.h>
|
||||
|
||||
#include <FreeRTOSConfig.h>
|
||||
|
||||
/*
|
||||
Select timer to use for periodic tick, and determine its interrupt number
|
||||
and priority. User may specify a timer by defining XT_TIMER_INDEX with -D,
|
||||
in which case its validity is checked (it must exist in this core and must
|
||||
not be on a high priority interrupt - an error will be reported in invalid).
|
||||
Otherwise select the highest priority low or medium priority interrupt timer
|
||||
available.
|
||||
*/
|
||||
#if XCHAL_NUM_TIMERS == 0
|
||||
|
||||
#error "This Xtensa configuration is unsupported, it has no timers."
|
||||
|
||||
#else
|
||||
|
||||
#ifndef XT_TIMER_INDEX
|
||||
#if XCHAL_TIMER3_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
|
||||
#if XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT) <= XCHAL_EXCM_LEVEL
|
||||
#undef XT_TIMER_INDEX
|
||||
#define XT_TIMER_INDEX 3
|
||||
#undef XT_TIMER_LEVEL
|
||||
#define XT_TIMER_LEVEL XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT)
|
||||
#endif
|
||||
#endif
|
||||
#if XCHAL_TIMER2_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
|
||||
#if XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL && \
|
||||
(!defined(XT_TIMER_INDEX) || \
|
||||
XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) > XT_TIMER_LEVEL)
|
||||
#undef XT_TIMER_INDEX
|
||||
#define XT_TIMER_INDEX 2
|
||||
#undef XT_TIMER_LEVEL
|
||||
#define XT_TIMER_LEVEL XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT)
|
||||
#endif
|
||||
#endif
|
||||
#if XCHAL_TIMER1_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
|
||||
#if XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL && \
|
||||
(!defined(XT_TIMER_INDEX) || \
|
||||
XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) > XT_TIMER_LEVEL)
|
||||
#undef XT_TIMER_INDEX
|
||||
#define XT_TIMER_INDEX 1
|
||||
#undef XT_TIMER_LEVEL
|
||||
#define XT_TIMER_LEVEL XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT)
|
||||
#endif
|
||||
#endif
|
||||
#if XCHAL_TIMER0_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
|
||||
#if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL && \
|
||||
(!defined(XT_TIMER_INDEX) || \
|
||||
XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) > XT_TIMER_LEVEL)
|
||||
#undef XT_TIMER_INDEX
|
||||
#define XT_TIMER_INDEX 0
|
||||
#undef XT_TIMER_LEVEL
|
||||
#define XT_TIMER_LEVEL XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef XT_TIMER_INDEX
|
||||
#error "There is no suitable timer in this Xtensa configuration."
|
||||
#endif
|
||||
|
||||
#define XT_CCOMPARE (CCOMPARE + XT_TIMER_INDEX)
|
||||
#define XT_TIMER_INTNUM XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX)
|
||||
#define XT_TIMER_INTPRI XCHAL_INT_LEVEL(XT_TIMER_INTNUM)
|
||||
|
||||
/*
|
||||
* Xtensa LX8 supports up to 128 interrupts whereas LX7 supports up to 32.
|
||||
*
|
||||
* Redefine the legacy XT_TIMER_INTEN (which limited the interrupt number to
|
||||
* be in the lower 32 or lower 64 bits depending on data type) as two defines
|
||||
* describing the INTEN bit within a 32-bit component and a 4-block component,
|
||||
* where each block contains a group of 32 interrupt bits.
|
||||
*
|
||||
* Name changes are intentional such that any dependencies are caught at
|
||||
* compile-time and are found regardless of timer configuration.
|
||||
*/
|
||||
#define XT_TIMER_INTEN_BIT (1 << (XT_TIMER_INTNUM & 31U))
|
||||
#define XT_TIMER_INTEN_BLK (XT_TIMER_INTNUM >> 5)
|
||||
|
||||
#if XT_TIMER_INTNUM == XTHAL_TIMER_UNCONFIGURED
|
||||
#error "The timer selected by XT_TIMER_INDEX does not exist in this core."
|
||||
#elif XT_TIMER_INTPRI > XCHAL_EXCM_LEVEL
|
||||
#error "The timer interrupt cannot be high priority (use medium or low)."
|
||||
#endif
|
||||
|
||||
#endif /* XCHAL_NUM_TIMERS */
|
||||
|
||||
/*
|
||||
Set processor clock frequency, used to determine clock divisor for timer tick.
|
||||
User should BE SURE TO ADJUST THIS for the Xtensa platform being used.
|
||||
If using a supported board via the board-independent API defined in xtbsp.h,
|
||||
this may be left undefined and frequency and tick divisor will be computed
|
||||
and cached during run-time initialization.
|
||||
|
||||
NOTE ON SIMULATOR:
|
||||
Under the Xtensa instruction set simulator, the frequency can only be estimated
|
||||
because it depends on the speed of the host and the version of the simulator.
|
||||
Also because it runs much slower than hardware, it is not possible to achieve
|
||||
real-time performance for most applications under the simulator. A frequency
|
||||
too low does not allow enough time between timer interrupts, starving threads.
|
||||
To obtain a more convenient but non-real-time tick duration on the simulator,
|
||||
compile with the option "-DXT_SIMULATOR".
|
||||
Adjust this frequency to taste (it's not real-time anyway!).
|
||||
*/
|
||||
#if defined(XT_SIMULATOR) && !defined(XT_CLOCK_FREQ)
|
||||
#define XT_CLOCK_FREQ configCPU_CLOCK_HZ
|
||||
#endif
|
||||
|
||||
#if !defined(XT_CLOCK_FREQ) && !defined(XT_BOARD)
|
||||
#error "XT_CLOCK_FREQ must be defined for the target platform."
|
||||
#endif
|
||||
|
||||
/*
|
||||
Default number of timer "ticks" per second (default 100 for 10ms tick).
|
||||
RTOS may define this in its own way (if applicable) in xtensa_rtos.h.
|
||||
User may redefine this to an optimal value for the application, either by
|
||||
editing this here or in xtensa_rtos.h, or compiling with the option
|
||||
"-DXT_TICK_PER_SEC=<value>" where <value> is a suitable number.
|
||||
*/
|
||||
#ifndef XT_TICK_PER_SEC
|
||||
#define XT_TICK_PER_SEC configTICK_RATE_HZ /* 10 ms tick = 100 ticks per second */
|
||||
#endif
|
||||
|
||||
/*
|
||||
Derivation of clock divisor for timer tick and interrupt (one per tick).
|
||||
*/
|
||||
#ifdef XT_CLOCK_FREQ
|
||||
#define XT_TICK_DIVISOR (XT_CLOCK_FREQ / XT_TICK_PER_SEC)
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
extern unsigned _xt_tick_divisor;
|
||||
extern void _xt_tick_divisor_init(void);
|
||||
#endif
|
||||
|
||||
#endif /* XTENSA_TIMER_H */
|
||||
+1953
File diff suppressed because it is too large
Load Diff
+478
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2015-2024 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
|
||||
*
|
||||
*/
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* Xtensa exception and interrupt dispatch for XEA3. */
|
||||
/* */
|
||||
/* Interrupt handlers and user exception handlers support interaction */
|
||||
/* with the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT */
|
||||
/* before and after calling the user's specific interrupt handlers. */
|
||||
/* */
|
||||
/* Users can install application-specific interrupt handlers by calling */
|
||||
/* xt_set_interrupt_handler(). These handlers can be written in C and */
|
||||
/* must follow the C calling convention. The handler table is indexed by */
|
||||
/* the interrupt number. Each handler may be provided with an argument. */
|
||||
/* */
|
||||
/* Users can install application-specific exception handlers in the */
|
||||
/* same way, by calling xt_set_exception_handler(). One handler slot is */
|
||||
/* provided for each exception type. Note that some exceptions are */
|
||||
/* handled by the porting layer itself, and cannot be taken over by */
|
||||
/* application code. These are the alloca, syscall, and coprocessor */
|
||||
/* exceptions. */
|
||||
/* */
|
||||
/* Exception handlers can be written in C, and must follow C calling */
|
||||
/* convention. Each handler is passed a pointer to an exception frame as */
|
||||
/* its single argument. The exception frame is created on the stack and */
|
||||
/* holds the saved context of the thread that took the exception. If the */
|
||||
/* handler returns, the context will be restored and the instruction */
|
||||
/* that caused the exception will be retried. If the handler makes any */
|
||||
/* changes to the saved state in the exception frame, the changes will */
|
||||
/* be applied when restoring the context. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
#include <xtensa/config/core.h>
|
||||
#include <xtensa/coreasm.h>
|
||||
|
||||
#if XCHAL_HAVE_XEA3
|
||||
|
||||
#include "xtensa_context.h"
|
||||
|
||||
#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2)
|
||||
#error Xtensa HW earlier than RH_2016.2 not supported.
|
||||
#endif
|
||||
|
||||
#if XT_STK_XTRA_SZ
|
||||
#define EXCFRAME_XTRA_OFF(field) (XT_STK_XTRA_SZ + (field))
|
||||
#else
|
||||
#define EXCFRAME_XTRA_OFF(field) (field)
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The entry point vectors are common for call0 and windowed configurations.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.extern _DoubleExceptionHandler
|
||||
.extern _xtos_exc_dispatch
|
||||
|
||||
.section .DispatchVector.text, "ax"
|
||||
#if XCHAL_HAVE_VECBASE
|
||||
.align 64 // 64-byte alignment needed when vecbase
|
||||
#else // is relocatable
|
||||
.align 4
|
||||
#endif
|
||||
|
||||
.org 0 // Fixed offset for Reset Vector
|
||||
.global _DispatchVector
|
||||
.weak _DispatchVector
|
||||
|
||||
_DispatchVector:
|
||||
j _JumpToResetHandler
|
||||
|
||||
.org 3 // Reserved
|
||||
.local _Reserved1
|
||||
|
||||
_Reserved1:
|
||||
ill
|
||||
|
||||
.org 6 // Fixed offset for Double Exception Vector
|
||||
.global _DoubleExceptionVector
|
||||
.weak _DoubleExceptionVector
|
||||
|
||||
_DoubleExceptionVector:
|
||||
j _DoubleExceptionHandler
|
||||
|
||||
.org 9 // Reserved
|
||||
.local _Reserved2
|
||||
|
||||
_Reserved2:
|
||||
ill
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Start of dispatch code.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.org 12 // Fixed offset for Tailchain entry point
|
||||
.global _xt_dispatch
|
||||
|
||||
_xt_dispatch:
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
|
||||
// NOTE: for call0, a15 is expected to be holding the previous stack pointer
|
||||
// when we get to the Tailchain segment.
|
||||
|
||||
s32si.x4 a2, a15 // Select interrupt, a2 <- (intnum << 2)
|
||||
movi a0, 0
|
||||
l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0])
|
||||
s32stk a9, a15, 96 // Set new stack pointer
|
||||
#if XT_STK_XTRA_SZ
|
||||
addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area
|
||||
#endif
|
||||
s32dis.h a0, a0 // Jump to handler if interrupt else fall through
|
||||
// Note this also clears local exclusive monitor
|
||||
|
||||
#else // windowed
|
||||
|
||||
s32si.x4 a10, a1 // Select interrupt, a10 <- (intnum << 2)
|
||||
movi a8, 0
|
||||
l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0])
|
||||
s32stk a9, a1, 96 // Set new stack pointer
|
||||
#if XT_STK_XTRA_SZ
|
||||
addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area
|
||||
#endif
|
||||
s32dis.h a8, a8 // Jump to handler if interrupt else fall through
|
||||
// Note this also clears local exclusive monitor
|
||||
|
||||
#endif // __XTENSA_CALL0_ABI__
|
||||
|
||||
.Lexit:
|
||||
j _xt_exit
|
||||
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
.org 36 // Fixed offset for Underflow segment
|
||||
.global _xt_underflow
|
||||
|
||||
_xt_underflow:
|
||||
l32e a8, a1, -64 // a8 <- [a1-32]
|
||||
l32e a9, a1, -64 // a9 <- [a1-28]
|
||||
l32e a10, a1, -64 // a10 <- [a1-24]
|
||||
l32e a11, a1, -64 // a11 <- [a1-20]
|
||||
l32e a12, a1, -64 // a12 <- [a1-16]
|
||||
l32e a13, a1, -64 // a13 <- [a1-12]
|
||||
l32e a14, a1, -64 // a14 <- [a1-8]
|
||||
l32e a15, a1, -64 // a15 <- [a1-4] ; Return (branch to EPC)
|
||||
#endif
|
||||
|
||||
.org 60 // Fixed offset for Save/Overflow segment
|
||||
.global _xt_save
|
||||
|
||||
_xt_save:
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
s32e a0, a1, -64 // [a1-64] <- a0
|
||||
s32e a2, a1, -48 // [a1-56] <- a2 ; a2 <- EPC
|
||||
s32e a3, a1, -64 // [a1-52] <- a3
|
||||
s32e a4, a1, -64 // [a1-48] <- a4
|
||||
s32e a5, a1, -64 // [a1-44] <- a5
|
||||
s32e a6, a1, -64 // [a1-40] <- a6
|
||||
s32e a7, a1, -64 // [a1-36] <- a7
|
||||
#else
|
||||
.global _xt_overflow
|
||||
_xt_overflow:
|
||||
#endif
|
||||
s32e a8, a1, -52 // [a1-32] <- a8 ; a8 <- ExcVAddr
|
||||
s32e a9, a1, -28 // [a1-28] <- a9 ; a9 <- PS/SAR
|
||||
s32e a10, a1, -48 // [a1-24] <- a10 ; a10 <- EPC
|
||||
s32e a11, a1, -24 // [a1-20] <- a11 ; a11 <- ExcCause
|
||||
s32e a12, a1, -44 // [a1-16] <- a12 ; a12 <- LBEG
|
||||
s32e a13, a1, -40 // [a1-12] <- a13 ; a13 <- LEND
|
||||
s32e a14, a1, -36 // [a1-8] <- a14 ; a14 <- LCOUNT
|
||||
s32e a15, a1, -32 // [a1-4] <- a15 ; a15 <- a1
|
||||
// If Overflow then return (branch to EPC)
|
||||
|
||||
_xt_entry:
|
||||
s32e a8, a1, -4 // [a1-68] <- a8 (ExcVAddr)
|
||||
s32e a11, a1, -8 // [a1-72] <- a11 (ExcCause)
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
s32e a12, a1, -20 // [a1-84] <- a12 (LBEG)
|
||||
s32e a13, a1, -24 // [a1-88] <- a13 (LEND)
|
||||
s32e a14, a1, -28 // [a1-92] <- a14 (LCOUNT)
|
||||
#endif
|
||||
#if XCHAL_HAVE_EXCLUSIVE
|
||||
movi a12, 0
|
||||
getex a12
|
||||
s32e a12, a1, -32 // [a1-96] <- a12 (ATOMCTL)
|
||||
#endif
|
||||
#if (defined __XTENSA_WINDOWED_ABI__) && portUSING_MPU_WRAPPERS
|
||||
s32e a2, a1, -36 // [a1-100] <- a2 (syscall arg)
|
||||
#endif
|
||||
|
||||
j 1f // make room for literals
|
||||
|
||||
.align 4
|
||||
.literal_position
|
||||
|
||||
.Le1:
|
||||
.word xt_exception_table
|
||||
|
||||
1:
|
||||
// Call OS-specific code for additional work to be done. Stay on interruptee's
|
||||
// stack in case more saves are required into stack frame.
|
||||
// NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed).
|
||||
// ALL other registers must be preserved.
|
||||
|
||||
XT_RTOS_INT_ENTER
|
||||
|
||||
// This sequence checks the interrupt controller and loads the interrupt
|
||||
// number if available, and also loads the wrapper handler address.
|
||||
// If there is an interrupt, execution will branch to the wrapper which
|
||||
// will then forward to the correct handler.
|
||||
// All this happens only if there is a pending interrupt. If not, execution
|
||||
// falls through to exception handling.
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
|
||||
s32si.x4 a2, a1 // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2)
|
||||
movi a0, 0
|
||||
l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0])
|
||||
s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96
|
||||
#if XT_STK_XTRA_SZ
|
||||
addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area
|
||||
#endif
|
||||
s32dis.h a0, a0 // Jump to handler if interrupt else fall through
|
||||
|
||||
#else // windowed
|
||||
|
||||
s32si.x4 a10, a1 // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2)
|
||||
movi a8, 0
|
||||
l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0])
|
||||
|
||||
// Exception frame size is 96 bytes for Windowed,
|
||||
// plus an extra 4 bytes if MPU wrappers are used (for XT_STK_A2)
|
||||
s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96
|
||||
#if portUSING_MPU_WRAPPERS && XT_STK_XTRA_SZ
|
||||
addi a9, a9, -XT_STK_XTRA_SZ-4 // Adjust for extra save area + XT_STK_A2
|
||||
#elif XT_STK_XTRA_SZ
|
||||
addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area
|
||||
#elif portUSING_MPU_WRAPPERS
|
||||
addi a9, a9, -4 // Adjust for XT_STK_A2
|
||||
#endif
|
||||
s32dis.h a8, a8 // Jump to handler if interrupt else fall through
|
||||
|
||||
#endif // __XTENSA_CALL0_ABI__
|
||||
|
||||
// At this point we have:
|
||||
// (note window has rotated for windowed ABI)
|
||||
// a0 holds return address (Tailchain+3)
|
||||
// For call0:
|
||||
// a11 holds ExcCause, also saved in [oldsp - 72]
|
||||
// a15 holds exception SP, a1 points to exception frame
|
||||
// For windowed:
|
||||
// a3 holds ExcCause, also saved in [oldsp - 72]
|
||||
// a1 holds new SP
|
||||
// New SP + XT_STK_XTRA_SZ points to exception frame
|
||||
|
||||
.global _xt_exception
|
||||
|
||||
_xt_exception:
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
mov a3, a11 // Copy exception cause to a3
|
||||
#endif
|
||||
extui a4, a3, 0, 4 // Extract exception cause
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
// Handle "RAISE PRIVILEGE" SYSCALL in assembly;
|
||||
// others use registered syscall handler
|
||||
bnei a4, EXCCAUSE_SYSCALL, .L_xt_proc_full_exc
|
||||
l32i a2, a1, EXCFRAME_XTRA_OFF(XT_STK_A2) // ExcFrame + A2 offset
|
||||
beqi a2, SYSCALL_raise_priv, do_raise_priv
|
||||
beqi a2, SYSCALL_is_priv, do_is_priv
|
||||
|
||||
.L_xt_proc_full_exc:
|
||||
#endif /* portUSING_MPU_WRAPPERS */
|
||||
l32r a2, .Le1 // Load exc table address
|
||||
addx4 a2, a4, a2 // Index into exc table
|
||||
l32i a4, a2, 0 // Load handler address
|
||||
#if XT_STK_XTRA_SZ
|
||||
addi a2, a1, XT_STK_XTRA_SZ // Argument = Exception frame ptr
|
||||
#else
|
||||
mov a2, a1 // Argument = Exception frame ptr
|
||||
#endif
|
||||
jx a4 // Return directly from handler
|
||||
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
.align 4
|
||||
do_is_priv:
|
||||
l32i a2, a1, EXCFRAME_XTRA_OFF(XT_STK_PS) // ExcFrame + PS offset
|
||||
movi a4, 1
|
||||
extui a2, a2, PS_RING_SHIFT, 1
|
||||
xor a2, a2, a4
|
||||
j privilege_return
|
||||
|
||||
// raise privilege syscall
|
||||
do_raise_priv:
|
||||
l32i a4, a1, EXCFRAME_XTRA_OFF(XT_STK_PS) // ExcFrame + PS offset
|
||||
bbsi a4, PS_RING_SHIFT, raise_privilege
|
||||
movi a2, 1
|
||||
privilege_return:
|
||||
l32i a4, a1, EXCFRAME_XTRA_OFF(XT_STK_PC) // ExcFrame + PC offset
|
||||
addi a4, a4, 3 // ++PC (3-byte syscall instruction)
|
||||
s32i a4, a1, EXCFRAME_XTRA_OFF(XT_STK_PC) // ExcFrame + PC offset
|
||||
s32i a2, a1, EXCFRAME_XTRA_OFF(XT_STK_A2) // Syscall return value
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
ret.n // Emulate end of handler
|
||||
#else
|
||||
retw.n // Emulate end of handler
|
||||
#endif
|
||||
raise_privilege:
|
||||
movi a2, ~PS_RING_MASK // PS.RING = 0
|
||||
and a4, a4, a2
|
||||
s32i a4, a1, EXCFRAME_XTRA_OFF(XT_STK_PS) // ExcFrame + PS offset
|
||||
movi a2, 0
|
||||
j privilege_return
|
||||
#endif /* portUSING_MPU_WRAPPERS */
|
||||
|
||||
// Exit/restore sequence
|
||||
|
||||
.global _xt_exit
|
||||
|
||||
_xt_exit:
|
||||
#if portUSING_MPU_WRAPPERS
|
||||
mov a8, a0
|
||||
call0 _xt_mpu_restore
|
||||
mov a0, a8
|
||||
#endif
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
mov a1, a15 // Restore stack pointer
|
||||
#endif
|
||||
|
||||
// Run OS-specific code to determine what to restore.
|
||||
// Interrupts will remain disabled through this sequence.
|
||||
// WARNING: stack pointer may change within this macro
|
||||
// so all restores off the stack must happen afterwards.
|
||||
|
||||
XT_RTOS_INT_EXIT
|
||||
|
||||
.global _xt_restore
|
||||
|
||||
_xt_restore:
|
||||
// Some loads must happen before DISPST = Restore, as these
|
||||
// will not be accessible via L32E once DISPST = Restore.
|
||||
|
||||
#if !(defined __XTENSA_CALL0_ABI__) && portUSING_MPU_WRAPPERS
|
||||
l32e a2, a1, -36 // a2 <- [a1-100] (syscall return)
|
||||
#endif
|
||||
#if XCHAL_HAVE_EXCLUSIVE
|
||||
l32e a12, a1, -32 // a12 <- [a1-96] (ATOMCTL)
|
||||
getex a12
|
||||
#endif
|
||||
l32e a10, a1, -12 // a10 <- [a1-76] (PS/SAR)
|
||||
l32e a12, a1, -20 // a12 <- [a1-84] (LBEG)
|
||||
l32e a13, a1, -24 // a13 <- [a1-88] (LEND)
|
||||
l32e a14, a1, -28 // a14 <- [a1-92] (LCOUNT)
|
||||
l32dis.epc a11, a1 // a11 <- [a1-80] (EPC)
|
||||
// If interrupt goto tailchain else fall through
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
l32e a0, a1, -64 // a0 <- [a1-64]
|
||||
l32e a2, a1, -64 // a2 <- [a1-56]
|
||||
l32e a3, a1, -64 // a3 <- [a1-52]
|
||||
l32e a4, a1, -64 // a4 <- [a1-48]
|
||||
l32e a5, a1, -64 // a5 <- [a1-44]
|
||||
l32e a6, a1, -64 // a6 <- [a1-40]
|
||||
l32e a7, a1, -64 // a7 <- [a1-36]
|
||||
#endif
|
||||
|
||||
// Important: the following restrictions must be observed:
|
||||
// 1) The LCOUNT register must be restored after LBEG/LEND.
|
||||
// 2) There must be at least 3 instructions between the LCOUNT
|
||||
// restore and the last L32E (the one that branches).
|
||||
|
||||
l32e a12, a1, -44 // LBEG <- a12, a12 <- [a1-16]
|
||||
l32e a13, a1, -40 // LEND <- a13, a13 <- [a1-12]
|
||||
l32e a14, a1, -36 // LCOUNT <- a14, a14 <- [a1-8]
|
||||
l32e a8, a1, -64 // a8 <- [a1-32]
|
||||
l32e a9, a1, -64 // a9 <- [a1-28]
|
||||
l32e a10, a1, -60 // PS/SAR <- a10, a10 <- [a1-24]
|
||||
l32e a11, a1, -48 // EPC <- a11, a11 <- [a1-20]
|
||||
l32e a15, a1, -64 // a15 <- [a1-4], Branch to EPC if no interrupt
|
||||
// If interrupt, branch to Tailchain
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Branch to reset handler code from here. Use CALL0 as a branch, will expand
|
||||
// to CALLX0 if needed when built with the -mlongcalls option.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.local _JumpToResetHandler
|
||||
|
||||
_JumpToResetHandler:
|
||||
call0 _ResetHandler
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Scheduler interrupt handler. Triggered by context switch. At this time only
|
||||
// useful for windowed ABI to spill register windows.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.align 4
|
||||
.global xt_sched_handler
|
||||
|
||||
xt_sched_handler:
|
||||
#ifdef __XTENSA_WINDOWED_ABI__
|
||||
entry a1, 32
|
||||
ssai 1
|
||||
spillw
|
||||
retw
|
||||
#else
|
||||
ret
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Symbols for the debugger to use in identifying interrupt / exception frames.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
.global _Interrupt
|
||||
.set _Interrupt, _xt_dispatch - 1
|
||||
.size _Interrupt, 1
|
||||
|
||||
.global _GeneralException
|
||||
.set _GeneralException, _xt_dispatch
|
||||
.size _GeneralException, .Lexit - _xt_dispatch
|
||||
|
||||
// Size of interrupt frame
|
||||
.global _InterruptFrameSize
|
||||
.set _InterruptFrameSize, XT_STK_FRMSZ
|
||||
|
||||
// Register save offset in interrupt frame
|
||||
.global _InterruptRegisterSaveOffset
|
||||
.set _InterruptRegisterSaveOffset, 0x20
|
||||
|
||||
// EPC offset in interrupt frame
|
||||
.global _InterruptEPCSaveOffset
|
||||
.set _InterruptEPCSaveOffset, 0x10
|
||||
|
||||
// Size of exc frame
|
||||
.global _GeneralExceptionFrameSize
|
||||
.set _GeneralExceptionFrameSize, XT_STK_FRMSZ
|
||||
|
||||
// Register save offset in exc frame
|
||||
.global _GeneralExceptionRegisterSaveOffset
|
||||
.set _GeneralExceptionRegisterSaveOffset, 0x20
|
||||
|
||||
// EPC offset in exc frame
|
||||
.global _GeneralExceptionEPCSaveOffset
|
||||
.set _GeneralExceptionEPCSaveOffset, 0x10
|
||||
|
||||
#endif // XCHAL_HAVE_XEA3
|
||||
Reference in New Issue
Block a user