From ee916bdb91c5a8ade7bf462eeb69a13cb9e3b8ec Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 5 Jan 2022 13:53:08 +0800 Subject: [PATCH] CEVA: add ceva platform xc5 xm6 support Signed-off-by: ligd --- arch/ceva/Kconfig | 133 ++++++ arch/ceva/include/.gitignore | 3 + arch/ceva/include/arch.h | 107 +++++ arch/ceva/include/inttypes.h | 230 +++++++++++ arch/ceva/include/irq.h | 78 ++++ arch/ceva/include/limits.h | 40 ++ arch/ceva/include/math.h | 34 ++ arch/ceva/include/spinlock.h | 106 +++++ arch/ceva/include/stdarg.h | 42 ++ arch/ceva/include/syscall.h | 110 +++++ arch/ceva/include/tls.h | 74 ++++ arch/ceva/include/types.h | 96 +++++ arch/ceva/include/xc5/irq.h | 269 ++++++++++++ arch/ceva/include/xc5/math.h | 58 +++ arch/ceva/include/xc5/reg.h | 143 +++++++ arch/ceva/include/xc5/spinlock.h | 42 ++ arch/ceva/include/xm6/irq.h | 259 ++++++++++++ arch/ceva/include/xm6/math.h | 58 +++ arch/ceva/include/xm6/reg.h | 139 +++++++ arch/ceva/include/xm6/spinlock.h | 160 +++++++ arch/ceva/src/.gitignore | 5 + arch/ceva/src/Makefile | 216 ++++++++++ arch/ceva/src/common/mpu.h | 145 +++++++ arch/ceva/src/common/svcall.h | 130 ++++++ arch/ceva/src/common/up_arch.h | 76 ++++ arch/ceva/src/common/up_assert.c | 372 +++++++++++++++++ arch/ceva/src/common/up_blocktask.c | 143 +++++++ arch/ceva/src/common/up_board.c | 180 ++++++++ arch/ceva/src/common/up_checkstack.c | 204 +++++++++ arch/ceva/src/common/up_createstack.c | 275 ++++++++++++ arch/ceva/src/common/up_doirq.c | 106 +++++ arch/ceva/src/common/up_exit.c | 84 ++++ arch/ceva/src/common/up_fullcontextrestore.c | 51 +++ arch/ceva/src/common/up_heap.c | 273 ++++++++++++ arch/ceva/src/common/up_idle.c | 170 ++++++++ arch/ceva/src/common/up_initialize.c | 232 +++++++++++ arch/ceva/src/common/up_internal.h | 352 ++++++++++++++++ arch/ceva/src/common/up_interruptcontext.c | 45 ++ arch/ceva/src/common/up_modifyreg16.c | 53 +++ arch/ceva/src/common/up_modifyreg32.c | 53 +++ arch/ceva/src/common/up_modifyreg8.c | 53 +++ arch/ceva/src/common/up_pthread_start.c | 70 ++++ arch/ceva/src/common/up_puts.c | 46 +++ arch/ceva/src/common/up_releasepending.c | 114 +++++ arch/ceva/src/common/up_releasestack.c | 117 ++++++ arch/ceva/src/common/up_reprioritizertr.c | 170 ++++++++ arch/ceva/src/common/up_saveusercontext.c | 67 +++ arch/ceva/src/common/up_schedulesigaction.c | 215 ++++++++++ arch/ceva/src/common/up_sigdeliver.c | 96 +++++ arch/ceva/src/common/up_signal_dispatch.c | 75 ++++ arch/ceva/src/common/up_stackframe.c | 111 +++++ arch/ceva/src/common/up_start.c | 312 ++++++++++++++ arch/ceva/src/common/up_svcall.c | 414 +++++++++++++++++++ arch/ceva/src/common/up_switchcontext.c | 51 +++ arch/ceva/src/common/up_task_start.c | 70 ++++ arch/ceva/src/common/up_unblocktask.c | 128 ++++++ arch/ceva/src/common/up_userspace.c | 231 +++++++++++ arch/ceva/src/common/up_usestack.c | 142 +++++++ arch/ceva/src/common/up_vfork.c | 208 ++++++++++ arch/ceva/src/common/vintc.h | 152 +++++++ arch/ceva/src/xc5/Kconfig | 11 + arch/ceva/src/xc5/Toolchain.defs | 68 +++ arch/ceva/src/xc5/cpm.S | 75 ++++ arch/ceva/src/xc5/cpm.h | 52 +++ arch/ceva/src/xc5/psu.h | 42 ++ arch/ceva/src/xc5/syscall.S | 78 ++++ arch/ceva/src/xc5/up_hardfault.c | 93 +++++ arch/ceva/src/xc5/up_head.S | 302 ++++++++++++++ arch/ceva/src/xc5/up_icache.c | 294 +++++++++++++ arch/ceva/src/xc5/up_initialstate.c | 88 ++++ arch/ceva/src/xc5/up_intc.c | 201 +++++++++ arch/ceva/src/xc5/up_mpu.c | 130 ++++++ arch/ceva/src/xc5/up_psu.c | 73 ++++ arch/ceva/src/xc5/up_relocate.c | 87 ++++ arch/ceva/src/xc5/up_signal_handler.S | 99 +++++ arch/ceva/src/xc5/up_svcall_handler.S | 110 +++++ arch/ceva/src/xc5/vfork.S | 112 +++++ arch/ceva/src/xm6/Kconfig | 11 + arch/ceva/src/xm6/Toolchain.defs | 73 ++++ arch/ceva/src/xm6/cpm.h | 64 +++ arch/ceva/src/xm6/syscall.S | 87 ++++ arch/ceva/src/xm6/up_hardfault.c | 111 +++++ arch/ceva/src/xm6/up_head.S | 229 ++++++++++ arch/ceva/src/xm6/up_icache.c | 298 +++++++++++++ arch/ceva/src/xm6/up_initialstate.c | 96 +++++ arch/ceva/src/xm6/up_intc.c | 217 ++++++++++ arch/ceva/src/xm6/up_mpu.c | 130 ++++++ arch/ceva/src/xm6/up_psu.c | 69 ++++ arch/ceva/src/xm6/up_signal_handler.S | 96 +++++ arch/ceva/src/xm6/up_svcall_handler.S | 103 +++++ arch/ceva/src/xm6/vfork.S | 121 ++++++ 91 files changed, 11808 insertions(+) create mode 100644 arch/ceva/Kconfig create mode 100644 arch/ceva/include/.gitignore create mode 100644 arch/ceva/include/arch.h create mode 100644 arch/ceva/include/inttypes.h create mode 100644 arch/ceva/include/irq.h create mode 100644 arch/ceva/include/limits.h create mode 100644 arch/ceva/include/math.h create mode 100644 arch/ceva/include/spinlock.h create mode 100644 arch/ceva/include/stdarg.h create mode 100644 arch/ceva/include/syscall.h create mode 100644 arch/ceva/include/tls.h create mode 100644 arch/ceva/include/types.h create mode 100644 arch/ceva/include/xc5/irq.h create mode 100644 arch/ceva/include/xc5/math.h create mode 100644 arch/ceva/include/xc5/reg.h create mode 100644 arch/ceva/include/xc5/spinlock.h create mode 100644 arch/ceva/include/xm6/irq.h create mode 100644 arch/ceva/include/xm6/math.h create mode 100644 arch/ceva/include/xm6/reg.h create mode 100644 arch/ceva/include/xm6/spinlock.h create mode 100644 arch/ceva/src/.gitignore create mode 100644 arch/ceva/src/Makefile create mode 100644 arch/ceva/src/common/mpu.h create mode 100644 arch/ceva/src/common/svcall.h create mode 100644 arch/ceva/src/common/up_arch.h create mode 100644 arch/ceva/src/common/up_assert.c create mode 100644 arch/ceva/src/common/up_blocktask.c create mode 100644 arch/ceva/src/common/up_board.c create mode 100644 arch/ceva/src/common/up_checkstack.c create mode 100644 arch/ceva/src/common/up_createstack.c create mode 100644 arch/ceva/src/common/up_doirq.c create mode 100644 arch/ceva/src/common/up_exit.c create mode 100644 arch/ceva/src/common/up_fullcontextrestore.c create mode 100644 arch/ceva/src/common/up_heap.c create mode 100644 arch/ceva/src/common/up_idle.c create mode 100644 arch/ceva/src/common/up_initialize.c create mode 100644 arch/ceva/src/common/up_internal.h create mode 100644 arch/ceva/src/common/up_interruptcontext.c create mode 100644 arch/ceva/src/common/up_modifyreg16.c create mode 100644 arch/ceva/src/common/up_modifyreg32.c create mode 100644 arch/ceva/src/common/up_modifyreg8.c create mode 100644 arch/ceva/src/common/up_pthread_start.c create mode 100644 arch/ceva/src/common/up_puts.c create mode 100644 arch/ceva/src/common/up_releasepending.c create mode 100644 arch/ceva/src/common/up_releasestack.c create mode 100644 arch/ceva/src/common/up_reprioritizertr.c create mode 100644 arch/ceva/src/common/up_saveusercontext.c create mode 100644 arch/ceva/src/common/up_schedulesigaction.c create mode 100644 arch/ceva/src/common/up_sigdeliver.c create mode 100644 arch/ceva/src/common/up_signal_dispatch.c create mode 100644 arch/ceva/src/common/up_stackframe.c create mode 100644 arch/ceva/src/common/up_start.c create mode 100644 arch/ceva/src/common/up_svcall.c create mode 100644 arch/ceva/src/common/up_switchcontext.c create mode 100644 arch/ceva/src/common/up_task_start.c create mode 100644 arch/ceva/src/common/up_unblocktask.c create mode 100644 arch/ceva/src/common/up_userspace.c create mode 100644 arch/ceva/src/common/up_usestack.c create mode 100644 arch/ceva/src/common/up_vfork.c create mode 100644 arch/ceva/src/common/vintc.h create mode 100644 arch/ceva/src/xc5/Kconfig create mode 100644 arch/ceva/src/xc5/Toolchain.defs create mode 100644 arch/ceva/src/xc5/cpm.S create mode 100644 arch/ceva/src/xc5/cpm.h create mode 100644 arch/ceva/src/xc5/psu.h create mode 100644 arch/ceva/src/xc5/syscall.S create mode 100644 arch/ceva/src/xc5/up_hardfault.c create mode 100644 arch/ceva/src/xc5/up_head.S create mode 100644 arch/ceva/src/xc5/up_icache.c create mode 100644 arch/ceva/src/xc5/up_initialstate.c create mode 100644 arch/ceva/src/xc5/up_intc.c create mode 100644 arch/ceva/src/xc5/up_mpu.c create mode 100644 arch/ceva/src/xc5/up_psu.c create mode 100644 arch/ceva/src/xc5/up_relocate.c create mode 100644 arch/ceva/src/xc5/up_signal_handler.S create mode 100644 arch/ceva/src/xc5/up_svcall_handler.S create mode 100644 arch/ceva/src/xc5/vfork.S create mode 100644 arch/ceva/src/xm6/Kconfig create mode 100644 arch/ceva/src/xm6/Toolchain.defs create mode 100644 arch/ceva/src/xm6/cpm.h create mode 100644 arch/ceva/src/xm6/syscall.S create mode 100644 arch/ceva/src/xm6/up_hardfault.c create mode 100644 arch/ceva/src/xm6/up_head.S create mode 100644 arch/ceva/src/xm6/up_icache.c create mode 100644 arch/ceva/src/xm6/up_initialstate.c create mode 100644 arch/ceva/src/xm6/up_intc.c create mode 100644 arch/ceva/src/xm6/up_mpu.c create mode 100644 arch/ceva/src/xm6/up_psu.c create mode 100644 arch/ceva/src/xm6/up_signal_handler.S create mode 100644 arch/ceva/src/xm6/up_svcall_handler.S create mode 100644 arch/ceva/src/xm6/vfork.S diff --git a/arch/ceva/Kconfig b/arch/ceva/Kconfig new file mode 100644 index 0000000000..b991c7ff00 --- /dev/null +++ b/arch/ceva/Kconfig @@ -0,0 +1,133 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_CEVA +comment "CEVA Options" + +config ARCH_XC5 + bool + default n + ---help--- + CEVA-XC5 is a licensable DSP and memory subsystem (MSS) platform + designed for advanced wireless communication, with low power and + flexible architecture support for both legacy and next-generation + wireless standards. + +config ARCH_XM6 + bool + default n + select ARCH_HAVE_HARDFAULT_DEBUG + select ARCH_HAVE_MPU + select ARCH_HAVE_MULTICPU + ---help--- + CEVA-XM6 is a licensable DSP and memory subsystem (MSS) platform + targeted for high-performance computer vision and image-processing + applications that provide very high processing power while + maintaining a small footprint and low power consumption. + +config ARCH_FAMILY + string + default "xc5" if ARCH_XC5 + default "xm6" if ARCH_XM6 + +config ARCH_ITCM_SIZE + int "ITCM Size" + +config ARCH_DTCM_SIZE + int "DTCM Size" + +config CEVA_ICACHE + bool "Use I-Cache" + default n + select ARCH_ICACHE + +config CEVA_DCACHE + bool "Use D-Cache" + default n + select ARCH_DCACHE + +config ARCH_NR_FPUS + int "FPU Number" + default 1 + depends on ARCH_HAVE_FPU + ---help--- + Built-in support for the number of Floating Point Unit. + Check your chip specifications first; not all CEVA chips + support the FPU. + +config ARCH_MPU + bool "MPU support" + default n + depends on ARCH_HAVE_MPU + select ARCH_USE_MPU + ---help--- + Built-in support for the CEVA Memory Protection Unit (MPU). + Also used to configure the cache and memory attribute. + +config ARCH_HAVE_VINTC + bool + default n + +config ARCH_HARDFAULT_IRQ + int "Hard Fault IRQ Number" + default -1 + +config ARCH_NR_MEMORY + int "Memory Block Number" + default 1 + +config ARCH_NR_USER_MEMORY + int "User Memory Block Number" + depends on BUILD_PROTECTED + default 1 + +config ARCH_DEFAULT_HEAP + int "Default Heap Index" + default 0 + +config ARCH_USER_DEFAULT_HEAP + int "User Default Heap Index" + depends on BUILD_PROTECTED + default 0 + +config ARCH_STACK_HEAP + int "Stack Heap Index" + default 0 + +config ARCH_KERNEL_STACK_HEAP + int "Kernel Stack Heap Index" + depends on MM_KERNEL_HEAP + default 0 + +config ARCH_RTL_MAJOR + int "RTL Version Major Number" + +config ARCH_RTL_MINOR + int "RTL Version Minor Number" + +config ARCH_RTL_REVISION + int "RTL Version Revision Number" + +config ARCH_HAVE_HARDFAULT_DEBUG + bool + default n + +config DEBUG_HARDFAULT + bool "Verbose Hard-Fault Debug" + default n + depends on ARCH_HAVE_HARDFAULT_DEBUG && DEBUG_ALERT + ---help--- + Enables verbose debug output when a hard fault occurs. This verbose + output is sometimes helpful when debugging difficult hard fault problems, + but may be more than you typically want to see. + +if ARCH_XC5 +source arch/ceva/src/xc5/Kconfig +endif +if ARCH_XM6 +source arch/ceva/src/xm6/Kconfig +endif + +endif # ARCH_CEVA diff --git a/arch/ceva/include/.gitignore b/arch/ceva/include/.gitignore new file mode 100644 index 0000000000..e6460c4a67 --- /dev/null +++ b/arch/ceva/include/.gitignore @@ -0,0 +1,3 @@ +/board +/chip + diff --git a/arch/ceva/include/arch.h b/arch/ceva/include/arch.h new file mode 100644 index 0000000000..4dfdd2df8b --- /dev/null +++ b/arch/ceva/include/arch.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/ceva/include/arch.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, + * only indirectly through nuttx/arch.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_ARCH_H +#define __ARCH_CEVA_INCLUDE_ARCH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK == 0 +/* The interrupt stack is required for CEVA porting */ + +# undef CONFIG_ARCH_INTERRUPTSTACK +# define CONFIG_ARCH_INTERRUPTSTACK CONFIG_IDLETHREAD_STACKSIZE +#endif + +#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) +/* In the kernel build, there are multiple user heaps; one for each task + * group. In this build configuration, the user heap structure lies + * in a reserved region at the beginning of the .bss/.data address + * space (CONFIG_ARCH_DATA_VBASE). The size of that region is given by + * ARCH_DATA_RESERVE_SIZE + */ + +# define UMM_HEAP(i) ((i) ? NULL : &ARCH_DATA_RESERVE->ar_usrheap) + +#elif defined(CONFIG_BUILD_PROTECTED) && defined(__KERNEL__) +/* In the protected mode, there are two heaps: A kernel heap and a single + * user heap. Kernel code must obtain the address of the user heap data + * structure from the userspace interface. + */ + +# define UMM_HEAP(i) ((struct mm_heap_s *const *)USERSPACE->us_heap)[i] + +#else +/* Otherwise, the user heap data structures are in common .bss */ + +# define UMM_HEAP(i) g_mm_heap[i] +#endif + +#ifdef CONFIG_MM_KERNEL_HEAP +/* Kernel has the dedicated heap data structures */ + +# define KMM_HEAP(i) g_mm_heap[i] +#else +/* Otherwise, kernel allocate the memory from the user heap data structures */ + +# define KMM_HEAP(i) UMM_HEAP(i) +#endif + +#ifdef __KERNEL__ +# define MM_HEAP(i) KMM_HEAP(i) +#else +# define MM_HEAP(i) UMM_HEAP(i) +#endif + +#define PM_IDLE_DOMAIN 0 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +EXTERN struct mm_heap_s *const g_mm_heap[]; + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_CEVA_INCLUDE_ARCH_H */ diff --git a/arch/ceva/include/inttypes.h b/arch/ceva/include/inttypes.h new file mode 100644 index 0000000000..ee1533d39c --- /dev/null +++ b/arch/ceva/include/inttypes.h @@ -0,0 +1,230 @@ +/**************************************************************************** + * arch/ceva/include/inttypes.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_INTTYPES_H +#define __ARCH_CEVA_INCLUDE_INTTYPES_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "lld" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 "lld" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 "lld" + +#define PRIdMAX "lld" +#define PRIdPTR "d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 "lli" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 "lli" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 "lli" + +#define PRIiMAX "lli" +#define PRIiPTR "i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 "llo" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 "llo" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 "llo" + +#define PRIoMAX "llo" +#define PRIoPTR "o" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 "llu" + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 "llu" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 "llu" + +#define PRIuMAX "llu" +#define PRIuPTR "u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "llx" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 "llx" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 "llx" + +#define PRIxMAX "llx" +#define PRIxPTR "x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 "llX" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 "llX" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 "llX" + +#define PRIXMAX "llX" +#define PRIXPTR "X" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 "lld" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 "lld" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 "hd" +#define SCNdFAST32 "d" +#define SCNdFAST64 "lld" + +#define SCNdMAX "lld" +#define SCNdPTR "d" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "lli" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 "lli" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 "hi" +#define SCNiFAST32 "i" +#define SCNiFAST64 "lli" + +#define SCNiMAX "lli" +#define SCNiPTR "i" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 "llo" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 "llo" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 "ho" +#define SCNoFAST32 "o" +#define SCNoFAST64 "llo" + +#define SCNoMAX "llo" +#define SCNoPTR "o" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 "llu" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 "llu" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 "hu" +#define SCNuFAST32 "u" +#define SCNuFAST64 "llu" + +#define SCNuMAX "llu" +#define SCNuPTR "u" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 "llx" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 "llx" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 "hx" +#define SCNxFAST32 "x" +#define SCNxFAST64 "llx" + +#define SCNxMAX "llx" +#define SCNxPTR "x" + +#endif /* __ARCH_CEVA_INCLUDE_INTTYPES_H */ diff --git a/arch/ceva/include/irq.h b/arch/ceva/include/irq.h new file mode 100644 index 0000000000..bd9a98e257 --- /dev/null +++ b/arch/ceva/include/irq.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * arch/ceva/include/irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directed but, rather, only indirectly + * through nuttx/irq.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_IRQ_H +#define __ARCH_CEVA_INCLUDE_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/* Include chip-specific IRQ definitions (including IRQ numbers) */ + +#include + +/* Include CEVA architecture-specific IRQ definitions (including register + * save structure and up_irq_save()/up_irq_restore() functions) + */ + +#if defined(CONFIG_ARCH_XC5) +# include +#elif defined(CONFIG_ARCH_XM6) +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IRQ_VINT0 (IRQ_VINT_FIRST + 0) +#define IRQ_VINT1 (IRQ_VINT_FIRST + 1) +#define IRQ_VINT2 (IRQ_VINT_FIRST + 2) +#define IRQ_VINT3 (IRQ_VINT_FIRST + 3) +#define IRQ_VINT4 (IRQ_VINT_FIRST + 4) +#define IRQ_VINT5 (IRQ_VINT_FIRST + 5) +#define IRQ_VINT6 (IRQ_VINT_FIRST + 6) +#define IRQ_VINT7 (IRQ_VINT_FIRST + 7) +#define IRQ_VINT8 (IRQ_VINT_FIRST + 8) +#define IRQ_VINT9 (IRQ_VINT_FIRST + 9) +#define IRQ_VINT10 (IRQ_VINT_FIRST + 10) +#define IRQ_VINT11 (IRQ_VINT_FIRST + 11) +#define IRQ_VINT12 (IRQ_VINT_FIRST + 12) +#define IRQ_VINT13 (IRQ_VINT_FIRST + 13) +#define IRQ_VINT14 (IRQ_VINT_FIRST + 14) +#define IRQ_VINT15 (IRQ_VINT_FIRST + 15) +#define IRQ_VINT16 (IRQ_VINT_FIRST + 16) +#define IRQ_VINT17 (IRQ_VINT_FIRST + 17) +#define IRQ_VINT18 (IRQ_VINT_FIRST + 18) +#define IRQ_VINT19 (IRQ_VINT_FIRST + 19) +#define IRQ_VINT20 (IRQ_VINT_FIRST + 20) +#define IRQ_VINT21 (IRQ_VINT_FIRST + 21) +#define IRQ_VINT22 (IRQ_VINT_FIRST + 22) +#define IRQ_VINT23 (IRQ_VINT_FIRST + 23) +#define IRQ_VINT24 (IRQ_VINT_FIRST + 24) +#define IRQ_VINT25 (IRQ_VINT_FIRST + 25) +#define IRQ_VINT26 (IRQ_VINT_FIRST + 26) + +#endif /* __ARCH_CEVA_INCLUDE_IRQ_H */ diff --git a/arch/ceva/include/limits.h b/arch/ceva/include/limits.h new file mode 100644 index 0000000000..e4b1b17637 --- /dev/null +++ b/arch/ceva/include/limits.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * arch/ceva/include/limits.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_LIMITS_H +#define __ARCH_CEVA_INCLUDE_LIMITS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include_next + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Assume ILP32 or LP64 */ + +#define PTR_MIN LONG_MIN +#define PTR_MAX LONG_MAX +#define UPTR_MAX ULONG_MAX + +#endif /* __ARCH_CEVA_INCLUDE_LIMITS_H */ diff --git a/arch/ceva/include/math.h b/arch/ceva/include/math.h new file mode 100644 index 0000000000..e53b28cc73 --- /dev/null +++ b/arch/ceva/include/math.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * arch/ceva/include/math.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_MATH_H +#define __ARCH_CEVA_INCLUDE_MATH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#if defined(CONFIG_ARCH_XC5) +# include +#elif defined(CONFIG_ARCH_XM6) +# include +#endif + +#endif /* __ARCH_CEVA_INCLUDE_MATH_H */ diff --git a/arch/ceva/include/spinlock.h b/arch/ceva/include/spinlock.h new file mode 100644 index 0000000000..13cc8fb1b2 --- /dev/null +++ b/arch/ceva/include/spinlock.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/ceva/include/spinlock.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_SPINLOCK_H +#define __ARCH_CEVA_INCLUDE_SPINLOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +# include +#endif /* __ASSEMBLY__ */ + +#if defined(CONFIG_ARCH_XC5) +# include +#elif defined(CONFIG_ARCH_XM6) +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Spinlock states */ + +#define SP_UNLOCKED 0 /* The Unlocked state */ +#define SP_LOCKED 1 /* The Locked state */ + +/* Memory barriers for use with NuttX spinlock logic + * + * Data Memory Barrier (DMB) acts as a memory barrier. It ensures that all + * explicit memory accesses that appear in program order before the DMB + * instruction are observed before any explicit memory accesses that appear + * in program order after the DMB instruction. It does not affect the + * ordering of any other instructions executing on the processor + * + * Data Synchronization Barrier (DSB) acts as a special kind of memory + * barrier. No instruction in program order after this instruction executes + * until this instruction completes. This instruction completes when: (1) All + * explicit memory accesses before this instruction complete, and (2) all + * Cache, Branch predictor and TLB maintenance operations before this + * instruction complete. + * + */ + +#define SP_DSB(n) up_dsb() +#define SP_DMB(n) up_dmb() + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* The Type of a spinlock. */ + +typedef uint32_t spinlock_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: up_testset + * + * Description: + * Perform an atomic test and set operation on the provided spinlock. + * + * This function must be provided via the architecture-specific logoic. + * + * Input Parameters: + * lock - The address of spinlock object. + * + * Returned Value: + * The spinlock is always locked upon return. The value of previous value + * of the spinlock variable is returned, either SP_LOCKED if the spinlock + * as previously locked (meaning that the test-and-set operation failed to + * obtain the lock) or SP_UNLOCKED if the spinlock was previously unlocked + * (meaning that we successfully obtained the lock) + * + ****************************************************************************/ + +/* See prototype in nuttx/include/nuttx/spinlock.h */ + +/* Include CEVA architecture-specific spinlock definitions */ + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_CEVA_INCLUDE_SPINLOCK_H */ diff --git a/arch/ceva/include/stdarg.h b/arch/ceva/include/stdarg.h new file mode 100644 index 0000000000..60ebc732f3 --- /dev/null +++ b/arch/ceva/include/stdarg.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/ceva/include/stdarg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_STDARG_H +#define __ARCH_CEVA_INCLUDE_STDARG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Redefine va_copy since: + * 1.TL4 doesn't define it at all + * 2.XM6/X2 generate the wrong code + */ + +#undef va_copy +#define va_copy(d,s) ((d) = (s)) + +#endif /* __ARCH_CEVA_INCLUDE_STDARG_H */ diff --git a/arch/ceva/include/syscall.h b/arch/ceva/include/syscall.h new file mode 100644 index 0000000000..8ad41665a4 --- /dev/null +++ b/arch/ceva/include/syscall.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * arch/ceva/include/syscall.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directed but, rather, only indirectly + * through include/syscall.h or include/sys/sycall.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_SYSCALL_H +#define __ARCH_CEVA_INCLUDE_SYSCALL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* TRAP call with SYS_ call number and no parameters */ + +uintptr_t sys_call0(unsigned int nbr); + +/* TRAP call with SYS_ call number and one parameter */ + +uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1); + +/* TRAP call with SYS_ call number and two parameters */ + +uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2); + +/* TRAP call with SYS_ call number and three parameters */ + +uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3); + +/* TRAP call with SYS_ call number and four parameters */ + +uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4); + +/* TRAP call with SYS_ call number and five parameters */ + +uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5); + +/* TRAP call with SYS_ call number and six parameters */ + +uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5, + uintptr_t parm6); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif + +#endif /* __ARCH_CEVA_INCLUDE_SYSCALL_H */ diff --git a/arch/ceva/include/tls.h b/arch/ceva/include/tls.h new file mode 100644 index 0000000000..fbf14953d1 --- /dev/null +++ b/arch/ceva/include/tls.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * arch/ceva/include/tls.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_TLS_H +#define __ARCH_CEVA_INCLUDE_TLS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#ifdef CONFIG_TLS + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_tls_info + * + * Description: + * Return the TLS information structure for the currently executing thread. + * When TLS is enabled, up_createstack() will align allocated stacks to + * the TLS_STACK_ALIGN value. An instance of the following structure will + * be implicitly positioned at the "lower" end of the stack. Assuming a + * "push down" stack, this is at the "far" end of the stack (and can be + * clobbered if the stack overflows). + * + * If an MCU has a "push up" then that TLS structure will lie at the top + * of the stack and stack allocation and initialization logic must take + * care to preserve this structure content. + * + * The stack memory is fully accessible to user mode threads. + * + * Input Parameters: + * None + * + * Returned Value: + * A pointer to TLS info structure at the beginning of the STACK memory + * allocation. This is essentially an application of the TLS_INFO(sp) + * macro and has a platform dependency only in the manner in which the + * stack pointer (sp) is obtained and interpreted. + * + ****************************************************************************/ + +static inline FAR struct tls_info_s *up_tls_info(void) +{ + DEBUGASSERT(!up_interrupt_context()); + return TLS_INFO((uintptr_t)up_getsp()); +} + +#endif /* CONFIG_TLS */ +#endif /* __ARCH_CEVA_INCLUDE_TLS_H */ diff --git a/arch/ceva/include/types.h b/arch/ceva/include/types.h new file mode 100644 index 0000000000..c82e2f0686 --- /dev/null +++ b/arch/ceva/include/types.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * arch/ceva/include/types.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directed but, rather, only indirectly + * through sys/types.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_TYPES_H +#define __ARCH_CEVA_INCLUDE_TYPES_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Type Declarations + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* These are the sizes of the standard integer types. NOTE that these type + * names have a leading underscore character. This file will be included + * (indirectly) by include/stdint.h and typedef'ed to the final name without + * the underscore character. This roundabout way of doings things allows + * the stdint.h to be removed from the include/ directory in the event that + * the user prefers to use the definitions provided by their toolchain header + * files + */ + +typedef signed char _int8_t; +typedef unsigned char _uint8_t; + +typedef signed short _int16_t; +typedef unsigned short _uint16_t; + +typedef signed int _int32_t; +typedef unsigned int _uint32_t; + +typedef signed long long _int64_t; +typedef unsigned long long _uint64_t; +#define __INT64_DEFINED + +/* A size is 4 bytes */ + +#if defined(__SIZE_TYPE__) +/* If __SIZE_TYPE__ is defined we define ssize_t based on size_t. + * We simply change "unsigned" to "signed" for this single definition + * to make sure ssize_t and size_t only differ by their signedness. + */ + +#define unsigned signed +typedef __SIZE_TYPE__ _ssize_t; +#undef unsigned +typedef __SIZE_TYPE__ _size_t; +#elif defined(CONFIG_ARCH_SIZET_LONG) +typedef signed long _ssize_t; +typedef unsigned long _size_t; +#else +typedef signed int _ssize_t; +typedef unsigned int _size_t; +#endif + +/* This is the size of the interrupt state save returned by up_irq_save(). */ + +typedef unsigned int irqstate_t; + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ARCH_CEVA_INCLUDE_TYPES_H */ diff --git a/arch/ceva/include/xc5/irq.h b/arch/ceva/include/xc5/irq.h new file mode 100644 index 0000000000..e086774f1e --- /dev/null +++ b/arch/ceva/include/xc5/irq.h @@ -0,0 +1,269 @@ +/**************************************************************************** + * arch/ceva/include/xc5/irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directed but, rather, only indirectly + * through nuttx/irq.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_XC5_IRQ_H +#define __ARCH_CEVA_INCLUDE_XC5_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/* Included implementation-dependent register save structure layouts */ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* If this is kernel build, how many nested system calls should we support? */ + +#ifndef CONFIG_SYS_NNEST +# define CONFIG_SYS_NNEST 2 +#endif + +/* Alternate register names *************************************************/ + +#define REG_FP REG_G0 +#define REG_LR REG_RETREG +#define REG_PC REG_RETREGI +#define REG_OM REG_MODQ + +/* MODG: satuation */ +#define REG_MODG_DEFAULT 0x001b + +/* MODP: IRQ enable/disable */ +#define REG_MODP_DEFAULT 0x3f80 + +#define REG_MODP_ENABLE 0x3f80 +#define REG_MODP_DISABLE 0x0080 + +/* MOD2: Confirm C compiler assumption */ +#define REG_MODPB_DEFAULT 0xf0 /* TRAPx */ + +/* MODQ: Operation mode */ +#define REG_OM_DEFAULT 0x20 /* PI and Supervisor */ + +/* Note: this is POM filed not OM field */ +#define REG_OM_KERNEL 0x00 /* Supervisor Mode */ +#define REG_OM_USER 0x08 /* User0 Mode */ +#define REG_OM_MASK 0x18 /* Mode mask */ + +/* First Level Interrupt (vectors 0-15) */ + +#define IRQ_RESET 0x00 /* Vector 0: Reset(not handler as an IRQ) */ +#define IRQ_BOOT 0x01 /* Vector 1: Boot(not handler as an IRQ) */ +#define IRQ_TRAP 0x02 /* Vector 2: Software interrupt */ +#define IRQ_TRAPE 0x03 /* Vector 3: Emulation Software Interrupt */ +#define IRQ_BI 0x03 /* Vector 3: Breakpoint Interrupt */ +#define IRQ_CRCALL 0x03 /* Vector 3: Code Replacement Call */ +#define IRQ_NMI 0x04 /* Vector 4: Non-Maskable Interrupt */ +#define IRQ_INT0 0x05 /* Vector 5: Maskable Interrupt 0 */ +#define IRQ_INT1 0x06 /* Vector 6: Maskable Interrupt 1 */ +#define IRQ_INT2 0x07 /* Vector 7: Maskable Interrupt 2 */ +#define IRQ_INT3 0x08 /* Vector 8: Maskable Interrupt 3 */ +#define IRQ_INT4 0x09 /* Vector 9: Maskable Interrupt 4 */ +#define IRQ_VINT 0x0a /* Vector 10: Vectored Interrupt */ +#define IRQ_TRAP0 0x0b /* Vector 10: Software Interrupt 0 */ +#define IRQ_TRAP1 0x0c /* Vector 11: Software Interrupt 1 */ +#define IRQ_TRAP2 0x0d /* Vector 12: Software Interrupt 2 */ +#define IRQ_TRAP3 0x0e /* Vector 13: Software Interrupt 3 */ +#define IRQ_PABP 0x0f /* Vector 15: Program Address Breakpoint */ + +/* Second Level interrupts (vectors >= 16). + * These definitions are chip-specific + */ + +#define IRQ_VINT_FIRST 16 /* Vector number of the first VINT interrupt */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* This structure represents the return state from a system call */ + +#ifdef CONFIG_LIB_SYSCALL +struct xcpt_syscall_s +{ + uint32_t saved_pc; +}; +#endif + +/* The following structure is included in the TCB and defines the complete + * state of the thread. + */ + +struct xcptcontext +{ +#ifndef CONFIG_DISABLE_SIGNALS + /* The following function pointer is non-zero if there + * are pending signals to be processed. + */ + + FAR void *sigdeliver; /* Actual type is sig_deliver_t */ + + /* These are saved copies of the context used during + * signal processing. + */ + + uint32_t *saved_regs; + +# ifdef CONFIG_BUILD_PROTECTED + /* This is the saved address to use when returning from a user-space + * signal handler. + */ + + uint32_t sigreturn; + +# endif +#endif + +#ifdef CONFIG_LIB_SYSCALL + /* The following array holds the return address + * needed to return from each nested system call. + */ + + uint8_t nsyscalls; + struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; + +#endif + + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ + + uint32_t *regs; +}; +#endif + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Name: up_irq_save, up_irq_restore, and friends. + * + * NOTE: This function should never be called from application code and, + * as a general rule unless you really know what you are doing, this + * function should not be called directly from operation system code either: + * Typically, the wrapper functions, enter_critical_section() and + * leave_critical section(), are probably what you really want. + */ + +/* Get/set the MODp register, here is the irq related bits: + * Bit [0] Interrupt context for NMI (RW) + * Bit [1] Interrupt context for INT0 (RW) + * Bit [2] Interrupt context for INT1 (RW) + * Bit [3] Interrupt context for INT2 (RW) + * Bit [4] Interrupt context for INT3 (RW) + * Bit [5] Interrupt context for INT4 (RW) + * Bit [6] (Reserved) + * Bit [7] Interrupt Enable (RW) + * Bit [8] Interrupt mask for INT0 (RW) + * Bit [9] Interrupt mask for INT1 (RW) + * Bit [10] Interrupt mask for INT2 (RW) + * Bit [11] Interrupt mask for INT3 (RW) + * Bit [12] Interrupt mask for INT4 (RW) + * Bit [13] Interrupt mask for VINT (RW) + * Bit [14] (Reserved) + * Bit [15] Interrupt pending for INT0 (RO) + * Bit [16] Interrupt pending for INT1 (RO) + * Bit [17] Interrupt pending for INT2 (RO) + * Bit [18] Interrupt pending for INT3 (RO) + * Bit [19] Interrupt pending for INT3 (RO) + * Bit [20] Interrupt pending for VINT (RO) + * All writable bits are clear by hardware during reset. + * + * We manipulate the individual mask bits instead of global enable bit since: + * 1.Global IE not only mask INTX request but also mask TRAPX instruction. + * 2.Hardware always enable global IE after the interrupt return. + * Both behavior don't match the nuttx requirement. + */ + +static inline uint32_t getmodp(void) +{ + register uint32_t modp __asm__ ("r0"); + __asm__ __volatile__("mov modp, %0\nnop\nnop" : "=r"(modp)); + return modp; +} + +static inline void setmodp(uint32_t modp_v) +{ + __asm__ __volatile__("nop\nnop\nmov %0, r0\nnop\nnop" : : "r"(modp_v)); + __asm__ __volatile__ + ( + "mov r0, modp\n" + "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop" + ); +} + +static inline void up_irq_disable(void) +{ + setmodp(REG_MODP_DISABLE); +} + +static inline irqstate_t up_irq_save(void) +{ + irqstate_t flags = getmodp(); + up_irq_disable(); + return flags; +} + +static inline void up_irq_enable(void) +{ + setmodp(REG_MODP_ENABLE); +} + +static inline void up_irq_restore(irqstate_t flags) +{ + setmodp(flags); +} + +/**************************************************************************** + * Name: up_getsp + ****************************************************************************/ + +static inline uint32_t up_getsp(void) +{ + uint32_t sp; + __asm__ __volatile__("nop\nmov sp, %0" : "=r"(sp)); + return sp; +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_CEVA_INCLUDE_XC5_IRQ_H */ diff --git a/arch/ceva/include/xc5/math.h b/arch/ceva/include/xc5/math.h new file mode 100644 index 0000000000..12c350fbee --- /dev/null +++ b/arch/ceva/include/xc5/math.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * arch/ceva/include/xc5/math.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XC5_MATH_H +#define __ARCH_CEVA_INCLUDE_XC5_MATH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include_next + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +float roundf(float x); +double round (double x); +long double roundl(long double x); + +double gamma(double x); +double lgamma(double x); + +float log2f (float x); +double log2 (double x); +long double log2l (long double x); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_CEVA_INCLUDE_XC5_MATH_H */ diff --git a/arch/ceva/include/xc5/reg.h b/arch/ceva/include/xc5/reg.h new file mode 100644 index 0000000000..269af1dd7c --- /dev/null +++ b/arch/ceva/include/xc5/reg.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * arch/ceva/include/xc5/reg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XC5_REG_H +#define __ARCH_CEVA_INCLUDE_XC5_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IRQ Stack Frame Format: */ + +/* The following registers are stored by the interrupt handling + * logic. + */ + +#define REG_SP 0 +#define REG_BKNEST40 1 +#define REG_BKNEST41 2 +#define REG_BKNEST30 3 +#define REG_BKNEST31 4 +#define REG_BKNEST20 5 +#define REG_BKNEST21 6 +#define REG_MODU2D 7 +#define REG_MODU3D 8 +#define REG_G4D 9 +#define REG_G5D 10 +#define REG_G6D 11 +#define REG_G7D 12 +#define REG_A20 13 +#define REG_A21 14 +#define REG_A22 15 +#define REG_A23 16 +#define REG_AKLMNE 17 +#define REG_RETREGN 18 +#define REG_MODP 19 +#define REG_MODQ 20 +#define REG_A16 21 +#define REG_A17 22 +#define REG_A18 23 +#define REG_A19 24 +#define REG_AGHIJE 25 +#define REG_S0 26 +#define REG_S1 27 +#define REG_S2 28 +#define REG_G0 29 +#define REG_G1 30 +#define REG_G2 31 +#define REG_G3 32 +#define REG_R0 33 +#define REG_R1 34 +#define REG_R2 35 +#define REG_R3 36 +#define REG_RETREG 37 +#define REG_RETREGB 38 +#define REG_RETREGI 39 +#define REG_A4 40 +#define REG_A5 41 +#define REG_A6 42 +#define REG_A7 43 +#define REG_A4567E 44 +#define BKNEST10 45 +#define BKNEST11 46 +#define REG_S3 47 +#define REG_A12 48 +#define REG_A13 49 +#define REG_A14 50 +#define REG_A15 51 +#define REG_ACDEFE 52 +#define REG_MOD0 53 +#define REG_MOD1 54 +#define REG_MOD2 55 +#define REG_MODG 56 +#define REG_MOD3 57 +#define REG_R4 58 +#define REG_R5 59 +#define REG_R6 60 +#define REG_A8 61 +#define REG_A9 62 +#define REG_A10 63 +#define REG_A11 64 +#define REG_A89ABE 65 +#define REG_BKNEST00 66 +#define REG_BKNEST01 67 +#define REG_MODU2 68 +#define REG_MODU3 69 +#define REG_G4 70 +#define REG_G5 71 +#define REG_G6 72 +#define REG_G7 73 +#define REG_R7 74 +#define REG_A0 75 +#define REG_A1 76 +#define REG_A2 77 +#define REG_A3 78 +#define REG_A0123E 79 +#define REG_MODU0 80 +#define REG_MODU1 81 +#define REG_RETREG2 82 + +/* The total number of registers is saved on the stack */ + +#define XCPTCONTEXT_REGS 83 +#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ARCH_CEVA_INCLUDE_XC5_REG_H */ diff --git a/arch/ceva/include/xc5/spinlock.h b/arch/ceva/include/xc5/spinlock.h new file mode 100644 index 0000000000..e766f90ca9 --- /dev/null +++ b/arch/ceva/include/xc5/spinlock.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/ceva/include/xc5/spinlock.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XC5_SPINLOCK_H +#define __ARCH_CEVA_INCLUDE_XC5_SPINLOCK_H + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Memory barrier doesn't need on tl4 */ + +static inline void up_dsb(void) +{ +} + +static inline void up_dmb(void) +{ +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_CEVA_INCLUDE_XC5_SPINLOCK_H */ diff --git a/arch/ceva/include/xm6/irq.h b/arch/ceva/include/xm6/irq.h new file mode 100644 index 0000000000..69a73b19d7 --- /dev/null +++ b/arch/ceva/include/xm6/irq.h @@ -0,0 +1,259 @@ +/**************************************************************************** + * arch/ceva/include/xm6/irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directed but, rather, only indirectly + * through nuttx/irq.h + */ + +#ifndef __ARCH_CEVA_INCLUDE_XM6_IRQ_H +#define __ARCH_CEVA_INCLUDE_XM6_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/* Included implementation-dependent register save structure layouts */ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* If this is kernel build, how many nested system calls should we support? */ + +#ifndef CONFIG_SYS_NNEST +# define CONFIG_SYS_NNEST 2 +#endif + +/* Alternate register names *************************************************/ + +#define REG_A0 REG_R0 +#define REG_A1 REG_R1 +#define REG_A2 REG_R2 +#define REG_A3 REG_R3 +#define REG_A4 REG_R4 +#define REG_A5 REG_R5 +#define REG_A6 REG_R6 +#define REG_FP REG_R8 +#define REG_LR REG_RETREG +#define REG_PC REG_RETREGI +#define REG_OM REG_MODC /* Operation Mode */ + +/* MODA: IRQ enable/disable */ + +#define REG_MODA_DEFAULT 0x07f0 + +#define REG_MODA_ENABLE 0x07f0 +#define REG_MODA_DISABLE 0x0010 + +/* MODC: Operation mode */ + +#define REG_OM_DEFAULT 0x20 /* PI and Supervisor */ + +/* Note: this is POM field not OM field */ + +#define REG_OM_KERNEL 0x00 /* Supervisor Mode */ +#define REG_OM_USER 0x08 /* User0 Mode */ +#define REG_OM_MASK 0x18 /* Mode Mask */ + +/* First Level Interrupt (vectors 0-15) */ + +#define IRQ_RESET 0x00 /* Vector 0: Reset(not handler as an IRQ) */ +#define IRQ_BOOT 0x01 /* Vector 1: Boot(not handler as an IRQ) */ +#define IRQ_TRAP 0x02 /* Vector 2: Software Interrupt */ +#define IRQ_TRAPE 0x03 /* Vector 3: Emulation Software Interrupt */ +#define IRQ_BI 0x03 /* Vector 3: Breakpoint Interrupt */ +#define IRQ_NMI 0x04 /* Vector 4: Non-Maskable Interrupt */ +#define IRQ_INT0 0x05 /* Vector 5: Maskable Interrupt 0 */ +#define IRQ_INT1 0x06 /* Vector 6: Maskable Interrupt 1 */ +#define IRQ_INT2 0x07 /* Vector 7: Maskable Interrupt 2 */ +#define IRQ_INT3 0x08 /* Vector 8: Maskable Interrupt 3 */ +#define IRQ_INT4 0x09 /* Vector 9: Maskable Interrupt 4 */ +#define IRQ_VINT 0x0a /* Vector 10: Vectored Interrupt */ +#define IRQ_TRAP0 0x0b /* Vector 11: Software Interrupt 0 */ +#define IRQ_TRAP1 0x0c /* Vector 12: Software Interrupt 1 */ +#define IRQ_TRAP2 0x0d /* Vector 13: Software Interrupt 2 */ +#define IRQ_TRAP3 0x0e /* Vector 14: Software Interrupt 3 */ +#define IRQ_PABP 0x03 /* Vector 3: Program Address Breakpoint */ + +/* Second Level interrupts (vectors >= 16). + * These definitions are chip-specific. + */ + +#define IRQ_VINT_FIRST 16 /* Vector number of the first VINT interrupt */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ +#ifndef __ASSEMBLY__ + +/* This structure represents the return state from a system call */ + +#ifdef CONFIG_LIB_SYSCALL +struct xcpt_syscall_s +{ + uint32_t saved_pc; + uint32_t saved_om; +}; +#endif + +/* The following structure is included in the TCB and defines the complete + * state of the thread. + */ + +struct xcptcontext +{ +#ifndef CONFIG_DISABLE_SIGNALS + /* The following function pointer is non-zero if there + * are pending signals to be processed. + */ + + FAR void *sigdeliver; /* Actual type is sig_deliver_t */ + + /* These are saved copies of the context used during + * signal processing. + */ + + uint32_t *saved_regs; + +# ifdef CONFIG_BUILD_PROTECTED + /* This is the saved address to use when returning from a user-space + * signal handler. + */ + + uint32_t sigreturn; + +# endif +#endif + +#ifdef CONFIG_LIB_SYSCALL + /* The following array holds the return address and operation mode + * needed to return from each nested system call. + */ + + uint8_t nsyscalls; + struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; + +#endif + + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ + + uint32_t *regs; +}; +#endif + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Name: up_irq_save, up_irq_restore, and friends. + * + * NOTE: This function should never be called from application code and, + * as a general rule unless you really know what you are doing, this + * function should not be called directly from operation system code either: + * Typically, the wrapper functions, enter_critical_section() and + * leave_critical section(), are probably what you really want. + */ + +/* Get/set the MODA register, here is the irq related bits: + * Bit [4] Interrupt enable (RW) + * Bit [5] Interrupt mask for INT0 (RW) + * Bit [6] Interrupt mask for INT1 (RW) + * Bit [7] Interrupt mask for INT2 (RW) + * Bit [8] Interrupt mask for INT3 (RW) + * Bit [9] Interrupt mask for INT4 (RW) + * Bit [10] Interrupt mask for VINT (RW) + * Bit [11] Interrupt pending for INT0 (RO) + * Bit [12] Interrupt pending for INT1 (RO) + * Bit [13] Interrupt pending for INT2 (RO) + * Bit [14] Interrupt pending for INT3 (RO) + * Bit [15] Interrupt pending for INT4 (RO) + * Bit [16] Interrupt pending for INTV (RO) + * All writable bits are clear by hardware during reset. + * + * We manipulate the individual mask bits instead of global enable bit since: + * 1.Global IE not only mask INTX request but also mask TRAPX instruction. + * 2.Hardware always enable global IE after the interrupt return. + * Both behavior don't match the nuttx requirement. + */ + +static inline uint32_t getmoda(void) +{ + uint32_t moda; + __asm__ __volatile__("mov moda.ui, %0.ui\nnop #0x02" : "=r"(moda)); + return moda; +} + +static inline void setmoda(uint32_t moda) +{ + __asm__ __volatile__("nop #0x04\nnop\nmovp %0.ui, moda.ui" : : "r"(moda)); +} + +static inline void up_irq_disable(void) +{ + setmoda(REG_MODA_DISABLE); +} + +static inline irqstate_t up_irq_save(void) +{ + irqstate_t flags = getmoda(); + up_irq_disable(); + return flags; +} + +static inline void up_irq_enable(void) +{ + setmoda(REG_MODA_ENABLE); +} + +static inline void up_irq_restore(irqstate_t flags) +{ + setmoda(flags); +} + +/**************************************************************************** + * Name: up_getsp + ****************************************************************************/ + +static inline uint32_t up_getsp(void) +{ + uint32_t sp; + __asm__ __volatile__("mov sp.ui, %0.ui" : "=r"(sp)); + return sp; +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_CEVA_INCLUDE_XM6_IRQ_H */ diff --git a/arch/ceva/include/xm6/math.h b/arch/ceva/include/xm6/math.h new file mode 100644 index 0000000000..db105c42ec --- /dev/null +++ b/arch/ceva/include/xm6/math.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * arch/ceva/include/xm6/math.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XM6_MATH_H +#define __ARCH_CEVA_INCLUDE_XM6_MATH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include_next + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +float roundf(float x); +double round (double x); +long double roundl(long double x); + +double gamma(double x); +double lgamma(double x); + +float log2f (float x); +double log2 (double x); +long double log2l (long double x); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_CEVA_INCLUDE_XM6_MATH_H */ diff --git a/arch/ceva/include/xm6/reg.h b/arch/ceva/include/xm6/reg.h new file mode 100644 index 0000000000..5c34b967f4 --- /dev/null +++ b/arch/ceva/include/xm6/reg.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * arch/ceva/include/xm6/reg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XM6_REG_H +#define __ARCH_CEVA_INCLUDE_XM6_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IRQ Stack Frame Format: */ + +/* The following registers are stored by the interrupt handling + * logic. + */ + +#define REG_SP 0 +#define REG_MODI 1 +#define REG_MODG 2 +#define REG_MODE 3 +#define REG_MODD 4 +#define REG_MODC 5 +#define REG_MODA 6 +#define REG_R56 7 +#define REG_R57 8 +#define REG_R58 9 +#define REG_R59 10 +#define REG_R60 11 +#define REG_R61 12 +#define REG_R62 13 +#define REG_R63 14 +#define REG_R48 15 +#define REG_R49 16 +#define REG_R50 17 +#define REG_R51 18 +#define REG_R52 19 +#define REG_R53 20 +#define REG_R54 21 +#define REG_R55 22 +#define REG_R40 23 +#define REG_R41 24 +#define REG_R42 25 +#define REG_R43 26 +#define REG_R44 27 +#define REG_R45 28 +#define REG_R46 29 +#define REG_R47 30 +#define REG_R32 31 +#define REG_R33 32 +#define REG_R34 33 +#define REG_R35 34 +#define REG_R36 35 +#define REG_R37 36 +#define REG_R38 37 +#define REG_R39 38 +#define REG_R24 39 +#define REG_R25 40 +#define REG_R26 41 +#define REG_R27 42 +#define REG_R28 43 +#define REG_R29 44 +#define REG_R30 45 +#define REG_R31 46 +#define REG_R16 47 +#define REG_R17 48 +#define REG_R18 49 +#define REG_R19 50 +#define REG_R20 51 +#define REG_R21 52 +#define REG_R22 53 +#define REG_R23 54 +#define REG_R8 55 +#define REG_R9 56 +#define REG_R10 57 +#define REG_R11 58 +#define REG_R12 59 +#define REG_R13 60 +#define REG_R14 61 +#define REG_R15 62 +#define REG_R0 63 +#define REG_R1 64 +#define REG_R2 65 +#define REG_R3 66 +#define REG_R4 67 +#define REG_R5 68 +#define REG_R6 69 +#define REG_R7 70 +#define REG_RETREGN 71 +#define REG_RETREG 72 +#define REG_RETREG_TEMP 73 +#define REG_RETREGI 74 +#define REG_MODVL0 75 +#define REG_MODVL1 76 +#define REG_MODVLL 77 +#define REG_MODVFP 78 + +/* The total number of registers is saved on the stack */ + +#define XCPTCONTEXT_REGS 79 +#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ARCH_CEVA_INCLUDE_XM6_REG_H */ diff --git a/arch/ceva/include/xm6/spinlock.h b/arch/ceva/include/xm6/spinlock.h new file mode 100644 index 0000000000..ed48770643 --- /dev/null +++ b/arch/ceva/include/xm6/spinlock.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * arch/ceva/include/xm6/spinlock.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_INCLUDE_XM6_SPINLOCK_H +#define __ARCH_CEVA_INCLUDE_XM6_SPINLOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SP_SECTION __attribute__ ((section(".DSECT spinlock"))) + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +static inline void up_dsb(void) +{ + /* MSS_BARRIER(0x638): + * Bit [7] Internal Barrier Activation + */ +#define MSS_BARRIER 0x638 + + uint32_t barrier = 0x80; + + __asm__ __volatile__ + ( + "out {cpm} %0.ui, (%1.ui).ui" + : : "r"(barrier), "r"(MSS_BARRIER) + ); + + do + { + __asm__ __volatile__ + ( + "in {cpm} (%1.ui).ui, %0.ui\n" + "nop #0x04\nnop #0x02" + : "=r"(barrier) + : "r"(MSS_BARRIER) + ); + + /* Wait unitl the barrier operation complete */ + } + while ((barrier & 0x80) != 0); +#undef MSS_BARRIER +} + +static inline void up_dmb(void) +{ + up_dsb(); /* use dsb instead since dmb doesn't exist on xm6 */ +} + +/**************************************************************************** + * Name: up_testset + * + * Description: + * Perform an atomic test and set operation on the provided spinlock. + * + * This function must be provided via the architecture-specific logoic. + * + * Input Parameters: + * lock - The address of spinlock object. + * + * Returned Value: + * The spinlock is always locked upon return. The value of previous value + * of the spinlock variable is returned, either SP_LOCKED if the spinlock + * as previously locked (meaning that the test-and-set operation failed to + * obtain the lock) or SP_UNLOCKED if the spinlock was previously unlocked + * (meaning that we successfully obtained the lock) + * + ****************************************************************************/ + +static inline spinlock_t up_testset(volatile FAR spinlock_t *lock) +{ + irqstate_t flags; + spinlock_t old; + + /* Disable the interrupt */ + + flags = up_irq_save(); + + while (1) + { + uint32_t modc = 0; + + /* Issue exclusive read */ + + __asm__ __volatile__ + ( + "nop\n" + "LS0.ld (%1.ui).ui, %0.ui || monitor {on}\n" + "nop #0x02" + : "=r"(old) + : "r"(lock) + ); + + /* Is it already locked by other? */ + + if (old == SP_LOCKED) + { + break; /* Yes, exit */ + } + + /* Not yet, issue exclusive write */ + + __asm__ __volatile__ + ( + "LS1.st %2.ui, (%1.ui).ui || monitor {off}\n" + "mov modc.ui, %0.ui\n" + "nop" + : "=r"(modc) + : "r"(lock), "r"(SP_LOCKED) + : "memory" + ); + + /* Exclusive write success? */ + + if ((modc & 0x01) == 0) /* Bit[0] Monitor status */ + { + break; /* Yes, we are done */ + } + + /* Fail, let's try again */ + } + + /* Restore the interrupt */ + + up_irq_restore(flags); + + return old; +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_CEVA_INCLUDE_XM6_SPINLOCK_H */ diff --git a/arch/ceva/src/.gitignore b/arch/ceva/src/.gitignore new file mode 100644 index 0000000000..dfdfc93543 --- /dev/null +++ b/arch/ceva/src/.gitignore @@ -0,0 +1,5 @@ +/.depend +/Make.dep +/locked.r +/board +/chip diff --git a/arch/ceva/src/Makefile b/arch/ceva/src/Makefile new file mode 100644 index 0000000000..7014ea7301 --- /dev/null +++ b/arch/ceva/src/Makefile @@ -0,0 +1,216 @@ +############################################################################ +# arch/ceva/src/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +-include $(TOPDIR)/Make.defs +-include chip$(DELIM)Make.defs + +ifeq ($(CONFIG_ARCH_XC5),y) +ARCH_SUBDIR = xc5 +else ifeq ($(CONFIG_ARCH_XM6),y) +ARCH_SUBDIR = xm6 +endif + +CPPFLAGS += $(EXTRADEFINES) +CFLAGS += $(EXTRADEFINES) +CXXFLAGS += $(EXTRADEFINES) + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + ARCH_SRCDIR = $(TOPDIR)\arch\$(CONFIG_ARCH)\src + NUTTX = "$(OUTDIR)\nuttx$(EXEEXT)" + CFLAGS += -I$(ARCH_SRCDIR)\chip + CFLAGS += -I$(ARCH_SRCDIR)\common + CFLAGS += -I$(ARCH_SRCDIR)\$(ARCH_SUBDIR) + CFLAGS += -I$(ARCH_SRCDIR)\$(CONFIG_ARCH_CHIP) + CFLAGS += -I$(TOPDIR)\sched +else + ARCH_SRCDIR = $(TOPDIR)/arch/$(CONFIG_ARCH)/src +ifeq ($(WINTOOL),y) + NUTTX = "${shell cygpath -w $(OUTDIR)/nuttx$(EXEEXT)}" + CFLAGS += -I "${shell cygpath -w $(ARCH_SRCDIR)/chip}" + CFLAGS += -I "${shell cygpath -w $(ARCH_SRCDIR)/common}" + CFLAGS += -I "${shell cygpath -w $(ARCH_SRCDIR)/$(ARCH_SUBDIR)}" + CFLAGS += -I "${shell cygpath -w $(ARCH_SRCDIR)/$(CONFIG_ARCH_CHIP)}" + CFLAGS += -I "${shell cygpath -w $(TOPDIR)/sched}" + LDSCRIPT := ${shell cygpath -m $(LDSCRIPT)} +else + NUTTX = "$(OUTDIR)/nuttx$(EXEEXT)" + CFLAGS += -I$(ARCH_SRCDIR)/chip + CFLAGS += -I$(ARCH_SRCDIR)/common + CFLAGS += -I$(ARCH_SRCDIR)/$(ARCH_SUBDIR) + CFLAGS += -I$(ARCH_SRCDIR)/$(CONFIG_ARCH_CHIP) + CFLAGS += -I$(TOPDIR)/sched +endif +endif + +# The "head" object + +HEAD_OBJ = $(HEAD_ASRC:.S=$(OBJEXT)) +STARTUP_OBJS ?= $(HEAD_OBJ) + +# Flat build or kernel-mode objects + +ASRCS = $(CHIP_ASRCS) $(CMN_ASRCS) +AOBJS = $(ASRCS:.S=$(OBJEXT)) + +CSRCS = $(CHIP_CSRCS) $(CMN_CSRCS) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +# User-mode objects + +UASRCS = $(CHIP_UASRCS) $(CMN_UASRCS) +UAOBJS = $(UASRCS:.S=$(OBJEXT)) + +UCSRCS = $(CHIP_UCSRCS) $(CMN_UCSRCS) +UCOBJS = $(UCSRCS:.c=$(OBJEXT)) + +USRCS = $(UASRCS) $(UCSRCS) +UOBJS = $(UAOBJS) $(UCOBJS) + +KBIN = libkarch$(LIBEXT) +UBIN = libuarch$(LIBEXT) +BIN = libarch$(LIBEXT) + +EXTRA_LIBS ?= +EXTRA_LIBPATHS ?= +LINKLIBS ?= + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BOARDMAKE = $(if $(wildcard .\board\Makefile),y,) + LIBPATHS += -I "$(OUTDIR)\staging" +ifeq ($(BOARDMAKE),y) + LIBPATHS += -I "$(OUTDIR)\arch\$(CONFIG_ARCH)\src\board" +endif + +else + BOARDMAKE = $(if $(wildcard ./board/Makefile),y,) + +ifeq ($(WINTOOL),y) + LIBPATHS += -I "${shell cygpath -w "$(OUTDIR)/staging"}" +ifeq ($(BOARDMAKE),y) + LIBPATHS += -I "${shell cygpath -w "$(OUTDIR)/arch/$(CONFIG_ARCH)/src/board"}" +endif + +else + LIBPATHS += -I "$(OUTDIR)/staging" +ifeq ($(BOARDMAKE),y) + LIBPATHS += -I "$(OUTDIR)/arch/$(CONFIG_ARCH)/src/board" +endif +endif +endif + +LDLIBS = $(patsubst %, -lib %,$(LINKLIBS)) +ifeq ($(BOARDMAKE),y) + LDLIBS += -lib libboard.lib +endif + +VPATH += . +VPATH += chip +VPATH += common +VPATH += $(ARCH_SUBDIR) + +VPATH := $(patsubst %,:$(SRCDIR)$(DELIM)%,$(VPATH)) +ifeq ($(WINTOOL),y) +VPATH += :$(shell cygpath -m $(OUTDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)chip) +else +VPATH += :$(OUTDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)chip +endif + +all: $(HEAD_OBJ) $(BIN) + +.PHONY: board$(DELIM)libboard$(LIBEXT) + +$(sort $(AOBJS) $(UAOBJS) $(HEAD_OBJ)): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(sort $(COBJS) $(UCOBJS)): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +$(BIN) $(KBIN): $(OBJS) + $(call ARCHIVE, $@, $(OBJS)) + +$(UBIN): $(UOBJS) + $(call ARCHIVE, $@, $(UOBJS)) + +board$(DELIM)libboard$(LIBEXT): +ifeq ($(CONFIG_ARCH_XC5), y) + $(Q) if [ ! -L "$(CROSSDEV)/cevaxccc-xdrv" ]; then \ + ln -sf "$(CROSSDEV)/cevaxccc-drv" "$(CROSSDEV)/cevaxccc-xdrv";\ + fi +endif + $(Q) $(MAKE) -C board TOPDIR="$(TOPDIR)" libboard$(LIBEXT) EXTRADEFINES=$(EXTRADEFINES) + +nuttx$(EXEEXT): $(HEAD_OBJ) board$(DELIM)libboard$(LIBEXT) $(LDSCRIPT) + $(Q) echo "LD: nuttx" + $(Q) $(call PREPROCESS, $(LDSCRIPT), $(notdir $(LDSCRIPT))) + $(Q) $(LD) $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \ + -o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \ + $(LDLIBS) $(EXTRA_LIBS) $(LIBGCC) \ + -l $(OUTDIR)$(DELIM)nuttx.lin $(notdir $(LDSCRIPT)) + $(Q) $(DISASM) -o $(OUTDIR)$(DELIM)nuttx.lst $(NUTTX) + $(Q) $(OBJDUMP) $(NUTTX) > $(OUTDIR)$(DELIM)nuttx.dump + $(Q) $(OBJCOPY) -b $(OUTDIR)$(DELIM)nuttx -c -split $(NUTTX) + +# This is part of the top-level export target +# Note that there may not be a head object if layout is handled +# by the linker configuration. + +export_startup: board$(DELIM)libboard$(LIBEXT) $(STARTUP_OBJS) +ifneq ($(STARTUP_OBJS),) + $(Q) if [ -d "$(EXPORT_DIR)$(DELIM)startup" ]; then \ + cp -f $(STARTUP_OBJS) "$(EXPORT_DIR)$(DELIM)startup$(DELIM)."; \ + else \ + echo "$(EXPORT_DIR)$(DELIM)startup does not exist"; \ + exit 1; \ + fi +endif + +# Dependencies + +.depend: Makefile chip$(DELIM)Make.defs $(SRCS) +ifeq ($(BOARDMAKE),y) + $(Q) $(MAKE) -C board TOPDIR="$(TOPDIR)" depend +endif + $(Q) $(MKDEP) $(patsubst %,--dep-path %,$(subst :, ,$(VPATH))) \ + "$(CC)" -- $(CFLAGS) -- $^ >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: +ifeq ($(BOARDMAKE),y) + $(Q) $(MAKE) -C board TOPDIR="$(TOPDIR)" clean +endif + $(call DELFILE, $(notdir $(LDSCRIPT))) + $(call DELFILE, $(KBIN)) + $(call DELFILE, $(UBIN)) + $(call DELFILE, $(BIN)) + $(call CLEAN) + +distclean: clean +ifeq ($(BOARDMAKE),y) + $(Q) $(MAKE) -C board TOPDIR="$(TOPDIR)" distclean +endif + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/arch/ceva/src/common/mpu.h b/arch/ceva/src/common/mpu.h new file mode 100644 index 0000000000..9f54c3e21b --- /dev/null +++ b/arch/ceva/src/common/mpu.h @@ -0,0 +1,145 @@ +/**************************************************************************** + * arch/ceva/src/common/mpu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_COMMON_MPU_H +#define __ARCH_CEVA_SRC_COMMON_MPU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_ARCH_MPU + +/**************************************************************************** + * Name: mpu_control + * + * Description: + * Configure and enable (or disable) the MPU + * + ****************************************************************************/ + +void mpu_control(bool enable); + +/**************************************************************************** + * Name: mpu_user_code + * + * Description: + * Configure a region for user code + * + ****************************************************************************/ + +void mpu_user_code(const void *base, size_t size); + +/**************************************************************************** + * Name: mpu_priv_code + * + * Description: + * Configure a region for privileged code + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_code(const void *base, size_t size); + +/**************************************************************************** + * Name: mpu_user_data + * + * Description: + * Configure a region as user data + * + ****************************************************************************/ + +void mpu_user_data(void *base, size_t size); + +/**************************************************************************** + * Name: mpu_priv_data + * + * Description: + * Configure a region as privileged data + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_data(void *base, size_t size); + +/**************************************************************************** + * Name: mpu_peripheral + * + * Description: + * Configure a region as privileged peripheral address space + * + ****************************************************************************/ + +void mpu_peripheral(void *base, size_t size); + +/**************************************************************************** + * Name: mpu_stronglyordered + * + * Description: + * Configure a region for privileged, strongly ordered memory + * + ****************************************************************************/ + +void mpu_stronglyordered(void *base, size_t size); + +#else + +#define mpu_control(enable) +#define mpu_user_code(base, size) +#define mpu_priv_code(base, size) +#define mpu_user_data(base, size) +#define mpu_priv_data(base, size) +#define mpu_peripheral(base, size) +#define mpu_stronglyordered(base, size) + +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_CEVA_SRC_COMMON_MPU_H */ diff --git a/arch/ceva/src/common/svcall.h b/arch/ceva/src/common/svcall.h new file mode 100644 index 0000000000..f7301d36d3 --- /dev/null +++ b/arch/ceva/src/common/svcall.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * arch/ceva/src/common/svcall.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_COMMON_SVCALL_H +#define __ARCH_CEVA_SRC_COMMON_SVCALL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* This logic uses three system calls {0,1,2} for context switching and one + * for the syscall return. + * So a minimum of four syscall values must be reserved. + * If CONFIG_BUILD_PROTECTED is defined, then four more syscall values + * must be reserved. + */ + +#ifdef CONFIG_LIB_SYSCALL +# ifdef CONFIG_BUILD_PROTECTED +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 8" +# elif CONFIG_SYS_RESERVED != 8 +# error "CONFIG_SYS_RESERVED must have the value 8" +# endif +# else +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 4" +# elif CONFIG_SYS_RESERVED != 4 +# error "CONFIG_SYS_RESERVED must have the value 4" +# endif +# endif +#endif + +/* CEVA system calls ********************************************************/ + +/* SYS call 0: + * + * int up_saveusercontext(uint32_t *saveregs); + */ + +#define SYS_save_context 0x00 + +/* SYS call 1: + * + * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; + */ + +#define SYS_restore_context 0x01 + +/* SYS call 2: + * + * void up_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); + */ + +#define SYS_switch_context 0x02 + +#ifdef CONFIG_LIB_SYSCALL +/* SYS call 3: + * + * void up_syscall_return(void); + */ + +#define SYS_syscall_return 0x03 + +#ifdef CONFIG_BUILD_PROTECTED +/* SYS call 4: + * + * void up_task_start(main_t taskentry, int argc, FAR char *argv[]) + * noreturn_function; + */ + +#define SYS_task_start 0x04 + +/* SYS call 5: + * + * void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) + * noreturn_function + */ + +#define SYS_pthread_start 0x05 + +/* SYS call 6: + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * FAR siginfo_t *info, FAR void *ucontext); + */ + +#define SYS_signal_handler 0x06 + +/* SYS call 7: + * + * void signal_handler_return(void); + */ + +#define SYS_signal_handler_return 0x07 + +#endif /* CONFIG_BUILD_PROTECTED */ +#endif /* CONFIG_LIB_SYSCALL */ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#endif /* __ARCH_CEVA_SRC_COMMON_SVCALL_H */ diff --git a/arch/ceva/src/common/up_arch.h b/arch/ceva/src/common/up_arch.h new file mode 100644 index 0000000000..d904249235 --- /dev/null +++ b/arch/ceva/src/common/up_arch.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/ceva/src/common/up_arch.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ___ARCH_CEVA_SRC_COMMON_UP_ARCH_H +#define ___ARCH_CEVA_SRC_COMMON_UP_ARCH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +# define getreg8(a) (*(volatile uint8_t *)(a)) +# define putreg8(v,a) (*(volatile uint8_t *)(a) = (v)) +# define getreg16(a) (*(volatile uint16_t *)(a)) +# define putreg16(v,a) (*(volatile uint16_t *)(a) = (v)) +# define getreg32(a) (*(volatile uint32_t *)(a)) +# define putreg32(v,a) (*(volatile uint32_t *)(a) = (v)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Atomic modification of registers */ + +void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits); +void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits); +void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* ___ARCH_CEVA_SRC_COMMON_UP_ARCH_H */ diff --git a/arch/ceva/src/common/up_assert.c b/arch/ceva/src/common/up_assert.c new file mode 100644 index 0000000000..9067d9d9d7 --- /dev/null +++ b/arch/ceva/src/common/up_assert.c @@ -0,0 +1,372 @@ +/**************************************************************************** + * arch/ceva/src/common/up_assert.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "sched/sched.h" +#include "irq/irq.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* USB trace dumping */ + +#ifndef CONFIG_USBDEV_TRACE +# undef CONFIG_ARCH_USBDUMP +#endif + +#ifndef CONFIG_BOARD_RESET_ON_ASSERT +# define CONFIG_BOARD_RESET_ON_ASSERT 0 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_ARCH_STACKDUMP +static uint32_t s_last_regs[XCPTCONTEXT_REGS]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_stackdump + ****************************************************************************/ + +#ifdef CONFIG_ARCH_STACKDUMP +static void up_stackdump(uint32_t sp, uint32_t stack_base) +{ + uint32_t stack; + + for (stack = sp; stack < stack_base; stack += 8 * sizeof(uint32_t)) + { + uint32_t *ptr = (uint32_t *)stack; + _alert("%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + stack, ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5], ptr[6], ptr[7]); + } +} +#else +# define up_stackdump(sp, stack_base) +#endif + +/**************************************************************************** + * Name: up_taskdump + ****************************************************************************/ + +#ifdef CONFIG_STACK_COLORATION +static void up_taskdump(FAR struct tcb_s *tcb, FAR void *arg) +{ + /* Dump interesting properties of this task */ + +#if CONFIG_TASK_NAME_SIZE > 0 + _alert("%s: PID=%d Stack Used=%lu of %lu\n", + tcb->name, tcb->pid, up_check_tcbstack(tcb), + tcb->adj_stack_size); +#else + _alert("PID: %d Stack Used=%lu of %lu\n", + tcb->pid, up_check_tcbstack(tcb), + tcb->adj_stack_size); +#endif +} +#endif + +/**************************************************************************** + * Name: up_showtasks + ****************************************************************************/ + +#ifdef CONFIG_STACK_COLORATION +static inline void up_showtasks(void) +{ + /* Dump interesting properties of each task in the crash environment */ + + sched_foreach(up_taskdump, NULL); +} +#else +# define up_showtasks() +#endif + +/**************************************************************************** + * Name: up_registerdump + ****************************************************************************/ + +#ifdef CONFIG_ARCH_STACKDUMP +static inline void up_registerdump(void) +{ + volatile uint32_t *regs = CURRENT_REGS; + int rx; + + /* Are user registers available from interrupt processing? */ + + if (regs == NULL) + { + /* No.. capture user registers by hand */ + + up_saveusercontext(s_last_regs); + regs = s_last_regs; + } + + /* Dump the interrupt registers */ + + for (rx = 0; rx < XCPTCONTEXT_REGS; rx += 8) + { + _alert("R%03d: %08x %08x %08x %08x %08x %08x %08x %08x\n", + rx, regs[rx], regs[rx + 1], regs[rx + 2], regs[rx + 3], + regs[rx + 4], regs[rx + 5], regs[rx + 6], regs[rx + 7]); + } +} +#else +# define up_registerdump() +#endif + +/**************************************************************************** + * Name: assert_tracecallback + ****************************************************************************/ + +#ifdef CONFIG_ARCH_USBDUMP +static int usbtrace_syslog(FAR const char *fmt, ...) +{ + va_list ap; + int ret; + + /* Let nx_vsyslog do the real work */ + + va_start(ap, fmt); + ret = nx_vsyslog(LOG_EMERG, fmt, &ap); + va_end(ap); + return ret; +} + +static int assert_tracecallback(FAR struct usbtrace_s *trace, FAR void *arg) +{ + usbtrace_trprintf(usbtrace_syslog, trace->event, trace->value); + return 0; +} +#endif + +/**************************************************************************** + * Name: up_dumpstate + ****************************************************************************/ + +#ifdef CONFIG_ARCH_STACKDUMP +static void up_dumpstate(void) +{ + struct tcb_s *rtcb = running_task(); + uint32_t sp = up_getsp(); + uint32_t ustackbase; + uint32_t ustacksize; + uint32_t istackbase; + uint32_t istacksize; + + /* Dump the registers (if available) */ + + up_registerdump(); + + /* Get the limits on the user stack memory */ + + ustackbase = (uint32_t)rtcb->adj_stack_ptr; + ustacksize = rtcb->adj_stack_size; + + /* Get the limits on the interrupt stack memory */ + + istackbase = (uint32_t)&g_intstackbase; + istacksize = &g_intstackbase - &g_intstackalloc; + + /* Show interrupt stack info */ + + _alert("sp: %08x\n", sp); + _alert("IRQ stack:\n"); + _alert(" base: %08x\n", istackbase); + _alert(" size: %08x\n", istacksize); +#ifdef CONFIG_STACK_COLORATION + _alert(" used: %08x\n", up_check_intstack()); +#endif + + /* Does the current stack pointer lie within the interrupt + * stack? + */ + + if (sp <= istackbase && sp > istackbase - istacksize) + { + /* Yes.. dump the interrupt stack */ + + up_stackdump(sp, istackbase); + } + else if (CURRENT_REGS) + { + _alert("ERROR: Stack pointer is not within the interrupt stack\n"); + up_stackdump(istackbase - istacksize, istackbase); + } + + /* Extract the user stack pointer if we are in an interrupt handler. + * If we are not in an interrupt handler. Then sp is the user stack + * pointer (and the above range check should have failed). + */ + + if (CURRENT_REGS) + { + sp = (uint32_t)CURRENT_REGS; + } + + /* Show user stack info */ + + _alert("sp: %08x\n", sp); + _alert("User stack:\n"); + _alert(" base: %08x\n", ustackbase); + _alert(" size: %08x\n", ustacksize); +#ifdef CONFIG_STACK_COLORATION + _alert(" used: %08x\n", up_check_tcbstack(rtcb)); +#endif + + /* Dump the user stack if the stack pointer lies within the allocated user + * stack memory. + */ + + if (sp > ustackbase || sp <= ustackbase - ustacksize) + { + _alert("ERROR: Stack pointer is not within the allocated stack\n"); + up_stackdump(ustackbase - ustacksize, ustackbase); + } + else + { + up_stackdump(sp, ustackbase); + } + +#ifdef CONFIG_SMP + /* Show the CPU number */ + + _alert("CPU%d:\n", up_cpu_index()); +#endif + + /* Dump the state of all tasks (if available) */ + + up_showtasks(); + +#ifdef CONFIG_ARCH_USBDUMP + /* Dump USB trace data */ + + usbtrace_enumerate(assert_tracecallback, NULL); +#endif +} +#else +# define up_dumpstate() +#endif + +/**************************************************************************** + * Name: _up_assert + ****************************************************************************/ + +static void _up_assert(int errorcode) noreturn_function; +static void _up_assert(int errorcode) +{ + /* Flush any buffered SYSLOG data */ + + syslog_flush(); + + /* Are we in an interrupt handler or the idle task? */ + + if (CURRENT_REGS || running_task()->pid == 0) + { + up_irq_save(); + for (; ; ) + { +#ifdef CONFIG_SMP + /* Try (again) to stop activity on other CPUs */ + + spin_trylock(&g_cpu_irqlock); +#endif + +#if CONFIG_BOARD_RESET_ON_ASSERT >= 1 + board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE); +#endif + } + } + else + { +#if CONFIG_BOARD_RESET_ON_ASSERT >= 2 + board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE); +#endif + exit(errorcode); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_assert + ****************************************************************************/ + +void up_assert(const uint8_t *filename, int lineno) +{ +#if CONFIG_TASK_NAME_SIZE > 0 && defined(CONFIG_DEBUG_ALERT) + struct tcb_s *rtcb = running_task(); +#endif + + /* Flush any buffered SYSLOG data (prior to the assertion) */ + + syslog_flush(); + +#ifdef CONFIG_SMP +#if CONFIG_TASK_NAME_SIZE > 0 + _alert("Assertion failed CPU%d at file:%s line: %d task: %s\n", + up_cpu_index(), filename, lineno, rtcb->name); +#else + _alert("Assertion failed CPU%d at file:%s line: %d\n", + up_cpu_index(), filename, lineno); +#endif +#else +#if CONFIG_TASK_NAME_SIZE > 0 + _alert("Assertion failed at file:%s line: %d task: %s\n", + filename, lineno, rtcb->name); +#else + _alert("Assertion failed at file:%s line: %d\n", + filename, lineno); +#endif +#endif + + up_dumpstate(); + + /* Flush any buffered SYSLOG data (from the above) */ + + syslog_flush(); + +#ifdef CONFIG_BOARD_CRASHDUMP + board_crashdump(up_getsp(), running_task(), filename, lineno); +#endif + + _up_assert(EXIT_FAILURE); +} diff --git a/arch/ceva/src/common/up_blocktask.c b/arch/ceva/src/common/up_blocktask.c new file mode 100644 index 0000000000..9ceeb233ad --- /dev/null +++ b/arch/ceva/src/common/up_blocktask.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * arch/ceva/src/common/up_blocktask.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_block_task + * + * Description: + * The currently executing task at the head of + * the ready to run list must be stopped. Save its context + * and move it to the inactive list specified by task_state. + * + * Inputs: + * tcb: Refers to a task in the ready-to-run list (normally + * the task at the head of the list). It most be + * stopped, its context saved and moved into one of the + * waiting task lists. It it was the task at the head + * of the ready-to-run list, then a context to the new + * ready to run task must be performed. + * task_state: Specifies which waiting task list should be + * hold the blocked task TCB. + * + ****************************************************************************/ + +void up_block_task(struct tcb_s *tcb, tstate_t task_state) +{ + struct tcb_s *rtcb = this_task(); + bool switch_needed; + + /* Verify that the context switch can be performed */ + + DEBUGASSERT((tcb->task_state >= FIRST_READY_TO_RUN_STATE) && + (tcb->task_state <= LAST_READY_TO_RUN_STATE)); + + /* Remove the tcb task from the ready-to-run list. If we + * are blocking the task at the head of the task list (the + * most likely case), then a context switch to the next + * ready-to-run task is needed. In this case, it should + * also be true that rtcb == tcb. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Add the task to the specified blocked task list */ + + sched_addblocked(tcb, (tstate_t)task_state); + + /* If there are any pending tasks, then add them to the ready-to-run + * task list now + */ + + if (g_pendingtasks.head) + { + switch_needed |= sched_mergepending(); + } + + /* Now, perform the context switch if one is needed */ + + if (switch_needed) + { + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + rtcb->xcp.regs = CURRENT_REGS; + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Reset scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + CURRENT_REGS = rtcb->xcp.regs; + } + + /* No, then we will need to perform the user context switch */ + + else + { + struct tcb_s *nexttcb = this_task(); + + /* Reset scheduler parameters */ + + sched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + up_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } +} diff --git a/arch/ceva/src/common/up_board.c b/arch/ceva/src/common/up_board.c new file mode 100644 index 0000000000..0fadc62f42 --- /dev/null +++ b/arch/ceva/src/common/up_board.c @@ -0,0 +1,180 @@ +/**************************************************************************** + * arch/ceva/src/common/up_board.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_BOARD_LATE_INITIALIZE) && !defined(CONFIG_NSH_ARCHINIT) +# error CONFIG_BOARD_LATE_INITIALIZE or CONFIG_NSH_ARCHINIT is required for late initialization +#endif + +#if defined(CONFIG_BOARD_LATE_INITIALIZE) && defined(CONFIG_NSH_ARCHINIT) +# error CONFIG_BOARD_LATE_INITIALIZE and CONFIG_NSH_ARCHINIT can not be defined at the same time +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_initialize(). board_initialize() will be + * called immediately after up_intitialize() is called and just before the + * initial application is started. This additional initialization phase + * may be used, for example, to initialize board-specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + /* Perform the arch late initialization */ + + up_lateinitialize(); + + /* Perform the board late initialization */ + + board_lateinitialize(); +} +#endif /* CONFIG_BOARD_LATE_INITIALIZE */ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initalization logic and the + * matching application logic. The value cold be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_LIB_BOARDCTL +int board_app_initialize(uintptr_t arg) +{ +# ifdef CONFIG_NSH_ARCHINIT + /* Perform the arch late initialization */ + + up_lateinitialize(); + + /* Perform the board late initialization */ + + board_lateinitialize(); +# endif + + return 0; +} +#endif /* CONFIG_LIB_BOARDCTL */ + +/**************************************************************************** + * Name: board_app_finalinitialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command + * BOARDIOC_FINALINIT. + * + * Input Parameters: + * arg - The argument has no meaning. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARDCTL_FINALINIT +int board_app_finalinitialize(uintptr_t arg) +{ + /* Perform the arch final initialization */ + + up_finalinitialize(); + + /* Perform the board final initialization */ + + board_finalinitialize(); + + return 0; +} +#endif /* CONFIG_BOARDCTL_FINALINIT */ + +/**************************************************************************** + * Name: board_reset + * + * Description: + * Reset board. This function may or may not be supported by a + * particular board architecture. + * + * Input Parameters: + * status - Status information provided with the reset event. This + * meaning of this status information is board-specific. If not used by + * a board, the value zero may be provided in calls to board_reset. + * + * Returned Value: + * If this function returns, then it was not possible to power-off the + * board due to some constraints. The return value int this case is a + * board-specific reason for the failure to shutdown. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARDCTL_RESET +int board_reset(int status) +{ + while (1) + { + up_reset(status); + up_cpu_idle(); + } + + return 0; +} +#endif /* CONFIG_BOARDCTL_RESET */ diff --git a/arch/ceva/src/common/up_checkstack.c b/arch/ceva/src/common/up_checkstack.c new file mode 100644 index 0000000000..f565ec136c --- /dev/null +++ b/arch/ceva/src/common/up_checkstack.c @@ -0,0 +1,204 @@ +/**************************************************************************** + * arch/ceva/src/common/up_checkstack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +#ifdef CONFIG_STACK_COLORATION + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static size_t do_stackcheck(uintptr_t alloc, size_t size, bool int_stack); + +/**************************************************************************** + * Name: do_stackcheck + * + * Description: + * Determine (approximately) how much stack has been used be searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * alloc - Allocation base address of the stack + * size - The size of the stack in bytes + * + * Returned value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +static size_t do_stackcheck(uintptr_t alloc, size_t size, bool int_stack) +{ + uintptr_t start; + uintptr_t end; + FAR uint32_t *ptr; + size_t nwords; + size_t mark; + + if (size == 0) + { + return 0; + } + + /* Get aligned addresses of the top and bottom of the stack */ + +#ifdef CONFIG_TLS + if (!int_stack) + { + /* Skip over the TLS data structure at the bottom of the stack */ + + DEBUGASSERT(alloc & (B2C(TLS_STACK_ALIGN) - 1) == 0); + start = alloc + sizeof(struct tls_info_s); + } + else +#endif + { + DEBUGASSERT(alloc & (sizeof(uint32_t) - 1) == 0); + start = alloc; + } + + end = alloc + size; + + /* Get the adjusted size based on the top and bottom of the stack */ + + size = end - start; + nwords = size / sizeof(uint32_t); + + /* The CEVA uses a push-down stack: the stack grows toward lower addresses + * in memory. We need to start at the lowest address in the stack memory + * allocation and search to higher addresses. The first word we encounter + * that does not have the magic value is the high water mark. + */ + + for (ptr = (FAR uint32_t *)start, mark = nwords; + *ptr == STACK_COLOR && mark > 0; + ptr++, mark--); + + /* If the stack is completely used, then this might mean that the stack + * overflowed from above (meaning that the stack is too small), or may + * have been overwritten from below meaning that some other stack or data + * structure overflowed. + * + * If you see returned values saying that the entire stack is being used + * then enable the following logic to see it there are unused areas in the + * middle of the stack. + */ + +#if 0 + if (mark + 16 > nwords) + { + int i; + int j; + + ptr = (FAR uint32_t *)start; + for (i = 0; i < nwords; i += 64) + { + for (j = 0; j < 64; j++) + { + int ch; + if (*ptr++ == STACK_COLOR) + { + ch = '.'; + } + else + { + ch = 'X'; + } + + up_putc(ch); + } + + up_putc('\n'); + } + } +#endif + + /* Return our guess about how much stack space was used */ + + return mark * sizeof(uint32_t); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_check_stack and friends + * + * Description: + * Determine (approximately) how much stack has been used be searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * None + * + * Returned value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +size_t up_check_tcbstack(FAR struct tcb_s *tcb) +{ + return do_stackcheck((uintptr_t)tcb->stack_alloc_ptr, + tcb->adj_stack_size, false); +} + +ssize_t up_check_tcbstack_remain(FAR struct tcb_s *tcb) +{ + return tcb->adj_stack_size - up_check_tcbstack(tcb); +} + +size_t up_check_stack(void) +{ + return up_check_tcbstack(this_task()); +} + +ssize_t up_check_stack_remain(void) +{ + return up_check_tcbstack_remain(this_task()); +} + +size_t up_check_intstack(void) +{ + return do_stackcheck((uintptr_t)&g_intstackalloc, + &g_intstackbase - &g_intstackalloc, + true); +} + +size_t up_check_intstack_remain(void) +{ + return &g_intstackbase - &g_intstackalloc - up_check_intstack(); +} + +#endif /* CONFIG_STACK_COLORATION */ diff --git a/arch/ceva/src/common/up_createstack.c b/arch/ceva/src/common/up_createstack.c new file mode 100644 index 0000000000..2ffb7c4ebd --- /dev/null +++ b/arch/ceva/src/common/up_createstack.c @@ -0,0 +1,275 @@ +/**************************************************************************** + * arch/ceva/src/common/up_createstack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Macros + ****************************************************************************/ + +/* Configuration */ + +#undef HAVE_KERNEL_HEAP +#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \ + defined(CONFIG_MM_KERNEL_HEAP) +# define HAVE_KERNEL_HEAP 1 +#endif + +/* Stack alignment macros */ + +#define STACK_ALIGN_MASK (sizeof(uint32_t) - 1) +#define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_create_stack + * + * Description: + * Allocate a stack for a new thread and setup up stack-related information + * in the TCB. + * + * The following TCB fields must be initialized by this function: + * + * - adj_stack_size: Stack size after adjustment for hardware, processor, + * etc. This value is retained only for debug purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of + * the stack pointer. + * + * Inputs: + * - tcb: The TCB of new task + * - stack_size: The requested stack size. At least this much + * must be allocated. + * - ttype: The thread type. This may be one of following (defined in + * include/nuttx/sched.h): + * + * TCB_FLAG_TTYPE_TASK Normal user task + * TCB_FLAG_TTYPE_PTHREAD User pthread + * TCB_FLAG_TTYPE_KERNEL Kernel thread + * + * This thread type is normally available in the flags field of the TCB, + * however, there are certain contexts where the TCB may not be fully + * initialized when up_create_stack is called. + * + * If either CONFIG_BUILD_PROTECTED or CONFIG_BUILD_KERNEL are defined, + * then this thread type may affect how the stack is allocated. For + * example, kernel thread stacks should be allocated from protected + * kernel memory. Stacks for user tasks and threads must come from + * memory that is accessible to user code. + * + ****************************************************************************/ + +int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype) +{ + /* Conver the stack size unit from byte to char */ + + stack_size = B2C(stack_size); + +#ifdef CONFIG_TLS + /* Add the size of the TLS information structure */ + + stack_size += sizeof(struct tls_info_s); + + /* The allocated stack size must not exceed the maximum possible for the + * TLS feature. + */ + + DEBUGASSERT(stack_size <= B2C(TLS_MAXSTACK)); + if (stack_size >= B2C(TLS_MAXSTACK)) + { + stack_size = B2C(TLS_MAXSTACK); + } +#endif + + /* Is there already a stack allocated of a different size? Because of + * alignment issues, stack_size might erroneously appear to be of a + * different size. Fortunately, this is not a critical operation. + */ + + if (tcb->stack_alloc_ptr && tcb->adj_stack_size != stack_size) + { + /* Yes.. Release the old stack */ + + up_release_stack(tcb, ttype); + } + + /* Do we need to allocate a new stack? */ + + if (!tcb->stack_alloc_ptr) + { + /* Allocate the stack. If DEBUG is enabled (but not stack debug), + * then create a zeroed stack to make stack dumps easier to trace. + * If TLS is enabled, then we must allocate aligned stacks. + */ + +#ifdef CONFIG_TLS +#ifdef HAVE_KERNEL_HEAP + /* Use the kernel allocator if this is a kernel thread */ + + if (ttype == TCB_FLAG_TTYPE_KERNEL) + { + tcb->stack_alloc_ptr = mm_memalign( + KMM_HEAP(CONFIG_ARCH_KERNEL_STACK_HEAP), + B2C(TLS_STACK_ALIGN), stack_size); + } + else +#endif + { + /* Use the user-space allocator if this is a task or pthread */ + + tcb->stack_alloc_ptr = mm_memalign( + UMM_HEAP(CONFIG_ARCH_STACK_HEAP), + B2C(TLS_STACK_ALIGN), stack_size); + } + +#else /* CONFIG_TLS */ +#ifdef HAVE_KERNEL_HEAP + /* Use the kernel allocator if this is a kernel thread */ + + if (ttype == TCB_FLAG_TTYPE_KERNEL) + { + tcb->stack_alloc_ptr = mm_malloc( + KMM_HEAP(CONFIG_ARCH_KERNEL_STACK_HEAP), + stack_size); + } + else +#endif + { + /* Use the user-space allocator if this is a task or pthread */ + + tcb->stack_alloc_ptr = mm_malloc( + UMM_HEAP(CONFIG_ARCH_STACK_HEAP), + stack_size); + } +#endif /* CONFIG_TLS */ + +#ifdef CONFIG_DEBUG_FEATURES + /* Was the allocation successful? */ + + if (!tcb->stack_alloc_ptr) + { + serr("ERROR: Failed to allocate stack, size %d\n", stack_size); + } +#endif + } + + /* Did we successfully allocate a stack? */ + + if (tcb->stack_alloc_ptr) + { +#if defined(CONFIG_TLS) && defined(CONFIG_STACK_COLORATION) + FAR void *stack_base; +#endif + FAR void *top_of_stack; + size_t size_of_stack; + + /* The CEVA uses a push-down stack: the stack grows toward lower + * addresses in memory. The stack pointer register, points to + * the lowest, valid work address (the "top" of the stack). Items + * on the stack are referenced as positive word offsets from sp. + */ + + /* The CEVA stack must be aligned to 4-byte alignment. + * If necessary size_of_stack must be rounded down to the next + * boundary + */ + + size_of_stack = STACK_ALIGN_DOWN(stack_size); + top_of_stack = tcb->stack_alloc_ptr + size_of_stack; + + /* Save the adjusted stack values in the struct tcb_s */ + + tcb->adj_stack_ptr = top_of_stack; + tcb->adj_stack_size = size_of_stack; + +#ifdef CONFIG_TLS + /* Initialize the TLS data structure */ + + memset(tcb->stack_alloc_ptr, 0, sizeof(struct tls_info_s)); + +#ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ + + stack_base = tcb->stack_alloc_ptr + sizeof(struct tls_info_s); + stack_size = tcb->adj_stack_size - sizeof(struct tls_info_s); + up_stack_color(stack_base, stack_size); + +#endif /* CONFIG_STACK_COLORATION */ +#else /* CONFIG_TLS */ +#ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a + * recognizable value that we can use later to test for high + * water marks. + */ + + up_stack_color(tcb->stack_alloc_ptr, tcb->adj_stack_size); + +#endif /* CONFIG_STACK_COLORATION */ +#endif /* CONFIG_TLS */ + + return OK; + } + + return ERROR; +} + +/**************************************************************************** + * Name: up_stack_color + * + * Description: + * Write a well know value into the stack + * + ****************************************************************************/ + +#ifdef CONFIG_STACK_COLORATION +void up_stack_color(FAR void *stackbase, size_t nbytes) +{ + uint32_t *stkptr = stackbase; + size_t nwords = nbytes / sizeof(uint32_t); + + /* Set the entire stack to the coloration value */ + + while (nwords-- > 0) + { + *stkptr++ = STACK_COLOR; + } +} +#endif diff --git a/arch/ceva/src/common/up_doirq.c b/arch/ceva/src/common/up_doirq.c new file mode 100644 index 0000000000..101fe96b96 --- /dev/null +++ b/arch/ceva/src/common/up_doirq.c @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/ceva/src/common/up_doirq.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* g_current_regs[] holds a references to the current interrupt level + * register storage structure. If is non-NULL only during interrupt + * processing. Access to g_current_regs[] must be through the macro + * CURRENT_REGS for portability. + */ + +#ifdef CONFIG_SMP +uint32_t *volatile g_current_regs[CONFIG_SMP_NCPUS]; +#else +uint32_t *volatile g_current_regs[1]; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +uint32_t *up_doirq(int irq, uint32_t *regs) +{ + /* Is it the outermost interrupt? */ + + if (CURRENT_REGS != NULL) + { + /* No, simply deliver the IRQ because only the outermost nested + * interrupt can result in a context switch. + */ + + irq_dispatch(irq, regs); + } + else + { + /* Current regs non-zero indicates that we are processing an interrupt; + * CURRENT_REGS is also used to manage interrupt level context + * switches. + */ + + CURRENT_REGS = regs; + + /* Deliver the IRQ */ + + irq_dispatch(irq, regs); + + /* If a context switch occurred while processing the interrupt then + * CURRENT_REGS may have change value. If we return any value + * different from the input regs, then the lower level will know that + * a context switch occurred during interrupt processing. + */ + + regs = CURRENT_REGS; + + /* Restore the previous value of CURRENT_REGS. NULL would indicate + * that we are no longer in an interrupt handler. + * It will be non-NULL if we are returning from a nested interrupt. + */ + + CURRENT_REGS = NULL; + + if (regs != (uint32_t *)regs[REG_SP]) + { + /* We are returning with a pending context switch. This case is + * different because in this case, the register save structure + * does not lie on the stack but, rather within other storage. + * We'll have to copy some values to the stack. + */ + + memcpy((uint32_t *)regs[REG_SP], regs, XCPTCONTEXT_SIZE); + regs = (uint32_t *)regs[REG_SP]; + } + } + + return regs; +} diff --git a/arch/ceva/src/common/up_exit.c b/arch/ceva/src/common/up_exit.c new file mode 100644 index 0000000000..dcdfbe2877 --- /dev/null +++ b/arch/ceva/src/common/up_exit.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * arch/ceva/src/common/up_exit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "task/task.h" +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _exit + * + * Description: + * This function causes the currently executing task to cease + * to exist. This is a special case of task_delete() where the task to + * be deleted is the currently executing task. It is more complex because + * a context switch must be perform to the next ready to run task. + * + ****************************************************************************/ + +void _exit(int status) +{ + struct tcb_s *tcb = this_task(); + + /* Make sure that we are in a critical section with local interrupts. + * The IRQ state will be restored when the next task is started. + */ + + enter_critical_section(); + + sinfo("TCB=%p exiting\n", tcb); + + /* Update scheduler parameters */ + + sched_suspend_scheduler(tcb); + + /* Destroy the task at the head of the ready to run list. */ + + nxtask_exit(); + + /* Now, perform the context switch to the new ready-to-run task at the + * head of the list. + */ + + tcb = this_task(); + + /* Reset scheduler parameters */ + + sched_resume_scheduler(tcb); + + /* Then switch contexts */ + + up_fullcontextrestore(tcb->xcp.regs); +} diff --git a/arch/ceva/src/common/up_fullcontextrestore.c b/arch/ceva/src/common/up_fullcontextrestore.c new file mode 100644 index 0000000000..5cf2cb33c9 --- /dev/null +++ b/arch/ceva/src/common/up_fullcontextrestore.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * arch/ceva/src/common/up_fullcontextrestore.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "svcall.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_fullcontextrestore + * + * Description: + * Restore the current thread context. Full prototype is: + * + * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; + * + * Return: + * None + * + ****************************************************************************/ + +void up_fullcontextrestore(uint32_t *restoreregs) +{ + /* Let sys_call1() do all of the work */ + + sys_call1(SYS_restore_context, (uintptr_t)restoreregs); + while (1); /* Shut up the compiler warning */ +} diff --git a/arch/ceva/src/common/up_heap.c b/arch/ceva/src/common/up_heap.c new file mode 100644 index 0000000000..33588bb722 --- /dev/null +++ b/arch/ceva/src/common/up_heap.c @@ -0,0 +1,273 @@ +/**************************************************************************** + * arch/ceva/src/common/up_heap.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "mpu.h" +#include "up_arch.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_MM_KERNEL_HEAP +# define MM_DEF_HEAP &g_kmmheap +#else +# define MM_DEF_HEAP &g_mmheap +#endif + +#if CONFIG_ARCH_DEFAULT_HEAP == 0 +# define MM_HEAP1 MM_DEF_HEAP +#else +static struct mm_heap_s g_mmheap1; +# define MM_HEAP1 &g_mmheap1 +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 2 +# if CONFIG_ARCH_DEFAULT_HEAP == 1 +# define MM_HEAP2 MM_DEF_HEAP +# else +static struct mm_heap_s g_mmheap2; +# define MM_HEAP2 &g_mmheap2 +# endif +# define _END_BSS2 ((void *)&_ebss2) +# define _END_HEAP2 ((void *)&_eheap2) +#else +# define MM_HEAP2 NULL +# define _END_BSS2 NULL +# define _END_HEAP2 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 3 +# if CONFIG_ARCH_DEFAULT_HEAP == 2 +# define MM_HEAP3 MM_DEF_HEAP +# else +static struct mm_heap_s g_mmheap3; +# define MM_HEAP3 &g_mmheap3 +# endif +# define _END_BSS3 ((void *)&_ebss3) +# define _END_HEAP3 ((void *)&_eheap3) +#else +# define MM_HEAP3 NULL +# define _END_BSS3 NULL +# define _END_HEAP3 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 4 +# if CONFIG_ARCH_DEFAULT_HEAP == 3 +# define MM_HEAP4 MM_DEF_HEAP +# else +static struct mm_heap_s g_mmheap4; +# define MM_HEAP4 &g_mmheap4 +# endif +# define _END_BSS4 ((void *)&_ebss4) +# define _END_HEAP4 ((void *)&_eheap4) +#else +# define MM_HEAP4 NULL +# define _END_BSS4 NULL +# define _END_HEAP4 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 5 +# error CONFIG_ARCH_NR_MEMORY must between 1 to 4 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static void *const g_bssend[] = +{ + _START_HEAP, _END_BSS2, _END_BSS3, _END_BSS4, NULL, +}; + +static void *const g_heapend[] = +{ + _END_HEAP, _END_HEAP2, _END_HEAP3, _END_HEAP4, NULL, +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct mm_heap_s *const g_mm_heap[] = +{ + MM_HEAP1, MM_HEAP2, MM_HEAP3, MM_HEAP4, NULL, +}; + +/* g_idle_topstack: _sbss is the start of the BSS region as defined by the + * linker script. _ebss lies at the end of the BSS region. The idle task + * stack starts at the end of BSS and is of size CONFIG_IDLETHREAD_STACKSIZE. + * The IDLE thread is the thread that the system boots on and, eventually, + * becomes the IDLE, do nothing task that runs only when there is nothing + * else to run. The heap continues from there until the end of memory. + * g_idle_topstack is a read-only variable the provides this computed + * address. + */ + +void *g_idle_basestack = _END_BSS; +void *g_idle_topstack = _START_HEAP; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_allocate_heap + * + * Description: + * This function will be called to dynamically set aside the heap region. + * + * - For the normal "flat" build, this function returns the size of the + * single heap. + * - For the protected build (CONFIG_BUILD_PROTECTED=y) with both kernel- + * and user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function + * provides the size of the unprotected, user-space heap. + * + * The following memory map is assumed for the flat build: + * + * .data region. Size determined at link time. + * .bss region Size determined at link time. + * IDLE thread stack. Size determined by CONFIG_IDLETHREAD_STACKSIZE. + * Heap. Extends to the end of SRAM. + * + * The following memory map is assumed for the kernel build: + * + * Kernel .data region. Size determined at link time. + * Kernel .bss region Size determined at link time. + * Kernel IDLE stack. Size determined by CONFIG_IDLETHREAD_STACKSIZE. + * Kernel heap. Size determined by CONFIG_MM_KERNEL_HEAPSIZE. + * Padding for alignment + * User .data region. Size determined at link time. + * User .bss region Size determined at link time. + * User heap. Extends to the end of SRAM. + * + ****************************************************************************/ + +void up_allocate_heap(FAR void **heap_start, size_t *heap_size) +{ + int i; + +#ifdef CONFIG_BUILD_PROTECTED + struct mm_heap_s *const *heap = + (struct mm_heap_s *const *)USERSPACE->us_heap; + void *const *bssend = (void *const *)USERSPACE->us_bssend; + void *const *heapend = (void *const *)USERSPACE->us_heapend; + + for (i = 0; i < CONFIG_ARCH_NR_USER_MEMORY; i++) + { + size_t size = heapend[i] - bssend[i]; + if (size != 0) + { + mpu_user_data(bssend[i], size); + up_heap_color(bssend[i], size); + if (i == CONFIG_ARCH_USER_DEFAULT_HEAP) + { + /* Return the default user-space heap settings */ + + *heap_start = bssend[i]; + *heap_size = heapend[i] - bssend[i]; + } + else + { + /* Initialize the additional user-space heap */ + + mm_initialize(heap[i], bssend[i], size); + } + } + } +#else + for (i = 0; i < CONFIG_ARCH_NR_MEMORY; i++) + { + size_t size = g_heapend[i] - g_bssend[i]; + if (size != 0) + { + mpu_priv_data(g_bssend[i], size); + up_heap_color(g_bssend[i], size); + if (i == CONFIG_ARCH_DEFAULT_HEAP) + { + /* Return the default heap settings */ + + *heap_start = g_bssend[i]; + *heap_size = g_heapend[i] - g_bssend[i]; + } + else + { + /* Initialize the additional heap */ + + mm_initialize(g_mm_heap[i], g_bssend[i], size); + } + } + } +#endif +} + +/**************************************************************************** + * Name: up_allocate_kheap + * + * Description: + * For the kernel build (CONFIG_BUILD_PROTECTED/KERNEL=y) with both kernel- + * and user-space heaps (CONFIG_MM_KERNEL_HEAP=y), this function allocates + * the kernel-space heap. + * + ****************************************************************************/ + +#ifdef CONFIG_MM_KERNEL_HEAP +void up_allocate_kheap(FAR void **heap_start, size_t *heap_size) +{ + int i; + + for (i = 0; i < CONFIG_ARCH_NR_MEMORY; i++) + { + size_t size = g_heapend[i] - g_bssend[i]; + if (size != 0) + { + mpu_priv_data(g_bssend[i], size); + up_heap_color(g_bssend[i], size); + if (i == CONFIG_ARCH_DEFAULT_HEAP) + { + /* Return the default kernel-space heap settings */ + + *heap_start = g_bssend[i]; + *heap_size = g_heapend[i] - g_bssend[i]; + + DEBUGASSERT(*heap_size >= CONFIG_MM_KERNEL_HEAPSIZE); + } + else + { + /* Initialize the additional kernel-space heap */ + + mm_initialize(g_mm_heap[i], g_bssend[i], size); + } + } + } +} +#endif diff --git a/arch/ceva/src/common/up_idle.c b/arch/ceva/src/common/up_idle.c new file mode 100644 index 0000000000..da86dfc3b1 --- /dev/null +++ b/arch/ceva/src/common/up_idle.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * arch/ceva/src/common/up_idle.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idlepm + * + * Description: + * Perform IDLE state power management. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_idlepm(void) +{ + enum pm_state_e newstate; + + /* Decide, which power saving level can be obtained */ + + newstate = pm_checkstate(PM_IDLE_DOMAIN); + + /* Then force the global state change */ + + pm_changestate(PM_IDLE_DOMAIN, newstate); + + /* The change may fail, let's get the final state from power manager */ + + newstate = pm_querystate(PM_IDLE_DOMAIN); + +#ifdef CONFIG_PM_KEEPBUSY + /* Check whether need keep CPU busy */ + + if (pm_keepbusy(PM_IDLE_DOMAIN, newstate)) + { + return; + } +#endif + + /* MCU-specific power management logic */ + + switch (newstate) + { + case PM_NORMAL: + up_cpu_doze(); + break; + + case PM_IDLE: + up_cpu_idle(); + break; + + case PM_STANDBY: + up_cpu_standby(); + break; + + case PM_SLEEP: + up_cpu_sleep(); + break; + + default: + break; + } +} +#else +# define up_idlepm() up_cpu_idle() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idle + * + * Description: + * up_idle() is the logic that will be executed + * when their is no other ready-to-run task. This is processor + * idle time and will continue until some interrupt occurs to + * cause a context switch from the idle task. + * + * Processing in this state may be processor-specific. e.g., + * this is where power management operations might be performed. + * + ****************************************************************************/ + +void up_idle(void) +{ + irqstate_t flags; + + flags = up_irq_save(); + sched_lock(); + + /* Perform IDLE mode power management */ + + up_idlepm(); + + /* Quit lower power mode, restore to PM_NORMAL */ + + up_cpu_normal(); + pm_changestate(PM_IDLE_DOMAIN, PM_RESTORE); + + sched_unlock(); + up_irq_restore(flags); +} + +/**************************************************************************** + * Power callback default implementation + ****************************************************************************/ + +void weak_function up_cpu_normal(void) +{ +} + +/**************************************************************************** + * Name: up_pminitialize + * + * Description: + * This function is called by MCU-specific logic at power-on reset in + * order to provide one-time initialization the power management subsystem. + * This function must be called *very* early in the initialization sequence + * *before* any other device drivers are initialized (since they may + * attempt to register with the power management subsystem). + * + * Input parameters: + * None. + * + * Returned value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +void up_pminitialize(void) +{ + /* Then initialize the power management subsystem proper */ + + pm_initialize(); +} +#endif diff --git a/arch/ceva/src/common/up_initialize.c b/arch/ceva/src/common/up_initialize.c new file mode 100644 index 0000000000..4f1fa97de7 --- /dev/null +++ b/arch/ceva/src/common/up_initialize.c @@ -0,0 +1,232 @@ +/**************************************************************************** + * arch/ceva/src/common/up_initialize.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "up_arch.h" +#include "up_internal.h" +#include "chip.h" + +#include "sched/sched.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_color_intstack + * + * Description: + * Set the interrupt stack to a value so that later we can determine how + * much stack space was used by interrupt handling logic + * + ****************************************************************************/ + +static inline void up_color_intstack(void) +{ + uint32_t *ptr = (uint32_t *)&g_intstackalloc; + ssize_t size; + + for (size = &g_intstackbase - &g_intstackalloc; + size > 0; + size -= sizeof(uint32_t)) + { + *ptr++ = INTSTACK_COLOR; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_initialize + * + * Description: + * up_initialize will be called once during OS initialization after the + * basic OS services have been initialized. The architecture specific + * details of initializing the OS will be handled here. Such things as + * setting up interrupt service routines, starting the clock, and + * registering device drivers are some of the things that are different + * for each processor and hardware platform. + * + * up_initialize is called after the OS initialized but before the user + * initialization logic has been started and before the libraries have + * been initialized. OS services and driver services are available. + * + ****************************************************************************/ + +void up_initialize(void) +{ + struct tcb_s *idle; + + /* Initialize global variables */ + + CURRENT_REGS = NULL; + + /* Initialize the idle task stack info */ + + idle = this_task(); /* It should be idle task */ + idle->stack_alloc_ptr = g_idle_basestack; + idle->adj_stack_ptr = g_idle_topstack; + idle->adj_stack_size = g_idle_topstack - g_idle_basestack; + + /* Colorize the interrupt stack */ + + up_color_intstack(); + + /* Add any extra memory fragments to the memory manager */ + + up_addregion(); + +#ifdef CONFIG_PM + /* Initialize the power management subsystem. This MCU-specific function + * must be called *very* early in the initialization sequence *before* any + * other device drivers are initialized (since they may attempt to register + * with the power management subsystem). + */ + + up_pminitialize(); +#endif + +#ifdef CONFIG_ARCH_DMA + /* Initialize the DMA subsystem if the weak function up_dma_initialize has + * been brought into the build + */ + + up_dma_initialize(); +#endif + + /* Register devices */ + +#if defined(CONFIG_DEV_NULL) + devnull_register(); /* Standard /dev/null */ +#endif + +#if defined(CONFIG_DEV_RANDOM) + devrandom_register(); /* Standard /dev/random */ +#endif + +#if defined(CONFIG_DEV_URANDOM) + devurandom_register(); /* Standard /dev/urandom */ +#endif + +#if defined(CONFIG_DEV_ZERO) + devzero_register(); /* Standard /dev/zero */ +#endif + +#if defined(CONFIG_DEV_LOOP) + loop_register(); /* Standard /dev/loop */ +#endif + +#if defined(CONFIG_SCHED_INSTRUMENTATION_BUFFER) && \ + defined(CONFIG_DRIVER_NOTE) + note_register(); /* Non-standard /dev/note */ +#endif + + /* Initialize the serial device driver */ + +#ifdef USE_SERIALDRIVER + up_serialinit(); +#endif + +#ifdef CONFIG_RPMSG_UART + rpmsg_serialinit(); +#endif + + /* Initialize the console device driver (if it is other than the standard + * serial driver). + */ + +#if defined (CONFIG_ARM_LWL_CONSOLE) + lwlconsole_init(); +#elif defined(CONFIG_CONSOLE_SYSLOG) + syslog_console_init(); +#endif + +#ifdef CONFIG_PSEUDOTERM_SUSV1 + /* Register the master pseudo-terminal multiplexor device */ + + ptmx_register(); +#endif + +#if defined(CONFIG_CRYPTO) + /* Initialize the HW crypto and /dev/crypto */ + + up_cryptoinitialize(); +#endif + +#ifdef CONFIG_CRYPTO_CRYPTODEV + devcrypto_register(); +#endif + +#ifndef CONFIG_NETDEV_LATEINIT + /* Initialize the network */ + + up_netinitialize(); +#endif + +#ifdef CONFIG_NET_LOOPBACK + /* Initialize the local loopback device */ + + localhost_initialize(); +#endif + +#ifdef CONFIG_NET_TUN + /* Initialize the TUN device */ + + tun_initialize(); +#endif + +#ifdef CONFIG_NETDEV_TELNET + /* Initialize the Telnet session factory */ + + telnet_initialize(); +#endif + +#if defined(CONFIG_USBDEV) || defined(CONFIG_USBHOST) + /* Initialize USB -- device and/or host */ + + up_usbinitialize(); +#endif +} diff --git a/arch/ceva/src/common/up_internal.h b/arch/ceva/src/common/up_internal.h new file mode 100644 index 0000000000..b4efc8baaf --- /dev/null +++ b/arch/ceva/src/common/up_internal.h @@ -0,0 +1,352 @@ +/**************************************************************************** + * arch/ceva/src/common/up_internal.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_COMMON_UP_INTERNAL_H +#define __ARCH_CEVA_SRC_COMMON_UP_INTERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determine which (if any) console driver to use. If a console is enabled + * and no other console device is specified, then a serial console is + * assumed. + */ + +#if !defined(CONFIG_DEV_CONSOLE) || CONFIG_NFILE_DESCRIPTORS == 0 +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT +# undef CONFIG_DEV_LOWCONSOLE +# undef CONFIG_RAMLOG_CONSOLE +#else +# if defined(CONFIG_RAMLOG_CONSOLE) +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT +# undef CONFIG_DEV_LOWCONSOLE +# elif defined(CONFIG_DEV_LOWCONSOLE) +# undef USE_SERIALDRIVER +# undef USE_EARLYSERIALINIT +# else +# define USE_SERIALDRIVER 1 +# define USE_EARLYSERIALINIT 1 +# endif +#endif + +/* If some other device is used as the console, then the serial driver may + * still be needed. Let's assume that if the upper half serial driver is + * built, then the lower half will also be needed. There is no need for + * the early serial initialization in this case. + */ + +#if !defined(USE_SERIALDRIVER) && defined(CONFIG_STANDARD_SERIAL) +# define USE_SERIALDRIVER 1 +#endif + +/* Linker defined section addresses */ + +#define _START_TEXT ((const void *)&_stext) +#define _END_TEXT ((const void *)&_etext) +#define _START_BSS ((void *)&_sbss) +#define _END_BSS ((void *)&_ebss) +#define _DATA_INIT ((const void *)&_eronly) +#define _START_DATA ((void *)&_sdata) +#define _END_DATA ((void *)&_edata) +#define _START_HEAP ((void *)&_ebss + B2C(CONFIG_IDLETHREAD_STACKSIZE)) +#define _END_HEAP ((void *)&_eheap) +#define _END_MEM ((void *)~0) + +/* This is the value used to mark the stack for subsequent stack monitoring + * logic. + */ + +#define STACK_COLOR 0xdeadbeef +#define INTSTACK_COLOR 0xdeadbeef +#define HEAP_COLOR 'h' + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* g_current_regs[] holds a references to the current interrupt level + * register storage structure. If is non-NULL only during interrupt + * processing. Access to g_current_regs[] must be through the macro + * CURRENT_REGS for portability. + */ + +#ifdef CONFIG_SMP +/* For the case of architectures with multiple CPUs, then there must be one + * such value for each processor that can receive an interrupt. + */ + +int up_cpu_index(void); /* See include/nuttx/arch.h */ + +EXTERN uint32_t *volatile g_current_regs[CONFIG_SMP_NCPUS]; +# define CURRENT_REGS (g_current_regs[up_cpu_index()]) + +#else + +EXTERN uint32_t *volatile g_current_regs[1]; +# define CURRENT_REGS (g_current_regs[0]) + +#endif + +/* This is the beginning of heap as provided from up_head.S. + * This is the first address in DRAM after the loaded + * program+bss+idle stack. The end of the heap is + * CONFIG_RAM_END + */ + +EXTERN void *g_idle_basestack; +EXTERN void *g_idle_topstack; + +/* Address of the interrupt stack pointer */ + +EXTERN char g_intstackalloc; /* Allocated stack base */ +EXTERN char g_intstackbase; /* Initial top of interrupt stack */ + +/* These 'addresses' of these values are setup by the linker script. + * They are not actual char storage locations! They are only used + * meaningfully in the following way: + * + * - The linker script defines, for example, the symbol _sdata. + * - The declareion extern char _sdata; makes C happy. C will believe + * that the value _sdata is the address of a char variable _data (it is + * not!). + * - We can recover the linker value then by simply taking the address of + * of _data. like: char *pdata = &_sdata; + */ + +/* Start of .text */ + +EXTERN const char _stext; +EXTERN const char _stext2; +EXTERN const char _stext3; +EXTERN const char _stext4; + +/* End+1 of .text */ + +EXTERN const char _etext; +EXTERN const char _etext2; +EXTERN const char _etext3; +EXTERN const char _etext4; + +/* End+1 of read only section (.text + .rodata) */ + +EXTERN const char _eronly; +EXTERN const char _eronly2; +EXTERN const char _eronly3; +EXTERN const char _eronly4; + +/* Start of .data */ + +EXTERN char _sdata; +EXTERN char _sdata2; +EXTERN char _sdata3; +EXTERN char _sdata4; + +/* End+1 of .data */ + +EXTERN char _edata; +EXTERN char _edata2; +EXTERN char _edata3; +EXTERN char _edata4; + +/* Start of .bss */ + +EXTERN char _sbss; +EXTERN char _sbss2; +EXTERN char _sbss3; +EXTERN char _sbss4; + +/* End+1 of .bss */ + +EXTERN char _ebss; +EXTERN char _ebss2; +EXTERN char _ebss3; +EXTERN char _ebss4; + +/* End+1 of the memory */ + +EXTERN char _eheap; +EXTERN char _eheap2; +EXTERN char _eheap3; +EXTERN char _eheap4; + +#endif /* __ASSEMBLY__ */ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/* Context switching */ + +int up_saveusercontext(uint32_t *saveregs); +void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; +void up_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); + +/* Signal handling **********************************************************/ + +void up_sigdeliver(void); + +/* Arch specific ************************************************************/ + +void up_earlyinitialize(void); +void up_lateinitialize(void); +void up_finalinitialize(void); + +/* Power management *********************************************************/ + +#ifdef CONFIG_PM +void up_pminitialize(void); +#else +# define up_pminitialize() +#endif + +void up_reset(void); + +void up_cpu_doze(void); +void up_cpu_idle(void); +void up_cpu_standby(void); +void up_cpu_sleep(void); +void up_cpu_normal(void); + +/* Interrupt handling *******************************************************/ + +void up_irqinitialize(void); + +/* Interrupt acknowledge and dispatch */ + +uint32_t *up_doirq(int irq, uint32_t *regs); + +/* Exception Handlers */ + +int up_svcall(int irq, FAR void *context, FAR void *arg); +int up_hardfault(int irq, FAR void *context, FAR void *arg); + +void up_svcall_handler(void); + +/* System timer *************************************************************/ + +void up_timer_initialize(void); + +/* Low level serial output **************************************************/ + +#ifdef USE_SERIALDRIVER +void up_serialinit(void); +#else +# define up_serialinit() +#endif + +#ifdef USE_EARLYSERIALINIT +void up_earlyserialinit(void); +#else +# define up_earlyserialinit() +#endif + +#ifdef CONFIG_RPMSG_UART +void rpmsg_serialinit(void); +#else +# define rpmsg_serialinit() +#endif + +/* Defined in drivers/lowconsole.c */ + +#ifdef CONFIG_DEV_LOWCONSOLE +void lowconsole_init(void); +#else +# define lowconsole_init() +#endif + +/* DMA **********************************************************************/ + +#ifdef CONFIG_ARCH_DMA +void up_dma_initialize(void); +#endif + +/* Memory management ********************************************************/ + +#if CONFIG_MM_REGIONS > 1 +void up_addregion(void); +#else +# define up_addregion() +#endif + +/* Watchdog timer ***********************************************************/ + +void up_wdtinit(void); + +/* Networking ***************************************************************/ + +#if defined(CONFIG_NET) && !defined(CONFIG_NETDEV_LATEINIT) +void up_netinitialize(void); +#else +# define up_netinitialize() +#endif + +/* USB **********************************************************************/ + +#ifdef CONFIG_USBDEV +void up_usbinitialize(void); +void up_usbuninitialize(void); +#else +# define up_usbinitialize() +# define up_usbuninitialize() +#endif + +/* Debug ********************************************************************/ +#ifdef CONFIG_HEAP_COLORATION +# define up_heap_color(start, size) memset(start, HEAP_COLOR, size) +#else +# define up_heap_color(start, size) +#endif + +#ifdef CONFIG_STACK_COLORATION +void up_stack_color(FAR void *stackbase, size_t nbytes); +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_CEVA_SRC_COMMON_UP_INTERNAL_H */ diff --git a/arch/ceva/src/common/up_interruptcontext.c b/arch/ceva/src/common/up_interruptcontext.c new file mode 100644 index 0000000000..0817df6d6a --- /dev/null +++ b/arch/ceva/src/common/up_interruptcontext.c @@ -0,0 +1,45 @@ +/**************************************************************************** + * arch/ceva/src/common/up_interruptcontext.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_interrupt_context + * + * Description: Return true is we are currently executing in + * the interrupt handler context. + ****************************************************************************/ + +bool up_interrupt_context(void) +{ + return CURRENT_REGS != NULL; +} diff --git a/arch/ceva/src/common/up_modifyreg16.c b/arch/ceva/src/common/up_modifyreg16.c new file mode 100644 index 0000000000..69d7fd854e --- /dev/null +++ b/arch/ceva/src/common/up_modifyreg16.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * arch/ceva/src/common/up_modifyreg16.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "up_arch.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg16 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits) +{ + irqstate_t flags; + uint16_t regval; + + flags = spin_lock_irqsave(); + regval = getreg16(addr); + regval &= ~clearbits; + regval |= setbits; + putreg16(regval, addr); + spin_unlock_irqrestore(flags); +} diff --git a/arch/ceva/src/common/up_modifyreg32.c b/arch/ceva/src/common/up_modifyreg32.c new file mode 100644 index 0000000000..f07acc2c16 --- /dev/null +++ b/arch/ceva/src/common/up_modifyreg32.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * arch/ceva/src/common/up_modifyreg32.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "up_arch.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg32 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits) +{ + irqstate_t flags; + uint32_t regval; + + flags = spin_lock_irqsave(); + regval = getreg32(addr); + regval &= ~clearbits; + regval |= setbits; + putreg32(regval, addr); + spin_unlock_irqrestore(flags); +} diff --git a/arch/ceva/src/common/up_modifyreg8.c b/arch/ceva/src/common/up_modifyreg8.c new file mode 100644 index 0000000000..ba5aaee9f0 --- /dev/null +++ b/arch/ceva/src/common/up_modifyreg8.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * arch/ceva/src/common/up_modifyreg8.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "up_arch.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg8 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits) +{ + irqstate_t flags; + uint8_t regval; + + flags = spin_lock_irqsave(); + regval = getreg8(addr); + regval &= ~clearbits; + regval |= setbits; + putreg8(regval, addr); + spin_unlock_irqrestore(flags); +} diff --git a/arch/ceva/src/common/up_pthread_start.c b/arch/ceva/src/common/up_pthread_start.c new file mode 100644 index 0000000000..d05c31e2d4 --- /dev/null +++ b/arch/ceva/src/common/up_pthread_start.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * arch/ceva/src/common/up_pthread_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "svcall.h" + +#if ((defined(CONFIG_BUILD_PROTECTED) && defined(__KERNEL__)) || \ + defined(CONFIG_BUILD_KERNEL)) && !defined(CONFIG_DISABLE_PTHREAD) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_pthread_start + * + * Description: + * In this kernel mode build, this function will be called to execute a + * pthread in user-space. When the pthread is first started, a kernel-mode + * stub will first run to perform some housekeeping functions. This + * kernel-mode stub will then be called transfer control to the user-mode + * pthread. + * + * Normally the a user-mode start-up stub will also execute before the + * pthread actually starts. See libc/pthread/pthread_startup.c + * + * Input Parameters: + * entrypt - The user-space address of the pthread entry point + * arg - Standard argument for the pthread entry point + * + * Returned Value: + * This function should not return. It should call the user-mode start-up + * stub and that stub should call pthread_exit if/when the user pthread + * terminates. + * + ****************************************************************************/ + +void up_pthread_start(pthread_startroutine_t entrypt, pthread_addr_t arg) +{ + /* Let sys_call2() do all of the work */ + + sys_call2(SYS_pthread_start, (uintptr_t)entrypt, (uintptr_t)arg); + while (1); /* Shut up the compiler warning */ +} + +#endif /* (CONFIG_BUILD_PROTECTED || CONFIG_BUILD_KERNEL) && !CONFIG_DISABLE_PTHREAD */ diff --git a/arch/ceva/src/common/up_puts.c b/arch/ceva/src/common/up_puts.c new file mode 100644 index 0000000000..edb931c059 --- /dev/null +++ b/arch/ceva/src/common/up_puts.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * arch/ceva/src/common/up_puts.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_puts + * + * Description: + * This is a low-level helper function used to support debug. + * + ****************************************************************************/ + +void up_puts(const char *str) +{ + while (*str) + { + up_putc(*str++); + } +} diff --git a/arch/ceva/src/common/up_releasepending.c b/arch/ceva/src/common/up_releasepending.c new file mode 100644 index 0000000000..65fb0872fc --- /dev/null +++ b/arch/ceva/src/common/up_releasepending.c @@ -0,0 +1,114 @@ +/**************************************************************************** + * arch/ceva/src/common/up_releasepending.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_release_pending + * + * Description: + * Release and ready-to-run tasks that have + * collected in the pending task list. This can call a + * context switch if a new task is placed at the head of + * the ready to run list. + * + ****************************************************************************/ + +void up_release_pending(void) +{ + struct tcb_s *rtcb = this_task(); + + sinfo("From TCB=%p\n", rtcb); + + /* Merge the g_pendingtasks list into the ready-to-run task list */ + + if (sched_mergepending()) + { + /* The currently active task has changed! We will need to switch + * contexts. + */ + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we operating in interrupt context? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. Just copy the + * CURRENT_REGS into the OLD rtcb. + */ + + rtcb->xcp.regs = CURRENT_REGS; + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + CURRENT_REGS = rtcb->xcp.regs; + } + + /* No, then we will need to perform the user context switch */ + + else + { + struct tcb_s *nexttcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + up_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } +} diff --git a/arch/ceva/src/common/up_releasestack.c b/arch/ceva/src/common/up_releasestack.c new file mode 100644 index 0000000000..67c29664d4 --- /dev/null +++ b/arch/ceva/src/common/up_releasestack.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * arch/ceva/src/common/up_releasestack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration */ + +#undef HAVE_KERNEL_HEAP +#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \ + defined(CONFIG_MM_KERNEL_HEAP) +# define HAVE_KERNEL_HEAP 1 +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_release_stack + * + * Description: + * A task has been stopped. Free all stack related resources retained in + * the defunct TCB. + * + * Input Parameters: + * - dtcb: The TCB containing information about the stack to be released + * - ttype: The thread type. This may be one of following (defined in + * include/nuttx/sched.h): + * + * TCB_FLAG_TTYPE_TASK Normal user task + * TCB_FLAG_TTYPE_PTHREAD User pthread + * TCB_FLAG_TTYPE_KERNEL Kernel thread + * + * This thread type is normally available in the flags field of the TCB, + * however, there are certain error recovery contexts where the TCB may + * not be fully initialized when up_release_stack is called. + * + * If either CONFIG_BUILD_PROTECTED or CONFIG_BUILD_KERNEL are defined, + * then this thread type may affect how the stack is freed. For example, + * kernel thread stacks may have been allocated from protected kernel + * memory. Stacks for user tasks and threads must have come from memory + * that is accessible to user code. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_release_stack(FAR struct tcb_s *dtcb, uint8_t ttype) +{ + /* Is there a stack allocated? */ + + if (dtcb->stack_alloc_ptr) + { +#ifdef HAVE_KERNEL_HEAP + /* Use the kernel allocator if this is a kernel thread */ + + if (ttype == TCB_FLAG_TTYPE_KERNEL) + { + if (kmm_heapmember(dtcb->stack_alloc_ptr)) + { + kmm_free(dtcb->stack_alloc_ptr); + } + } + else +#endif + { + /* Use the user-space allocator if this is a task or pthread */ + + if (umm_heapmember(dtcb->stack_alloc_ptr)) + { + kumm_free(dtcb->stack_alloc_ptr); + } + } + + /* Mark the stack freed */ + + dtcb->stack_alloc_ptr = NULL; + } + + /* The size of the allocated stack is now zero */ + + dtcb->adj_stack_size = 0; +} diff --git a/arch/ceva/src/common/up_reprioritizertr.c b/arch/ceva/src/common/up_reprioritizertr.c new file mode 100644 index 0000000000..d2aab1bd70 --- /dev/null +++ b/arch/ceva/src/common/up_reprioritizertr.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * arch/ceva/src/common/up_reprioritizertr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_reprioritize_rtr + * + * Description: + * Called when the priority of a running or + * ready-to-run task changes and the reprioritization will + * cause a context switch. Two cases: + * + * 1) The priority of the currently running task drops and the next + * task in the ready to run list has priority. + * 2) An idle, ready to run task's priority has been raised above the + * the priority of the current, running task and it now has the + * priority. + * + * Inputs: + * tcb: The TCB of the task that has been reprioritized + * priority: The new task priority + * + ****************************************************************************/ + +void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority) +{ + /* Verify that the caller is sane */ + + if (tcb->task_state < FIRST_READY_TO_RUN_STATE || + tcb->task_state > LAST_READY_TO_RUN_STATE +#if SCHED_PRIORITY_MIN > 0 + || priority < SCHED_PRIORITY_MIN +#endif +#if SCHED_PRIORITY_MAX < UINT8_MAX + || priority > SCHED_PRIORITY_MAX +#endif + ) + { + DEBUGPANIC(); + } + else + { + struct tcb_s *rtcb = this_task(); + bool switch_needed; + + sinfo("TCB=%p PRI=%d\n", tcb, priority); + + /* Remove the tcb task from the ready-to-run list. + * sched_removereadytorun will return true if we just removed the head + * of the ready to run list. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Setup up the new task priority */ + + tcb->sched_priority = (uint8_t)priority; + + /* Return the task to the ready-to-run task list. sched_addreadytorun + * will return true if the task was added to the head of ready-to-run + * list. We will need to perform a context switch only if the + * EXCLUSIVE or of the two calls is non-zero (i.e., one and only one + * the calls changes the head of the ready-to-run list). + */ + + switch_needed ^= sched_addreadytorun(tcb); + + /* Now, perform the context switch if one is needed (i.e. if the head + * of the ready-to-run list is no longer the same). + */ + + if (switch_needed) + { + /* If we are going to do a context switch, then now is the right + * time to add any pending tasks back into the ready-to-run list. + * task list now + */ + + if (g_pendingtasks.head) + { + sched_mergepending(); + } + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + rtcb->xcp.regs = CURRENT_REGS; + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + CURRENT_REGS = rtcb->xcp.regs; + } + + /* No, then we will need to perform the user context switch */ + + else + { + struct tcb_s *nexttcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + up_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the + * blocked task is again ready to run and has execution + * priority. + */ + } + } + } +} diff --git a/arch/ceva/src/common/up_saveusercontext.c b/arch/ceva/src/common/up_saveusercontext.c new file mode 100644 index 0000000000..068592e974 --- /dev/null +++ b/arch/ceva/src/common/up_saveusercontext.c @@ -0,0 +1,67 @@ +/**************************************************************************** + * arch/ceva/src/common/up_saveusercontext.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_saveusercontext + * + * Description: + * Save the current thread context. Full prototype is: + * + * int up_saveusercontext(uint32_t *saveregs); + * + * Return: + * 0: Normal return + * 1: Context switch return + * + ****************************************************************************/ + +int up_saveusercontext(uint32_t *saveregs) +{ + int ret; + + /* Let sys_call1() do all of the work */ + + ret = sys_call1(SYS_save_context, (uintptr_t)saveregs); + if (ret == 0) + { + /* There are two return conditions. On the first return, A0 (the + * return value will be zero. On the second return we need to + * force A0 to be 1. + */ + + saveregs[REG_A0] = 1; + } + + return ret; +} diff --git a/arch/ceva/src/common/up_schedulesigaction.c b/arch/ceva/src/common/up_schedulesigaction.c new file mode 100644 index 0000000000..d2129bb9c7 --- /dev/null +++ b/arch/ceva/src/common/up_schedulesigaction.c @@ -0,0 +1,215 @@ +/**************************************************************************** + * arch/ceva/src/common/up_schedulesigaction.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_schedule_sigaction + * + * Description: + * This function is called by the OS when one or more + * signal handling actions have been queued for execution. + * The architecture specific code must configure things so + * that the 'sigdeliver' callback is executed on the thread + * specified by 'tcb' as soon as possible. + * + * This function may be called from interrupt handling logic. + * + * This operation should not cause the task to be unblocked + * nor should it cause any immediate execution of sigdeliver. + * Typically, a few cases need to be considered: + * + * (1) This function may be called from an interrupt handler + * During interrupt processing, all xcptcontext structures + * should be valid for all tasks. That structure should + * be modified to invoke sigdeliver() either on return + * from (this) interrupt or on some subsequent context + * switch to the recipient task. + * (2) If not in an interrupt handler and the tcb is NOT + * the currently executing task, then again just modify + * the saved xcptcontext structure for the recipient + * task so it will invoke sigdeliver when that task is + * later resumed. + * (3) If not in an interrupt handler and the tcb IS the + * currently executing task -- just call the signal + * handler now. + * + ****************************************************************************/ + +void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) +{ + sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver); + DEBUGASSERT(tcb != NULL && sigdeliver != NULL); + + /* Refuse to handle nested signal actions */ + + if (tcb->xcp.sigdeliver == NULL) + { + /* First, handle some special cases when the signal is being delivered + * to task that is currently executing on any CPU. + */ + + sinfo("rtcb=0x%p CURRENT_REGS=0x%p\n", this_task(), CURRENT_REGS); + + if (tcb->task_state == TSTATE_TASK_RUNNING) + { + uint8_t me = this_cpu(); +#ifdef CONFIG_SMP + uint8_t cpu = tcb->cpu; +#else + uint8_t cpu = 0; +#endif + + /* CASE 1: We are not in an interrupt handler and a task is + * signaling itself for some reason. + */ + + if (cpu == me && !CURRENT_REGS) + { + /* In this case just deliver the signal now. */ + + sigdeliver(tcb); + } + + /* CASE 2: The task that needs to receive the signal is running. + * This could happen if the task is running on another CPU OR if + * we are in an interrupt handler and the task is running on this + * CPU. In the former case, we will have to PAUSE the other CPU + * first. But in either case, we will have to modify the return + * state as well as the state in the TCB. + */ + + else + { +#ifdef CONFIG_SMP + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ + + if (cpu != me) + { + /* Pause the CPU */ + + up_cpu_pause(cpu); + + /* Wait while the pause request is pending */ + + while (up_cpu_pausereq(cpu)) + { + } + } + + /* Now tcb on the other CPU can be accessed safely */ +#endif + + /* Save the current register context location */ + + tcb->xcp.saved_regs = g_current_regs[cpu]; + tcb->xcp.sigdeliver = (FAR void *)sigdeliver; + + /* Duplicate the register context. These will be + * restored by the signal trampoline after the signal has been + * delivered. + */ + + g_current_regs[cpu] -= XCPTCONTEXT_REGS; + memcpy(g_current_regs[cpu], g_current_regs[cpu] + + XCPTCONTEXT_REGS, XCPTCONTEXT_SIZE); + + g_current_regs[cpu][REG_SP] = (uint32_t)g_current_regs[cpu]; + + /* Then set up to vector to the trampoline with interrupts + * unchanged. We must already be in privileged thread mode + * to be here. + */ + + g_current_regs[cpu][REG_PC] = (uint32_t)up_sigdeliver; +#ifdef REG_OM + g_current_regs[cpu][REG_OM] &= ~REG_OM_MASK; + g_current_regs[cpu][REG_OM] |= REG_OM_KERNEL; +#endif + +#ifdef CONFIG_SMP + /* RESUME the other CPU if it was PAUSED */ + + if (cpu != me) + { + up_cpu_resume(cpu); + } +#endif + } + } + + /* Otherwise, we are (1) signaling a task is not running from an + * interrupt handler or (2) we are not in an interrupt handler and the + * running task is signaling some other non-running task. + */ + + else + { + /* Save the current register context location */ + + tcb->xcp.saved_regs = tcb->xcp.regs; + tcb->xcp.sigdeliver = (FAR void *)sigdeliver; + + /* Duplicate the register context. These will be restored + * by the signal trampoline after the signal has been delivered. + */ + + tcb->xcp.regs -= XCPTCONTEXT_REGS; + memcpy(tcb->xcp.regs, tcb->xcp.regs + + XCPTCONTEXT_REGS, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + + /* Then set up to vector to the trampoline with interrupts + * unchanged. We must already be in privileged thread mode to be + * here. + */ + + tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver; +#ifdef REG_OM + tcb->xcp.regs[REG_OM] &= ~REG_OM_MASK; + tcb->xcp.regs[REG_OM] |= REG_OM_KERNEL; +#endif + } + } +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/ceva/src/common/up_sigdeliver.c b/arch/ceva/src/common/up_sigdeliver.c new file mode 100644 index 0000000000..dd222ca445 --- /dev/null +++ b/arch/ceva/src/common/up_sigdeliver.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * arch/ceva/src/common/up_sigdeliver.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_sigdeliver + * + * Description: + * This is the a signal handling trampoline. When a signal action was + * posted. The task context was mucked with and forced to branch to this + * location with interrupts unchanged. + * + ****************************************************************************/ + +void up_sigdeliver(void) +{ + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; + sig_deliver_t sigdeliver; + + /* Save the errno. This must be preserved throughout the signal handling + * so that the user code final gets the correct errno value (probably + * EINTR). + */ + + int saved_errno = rtcb->pterrno; + + sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n", + rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); + DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); + + /* Get a local copy of the sigdeliver function pointer. We do this so that + * we can nullify the sigdeliver function pointer in the TCB and accept + * more signal deliveries while processing the current pending signals. + */ + + sigdeliver = (sig_deliver_t)rtcb->xcp.sigdeliver; + rtcb->xcp.sigdeliver = NULL; + + /* Deliver the signal */ + + sigdeliver(rtcb); + + /* Output any debug messages BEFORE restoring errno (because they may + * alter errno), then disable interrupts again and restore the original + * errno that is needed by the user logic (it is probably EINTR). + */ + + sinfo("Resuming\n"); + + rtcb->pterrno = saved_errno; + + /* Then restore the correct state for this thread of + * execution. + */ + + up_fullcontextrestore(regs); +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ diff --git a/arch/ceva/src/common/up_signal_dispatch.c b/arch/ceva/src/common/up_signal_dispatch.c new file mode 100644 index 0000000000..4065f8e7d1 --- /dev/null +++ b/arch/ceva/src/common/up_signal_dispatch.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/ceva/src/common/up_signal_dispatch.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" + +#if ((defined(CONFIG_BUILD_PROTECTED) && defined(__KERNEL__)) || \ + defined(CONFIG_BUILD_KERNEL)) && !defined(CONFIG_DISABLE_SIGNALS) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_dispatch + * + * Description: + * In this kernel mode build, this function will be called to execute a + * a signal handler in user-space. When the signal is delivered, a + * kernel-mode stub will first run to perform some housekeeping functions. + * This kernel-mode stub will then be called transfer control to the user + * mode signal handler by calling this function. + * + * Normally the a user-mode signalling handling stub will also execute + * before the ultimate signal handler is called. See + * arch/ceva/src/[xc5/xm6]/up_signal_handler. This function is the + * user-space, signal handler trampoline function. It is called from + * up_signal_dispatch() in user-mode. + * + * Inputs: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via an architecture specific system call made by up_signal_handler(). + * However, this will look like a normal return by the caller of + * up_signal_dispatch. + * + ****************************************************************************/ + +void up_signal_dispatch(_sa_sigaction_t sighand, int signo, + FAR siginfo_t *info, FAR void *ucontext) +{ + /* Let sys_call4() do all of the work */ + + sys_call4(SYS_signal_handler, (uintptr_t)sighand, (uintptr_t)signo, + (uintptr_t)info, (uintptr_t)ucontext); +} + +#endif /* (CONFIG_BUILD_PROTECTED || CONFIG_BUILD_KERNEL) && !CONFIG_DISABLE_PTHREAD */ diff --git a/arch/ceva/src/common/up_stackframe.c b/arch/ceva/src/common/up_stackframe.c new file mode 100644 index 0000000000..4d8a3a5a85 --- /dev/null +++ b/arch/ceva/src/common/up_stackframe.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * arch/ceva/src/common/up_stackframe.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Macros + ****************************************************************************/ + +/* Stack alignment macros */ + +#define STACK_ALIGN_MASK (sizeof(uint32_t) - 1) +#define STACK_ALIGN_UP(a) (((a) + STACK_ALIGN_MASK) & ~STACK_ALIGN_MASK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_stack_frame + * + * Description: + * Allocate a stack frame in the TCB's stack to hold thread-specific data. + * This function may be called anytime after up_create_stack() or + * up_use_stack() have been called but before the task has been started. + * + * Thread data may be kept in the stack (instead of in the TCB) if it is + * accessed by the user code directly. This includes such things as + * argv[]. The stack memory is guaranteed to be in the same protection + * domain as the thread. + * + * The following TCB fields will be re-initialized: + * + * - adj_stack_size: Stack size after removal of the stack frame from + * the stack + * - adj_stack_ptr: Adjusted initial stack pointer after the frame has + * been removed from the stack. This will still be the initial value + * of the stack pointer when the task is started. + * + * Inputs: + * - tcb: The TCB of new task + * - frame_size: The size of the stack frame to allocate. + * + * Returned Value: + * - A pointer to bottom of the allocated stack frame. NULL will be + * returned on any failures. The alignment of the returned value is + * the same as the alignment of the stack itself. + * + ****************************************************************************/ + +FAR void *up_stack_frame(FAR struct tcb_s *tcb, size_t frame_size) +{ + FAR void *topaddr; + + /* Align the frame_size */ + + frame_size = STACK_ALIGN_UP(frame_size); + + /* Is there already a stack allocated? Is it big enough? */ + + if (!tcb->stack_alloc_ptr || tcb->adj_stack_size < frame_size) + { + return NULL; + } + + /* Save the adjusted stack values in the struct tcb_s */ + + topaddr = tcb->adj_stack_ptr - frame_size; + tcb->adj_stack_ptr = topaddr; + tcb->adj_stack_size -= frame_size; + + /* Reinitialize the task state after the stack is adjusted */ + + up_initial_state(tcb); + + /* And return the pointer to the allocated region */ + + return topaddr; +} diff --git a/arch/ceva/src/common/up_start.c b/arch/ceva/src/common/up_start.c new file mode 100644 index 0000000000..5a673484b3 --- /dev/null +++ b/arch/ceva/src/common/up_start.c @@ -0,0 +1,312 @@ +/**************************************************************************** + * arch/ceva/src/common/up_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "mpu.h" +#include "up_internal.h" + +#if CONFIG_ARCH_NR_MEMORY >= 2 +# define _START_TEXT2 ((const void *)&_stext2) +# define _END_TEXT2 ((const void *)&_etext2) +# define _START_BSS2 ((void *)&_sbss2) +# define _END_BSS2 ((void *)&_ebss2) +# define _DATA_INIT2 ((const void *)&_eronly2) +# define _START_DATA2 ((void *)&_sdata2) +# define _END_DATA2 ((void *)&_edata2) +#else +# define _START_TEXT2 NULL +# define _END_TEXT2 NULL +# define _START_BSS2 NULL +# define _END_BSS2 NULL +# define _DATA_INIT2 NULL +# define _START_DATA2 NULL +# define _END_DATA2 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 3 +# define _START_TEXT3 ((const void *)&_stext3) +# define _END_TEXT3 ((const void *)&_etext3) +# define _START_BSS3 ((void *)&_sbss3) +# define _END_BSS3 ((void *)&_ebss3) +# define _DATA_INIT3 ((const void *)&_eronly3) +# define _START_DATA3 ((void *)&_sdata3) +# define _END_DATA3 ((void *)&_edata3) +#else +# define _START_TEXT3 NULL +# define _END_TEXT3 NULL +# define _START_BSS3 NULL +# define _END_BSS3 NULL +# define _DATA_INIT3 NULL +# define _START_DATA3 NULL +# define _END_DATA3 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 4 +# define _START_TEXT4 ((const void *)&_stext4) +# define _END_TEXT4 ((const void *)&_etext4) +# define _START_BSS4 ((void *)&_sbss4) +# define _END_BSS4 ((void *)&_ebss4) +# define _DATA_INIT4 ((const void *)&_eronly4) +# define _START_DATA4 ((void *)&_sdata4) +# define _END_DATA4 ((void *)&_edata4) +#else +# define _START_TEXT4 NULL +# define _END_TEXT4 NULL +# define _START_BSS4 NULL +# define _END_BSS4 NULL +# define _DATA_INIT4 NULL +# define _START_DATA4 NULL +# define _END_DATA4 NULL +#endif + +#if CONFIG_ARCH_NR_MEMORY >= 5 +# error CONFIG_ARCH_NR_MEMORY must between 1 to 4 +#endif + +/**************************************************************************** + * Private Function prototypes + ****************************************************************************/ + +static void init_bss_section(bool priv, + void *const bssstart[], + void *const bssend[]); + +static void init_data_section(bool priv, + const void *const datasource[], + void *const datastart[], + void *const dataend[]); + +static void init_text_section(bool priv, + const void *const textstart[], + const void *const textend[]); + +static void init_kernelspace(void); + +#ifdef CONFIG_BUILD_PROTECTED +static void init_userspace(void); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void init_bss_section(bool priv, + void *const bssstart[], + void *const bssend[]) +{ + int i; + + for (i = 0; bssstart[i] != _END_MEM || bssend[i] != _END_MEM; i++) + { + if (priv) + { + mpu_priv_data(bssstart[i], bssend[i] - bssstart[i]); + } + else + { + mpu_user_data(bssstart[i], bssend[i] - bssstart[i]); + } + + memset(bssstart[i], 0, bssend[i] - bssstart[i]); + } +} + +static void init_data_section(bool priv, + const void *const datasource[], + void *const datastart[], + void *const dataend[]) +{ + int i; + + for (i = 0; datasource[i] != _END_MEM + || datastart[i] != _END_MEM + || dataend[i] != _END_MEM; i++) + { + if (priv) + { + mpu_priv_data(datastart[i], dataend[i] - datastart[i]); + } + else + { + mpu_user_data(datastart[i], dataend[i] - datastart[i]); + } + + if (datasource[i] != datastart[i]) + { + memcpy(datastart[i], datasource[i], dataend[i] - datastart[i]); + } + } +} + +static void init_text_section(bool priv, + const void *const textstart[], + const void *const textend[]) +{ + int i; + + for (i = 0; textstart[i] != _END_MEM || textend[i] != _END_MEM; i++) + { + if (priv) + { + mpu_priv_code(textstart[i], textend[i] - textstart[i]); + } + else + { + mpu_user_code(textstart[i], textend[i] - textstart[i]); + } + } +} + +static void init_kernelspace(void) +{ + const void *const textstart[] = + { + _START_TEXT, _START_TEXT2, _START_TEXT3, _START_TEXT4, _END_MEM, + }; + + const void *const textend[] = + { + _END_TEXT, _END_TEXT2, _END_TEXT3, _END_TEXT4, _END_MEM, + }; + + const void *const datasource[] = + { + _DATA_INIT, _DATA_INIT2, _DATA_INIT3, _DATA_INIT4, _END_MEM, + }; + + void *const datastart[] = + { + _START_DATA, _START_DATA2, _START_DATA3, _START_DATA4, _END_MEM, + }; + + void *const dataend[] = + { + _END_DATA, _END_DATA2, _END_DATA3, _END_DATA4, _END_MEM, + }; + + void *const bssstart[] = + { + _START_BSS, _START_BSS2, _START_BSS3, _START_BSS4, _END_MEM, + }; + + void *const bssend[] = + { + _END_BSS, _END_BSS2, _END_BSS3, _END_BSS4, _END_MEM, + }; + + init_text_section(true, textstart, textend); + + /* Move the initialized data section from his temporary holding spot in + * FLASH into the correct place in SRAM. The correct place in SRAM is + * give by _sdata and _edata. The temporary location is in FLASH at the + * end of all of the other read-only data (.text, .rodata) at _eronly. + */ + + init_data_section(true, datasource, datastart, dataend); + + /* Clear .bss. We'll do this inline (vs. calling memset) just to be + * certain that there are no issues with the state of global variables. + */ + + init_bss_section(true, bssstart, bssend); + + /* Initialize the idle stack */ + + mpu_priv_data(g_idle_basestack, + g_idle_topstack - g_idle_basestack); +#ifdef CONFIG_STACK_COLORATION + up_stack_color(g_idle_basestack, + g_idle_topstack - g_idle_basestack - B2C(256)); +#endif +} + +#ifdef CONFIG_BUILD_PROTECTED +static void init_userspace(void) +{ + /* Initialize all of user-space .data */ + + DEBUGASSERT( + USERSPACE->us_datasource != 0 && + USERSPACE->us_datastart != 0 && + USERSPACE->us_dataend != 0); + + init_text_section(false, + (const void *const *)USERSPACE->us_textstart, + (const void *const *)USERSPACE->us_textend); + + init_data_section(false, + (const void *const *)USERSPACE->us_datasource, + (void *const *)USERSPACE->us_datastart, + (void *const *)USERSPACE->us_dataend); + + /* Clear all of user-space .bss */ + + DEBUGASSERT( + USERSPACE->us_bssstart != 0 && + USERSPACE->us_bssend != 0); + + init_bss_section(false, + (void *const *)USERSPACE->us_bssstart, + (void *const *)USERSPACE->us_bssend); +} +#else +# define init_userspace() +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_start + * + * Description: + * This is the reset entry point. + * + ****************************************************************************/ + +void up_start(void) +{ + up_enable_icache(); + up_enable_dcache(); + + init_kernelspace(); + init_userspace(); + + mpu_control(true); + + up_earlyserialinit(); + up_earlyinitialize(); + board_earlyinitialize(); + + nx_start(); +} diff --git a/arch/ceva/src/common/up_svcall.c b/arch/ceva/src/common/up_svcall.c new file mode 100644 index 0000000000..b7889dddc1 --- /dev/null +++ b/arch/ceva/src/common/up_svcall.c @@ -0,0 +1,414 @@ +/**************************************************************************** + * arch/ceva/src/common/up_svcall.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "svcall.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_svcall + * + * Description: + * This is SVCall exception handler that performs context switching + * + ****************************************************************************/ + +int up_svcall(int irq, FAR void *context, FAR void *arg) +{ + uint32_t *regs = (uint32_t *)context; + uint32_t cmd; + + DEBUGASSERT(regs && regs == CURRENT_REGS); + cmd = regs[REG_A0]; + + /* The SVCall software interrupt is called with A0 = system call command + * and A1..A6 = variable number of arguments depending on the system call. + */ + +#ifdef CONFIG_DEBUG_SYSCALL_INFO +# ifndef CONFIG_DEBUG_SVCALL + if (cmd > SYS_switch_context) +# endif + { + svcinfo("SVCALL Entry: regs: %p cmd: %d\n", regs, cmd); + svcinfo("A0: %08x %08x %08x %08x %08x %08x %08x\n", + regs[REG_A0], regs[REG_A1], regs[REG_A2], regs[REG_A3], + regs[REG_A4], regs[REG_A5], regs[REG_A6]); + svcinfo("FP: %08x LR: %08x PC: %08x IRQ: %08x OM: %08x\n", + regs[REG_FP], regs[REG_LR], regs[REG_PC], regs[REG_IRQ], +# ifdef REG_OM + regs[REG_OM] +#else + 0x00000000 +#endif + ); + } +#endif + + /* Handle the SVCall according to the command in A0 */ + + switch (cmd) + { + /* A0=SYS_save_context: This is a save context command: + * + * int up_saveusercontext(uint32_t *saveregs); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_save_context + * A1 = saveregs + * + * In this case, we simply need to copy the current regsters to the + * save register space references in the saved A1 and return. + */ + + case SYS_save_context: + { + DEBUGASSERT(regs[REG_A1] != 0); + memcpy((uint32_t *)regs[REG_A1], regs, XCPTCONTEXT_SIZE); + } + break; + + /* A0=SYS_restore_context: This a restore context command: + * + * void up_fullcontextrestore(uint32_t *restoreregs); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_restore_context + * A1 = restoreregs + * + * In this case, we simply need to set CURRENT_REGS to restore register + * area referenced in the saved A1. context == CURRENT_REGS is the + * noraml exception return. By setting CURRENT_REGS = context[A1], + * we force the return to the saved context referenced in A1. + */ + + case SYS_restore_context: + { + DEBUGASSERT(regs[REG_A1] != 0); + CURRENT_REGS = (uint32_t *)regs[REG_A1]; + } + break; + + /* A0=SYS_switch_context: This a switch context command: + * + * void up_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_switch_context + * A1 = saveregs + * A2 = restoreregs + * + * In this case, we do both: We save the context registers to the save + * register area reference by the saved contents of A1 and then set + * CURRENT_REGS to to the save register area referenced by the saved + * contents of A2. + */ + + case SYS_switch_context: + { + DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0); + *(uint32_t **)regs[REG_A1] = regs; + CURRENT_REGS = (uint32_t *)regs[REG_A2]; + } + break; + + /* A0=SYS_syscall_return: This a syscall return command: + * + * void up_syscall_return(void); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_syscall_return + * + * We need to restore the saved return address and return in + * unprivileged thread mode. + */ + +#ifdef CONFIG_LIB_SYSCALL + case SYS_syscall_return: + { + struct tcb_s *rtcb = sched_self(); + int index = rtcb->xcp.nsyscalls - 1; + + /* Make sure that there is a saved syscall return address. */ + + DEBUGASSERT(index >= 0); + + /* Setup to return to the saved syscall return address in + * the original mode. + */ + + regs[REG_PC] = rtcb->xcp.syscall[index].saved_pc; +#ifdef REG_OM + regs[REG_OM] = rtcb->xcp.syscall[index].saved_om; +#endif + rtcb->xcp.nsyscalls = index; + + /* The return value must be in A0-A1. up_svcall_handler() + * temporarily moved the value for A0 into A2. + */ + + regs[REG_A0] = regs[REG_A2]; + } + break; +#endif + + /* A0=SYS_task_start: This a user task start + * + * void up_task_start(main_t taskentry, int argc, FAR char *argv[]); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_task_start + * A1 = taskentry + * A2 = argc + * A3 = argv + */ + +#ifdef CONFIG_BUILD_PROTECTED + case SYS_task_start: + { + /* Set up to return to the user-space task start-up function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)USERSPACE->task_startup; +#ifdef REG_OM + regs[REG_OM] &= ~REG_OM_MASK; + regs[REG_OM] |= REG_OM_USER; +#endif + + /* Change the parameter ordering to match the expectation of struct + * userpace_s task_startup: + */ + + regs[REG_A0] = regs[REG_A1]; /* Task entry */ + regs[REG_A1] = regs[REG_A2]; /* argc */ + regs[REG_A2] = regs[REG_A3]; /* argv */ + } + break; +#endif + + /* A0=SYS_pthread_start: This a user pthread start + * + * void up_pthread_start(pthread_startroutine_t entrypt, + pthread_addr_t arg); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_pthread_start + * A1 = entrypt + * A2 = arg + */ + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(CONFIG_DISABLE_PTHREAD) + case SYS_pthread_start: + { + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)USERSPACE->pthread_startup; +#ifdef REG_OM + regs[REG_OM] &= ~REG_OM_MASK; + regs[REG_OM] |= REG_OM_USER; +#endif + + /* Change the parameter ordering to match the expectation of struct + * userpace_s pthread_startup: + */ + + regs[REG_A0] = regs[REG_A1]; /* pthread entry */ + regs[REG_A1] = regs[REG_A2]; /* arg */ + } + break; +#endif + + /* A0=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * FAR siginfo_t *info, FAR void *ucontext); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_signal_handler + * A1 = sighand + * A2 = signo + * A3 = info + * A4 = ucontext + */ + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler: + { + struct tcb_s *rtcb = sched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_PC]; + + /* Set up to return to the user-space signal handler function in + * unprivileged mode. + */ + + regs[REG_PC] = (uint32_t)USERSPACE->signal_handler; +#ifdef REG_OM + regs[REG_OM] &= ~REG_OM_MASK; + regs[REG_OM] |= REG_OM_USER; +#endif + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_A0] = regs[REG_A1]; /* sighand */ + regs[REG_A1] = regs[REG_A2]; /* signal */ + regs[REG_A2] = regs[REG_A3]; /* info */ + regs[REG_A3] = regs[REG_A4]; /* ucontext */ + } + break; +#endif + + /* A0=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * A0 = SYS_signal_handler_return + */ + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(CONFIG_DISABLE_SIGNALS) + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = sched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + + regs[REG_PC] = rtcb->xcp.sigreturn; +#ifdef REG_OM + regs[REG_OM] &= ~REG_OM_MASK; + regs[REG_OM] |= REG_OM_KERNEL; +#endif + rtcb->xcp.sigreturn = 0; + } + break; +#endif + + /* This is not an architecture-specific system call. If NuttX is built + * as a standalone kernel with a system call interface, then all of the + * additional system calls must be handled as in the default case. + */ + + default: + { +#ifdef CONFIG_LIB_SYSCALL + FAR struct tcb_s *rtcb = sched_self(); + int index = rtcb->xcp.nsyscalls; + + /* Verify that the SYS call number is within range */ + + DEBUGASSERT(cmd >= CONFIG_SYS_RESERVED && cmd < SYS_maxsyscall); + DEBUGASSERT(index < CONFIG_SYS_NNEST); + + /* Setup to return to up_svcall_handler in privileged mode. */ + + rtcb->xcp.syscall[index].saved_pc = regs[REG_PC]; +#ifdef REG_OM + rtcb->xcp.syscall[index].saved_om = regs[REG_OM]; +#endif + rtcb->xcp.nsyscalls = index + 1; + + regs[REG_PC] = (uint32_t)up_svcall_handler; +#ifdef REG_OM + regs[REG_OM] &= ~REG_OM_MASK; + regs[REG_OM] |= REG_OM_KERNEL; +#endif + + /* Offset A0 to account for the reserved values */ + + regs[REG_A0] -= CONFIG_SYS_RESERVED; +#else + svcerr("ERROR: Bad SYS call: %d\n", regs[REG_A0]); +#endif + } + break; + } + + /* Report what happened. + * That might be different in the case of a context switch + */ + +#ifdef CONFIG_DEBUG_SYSCALL_INFO +# ifndef CONFIG_DEBUG_SVCALL + if (cmd > SYS_switch_context) +# else + if (regs != CURRENT_REGS) +# endif + { + svcinfo("SVCall Return:\n"); + svcinfo("A0: %08x %08x %08x %08x %08x %08x %08x\n", + CURRENT_REGS[REG_A0], CURRENT_REGS[REG_A1], + CURRENT_REGS[REG_A2], CURRENT_REGS[REG_A3], + CURRENT_REGS[REG_A4], CURRENT_REGS[REG_A5], + CURRENT_REGS[REG_A6]); + svcinfo("FP: %08x LR: %08x PC: %08x IRQ: %08x OM: %08x\n", + CURRENT_REGS[REG_FP], CURRENT_REGS[REG_LR], + CURRENT_REGS[REG_PC], CURRENT_REGS[REG_IRQ], +# ifdef REG_OM + CURRENT_REGS[REG_OM] +#else + 0x00000000 +#endif + ); + } +# ifdef CONFIG_DEBUG_SVCALL + else + { + svcinfo("SVCall Return: %d\n", regs[REG_A0]); + } +# endif +#endif + + return OK; +} diff --git a/arch/ceva/src/common/up_switchcontext.c b/arch/ceva/src/common/up_switchcontext.c new file mode 100644 index 0000000000..c7e9a1cd2d --- /dev/null +++ b/arch/ceva/src/common/up_switchcontext.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * arch/ceva/src/common/up_switchcontext.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "svcall.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_switchcontext + * + * Description: + * Save the current thread context and restore the specified context. + * Full prototype is: + * + * void up_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); + * + * Return: + * None + * + ****************************************************************************/ + +void up_switchcontext(uint32_t **saveregs, uint32_t *restoreregs) +{ + /* Let sys_call2() do all of the work */ + + sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs); +} diff --git a/arch/ceva/src/common/up_task_start.c b/arch/ceva/src/common/up_task_start.c new file mode 100644 index 0000000000..62ac279cda --- /dev/null +++ b/arch/ceva/src/common/up_task_start.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * arch/ceva/src/common/up_task_start.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" + +#if defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_task_start + * + * Description: + * In this kernel mode build, this function will be called to execute a + * task in user-space. When the task is first started, a kernel-mode + * stub will first run to perform some housekeeping functions. This + * kernel-mode stub will then be called transfer control to the user-mode + * task. + * + * Normally the a user-mode start-up stub will also execute before the + * task actually starts. See libc/sched/task_startup.c + * + * Input Parameters: + * taskentry - The user-space entry point of the task. + * argc - The number of parameters being passed. + * argv - The parameters being passed. These lie in kernel-space memory + * and will have to be reallocated in user-space memory. + * + * Returned Value: + * This function should not return. It should call the user-mode start-up + * stub and that stub should call exit if/when the user task terminates. + * + ****************************************************************************/ + +void up_task_start(main_t taskentry, int argc, FAR char *argv[]) +{ + /* Let sys_call3() do all of the work */ + + sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc, + (uintptr_t)argv); + while (1); /* Shut up the compiler warning */ +} + +#endif /* CONFIG_BUILD_PROTECTED || CONFIG_BUILD_KERNEL */ diff --git a/arch/ceva/src/common/up_unblocktask.c b/arch/ceva/src/common/up_unblocktask.c new file mode 100644 index 0000000000..84e7b24502 --- /dev/null +++ b/arch/ceva/src/common/up_unblocktask.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * arch/ceva/src/common/up_unblocktask.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" +#include "up_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_unblock_task + * + * Description: + * A task is currently in an inactive task list + * but has been prepped to execute. Move the TCB to the + * ready-to-run list, restore its context, and start execution. + * + * Inputs: + * tcb: Refers to the tcb to be unblocked. This tcb is + * in one of the waiting tasks lists. It must be moved to + * the ready-to-run list and, if it is the highest priority + * ready to run taks, executed. + * + ****************************************************************************/ + +void up_unblock_task(struct tcb_s *tcb) +{ + struct tcb_s *rtcb = this_task(); + + /* Verify that the context switch can be performed */ + + DEBUGASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && + (tcb->task_state <= LAST_BLOCKED_STATE)); + + /* Remove the task from the blocked task list */ + + sched_removeblocked(tcb); + + /* Add the task in the correct location in the prioritized + * ready-to-run task list + */ + + if (sched_addreadytorun(tcb)) + { + /* The currently active task has changed! We need to do + * a context switch to the new task. + */ + + /* Update scheduler parameters */ + + sched_suspend_scheduler(rtcb); + + /* Are we in an interrupt handler? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + rtcb->xcp.regs = CURRENT_REGS; + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + CURRENT_REGS = rtcb->xcp.regs; + } + + /* No, then we will need to perform the user context switch */ + + else + { + struct tcb_s *nexttcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + up_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } +} diff --git a/arch/ceva/src/common/up_userspace.c b/arch/ceva/src/common/up_userspace.c new file mode 100644 index 0000000000..5e34e3bc01 --- /dev/null +++ b/arch/ceva/src/common/up_userspace.c @@ -0,0 +1,231 @@ +/**************************************************************************** + * arch/ceva/src/common/up_userspace.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "up_internal.h" + +#ifdef CONFIG_BUILD_PROTECTED + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if CONFIG_ARCH_USER_DEFAULT_HEAP == 0 +# define MM_HEAP1 &g_mmheap +#else +static struct mm_heap_s g_mmheap1; +# define MM_HEAP1 &g_mmheap1 +#endif + +#if CONFIG_ARCH_NR_USER_MEMORY >= 2 +# if CONFIG_ARCH_USER_DEFAULT_HEAP == 1 +# define MM_HEAP2 &g_mmheap +# else +static struct mm_heap_s g_mmheap2; +# define MM_HEAP2 &g_mmheap2 +# endif +# define _START_TEXT2 ((const void *)&_stext2) +# define _END_TEXT2 ((const void *)&_etext2) +# define _START_BSS2 ((void *)&_sbss2) +# define _END_BSS2 ((void *)&_ebss2) +# define _DATA_INIT2 ((const void *)&_eronly2) +# define _START_DATA2 ((void *)&_sdata2) +# define _END_DATA2 ((void *)&_edata2) +# define _END_HEAP2 ((void *)&_eheap2) +#else +# define MM_HEAP2 NULL +# define _START_TEXT2 NULL +# define _END_TEXT2 NULL +# define _START_BSS2 NULL +# define _END_BSS2 NULL +# define _DATA_INIT2 NULL +# define _START_DATA2 NULL +# define _END_DATA2 NULL +# define _END_HEAP2 NULL +#endif + +#if CONFIG_ARCH_NR_USER_MEMORY >= 3 +# if CONFIG_ARCH_USER_DEFAULT_HEAP == 2 +# define MM_HEAP3 &g_mmheap +# else +static struct mm_heap_s g_mmheap3; +# define MM_HEAP3 &g_mmheap3 +# endif +# define _START_TEXT3 ((const void *)&_stext3) +# define _END_TEXT3 ((const void *)&_etext3) +# define _START_BSS3 ((void *)&_sbss3) +# define _END_BSS3 ((void *)&_ebss3) +# define _DATA_INIT3 ((const void *)&_eronly3) +# define _START_DATA3 ((void *)&_sdata3) +# define _END_DATA3 ((void *)&_edata3) +# define _END_HEAP3 ((void *)&_eheap3) +#else +# define MM_HEAP3 NULL +# define _START_TEXT3 NULL +# define _END_TEXT3 NULL +# define _START_BSS3 NULL +# define _END_BSS3 NULL +# define _DATA_INIT3 NULL +# define _START_DATA3 NULL +# define _END_DATA3 NULL +# define _END_HEAP3 NULL +#endif + +#if CONFIG_ARCH_NR_USER_MEMORY >= 4 +# if CONFIG_ARCH_USER_DEFAULT_HEAP == 3 +# define MM_HEAP4 &g_mmheap +# else +static struct mm_heap_s g_mmheap4; +# define MM_HEAP4 &g_mmheap4 +# endif +# define _START_TEXT4 ((const void *)&_stext4) +# define _END_TEXT4 ((const void *)&_etext4) +# define _START_BSS4 ((void *)&_sbss4) +# define _END_BSS4 ((void *)&_ebss4) +# define _DATA_INIT4 ((const void *)&_eronly4) +# define _START_DATA4 ((void *)&_sdata4) +# define _END_DATA4 ((void *)&_edata4) +# define _END_HEAP4 ((void *)&_eheap4) +#else +# define MM_HEAP4 NULL +# define _START_TEXT4 NULL +# define _END_TEXT4 NULL +# define _START_BSS4 NULL +# define _END_BSS4 NULL +# define _DATA_INIT4 NULL +# define _START_DATA4 NULL +# define _END_DATA4 NULL +# define _END_HEAP4 NULL +#endif + +#if CONFIG_ARCH_NR_USER_MEMORY >= 5 +# error CONFIG_ARCH_NR_USER_MEMORY must between 1 to 4 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const void *const g_textstart[] = +{ + _START_TEXT, _START_TEXT2, _START_TEXT3, _START_TEXT4, _END_MEM, +}; + +static const void *const g_textend[] = +{ + _END_TEXT, _END_TEXT2, _END_TEXT3, _END_TEXT4, _END_MEM, +}; + +static const void *const g_datasource[] = +{ + _DATA_INIT, _DATA_INIT2, _DATA_INIT3, _DATA_INIT4, _END_MEM, +}; + +static void *const g_datastart[] = +{ + _START_DATA, _START_DATA2, _START_DATA3, _START_DATA4, _END_MEM, +}; + +static void *const g_dataend[] = +{ + _END_DATA, _END_DATA2, _END_DATA3, _END_DATA4, _END_MEM, +}; + +static void *const g_bssstart[] = +{ + _START_BSS, _START_BSS2, _START_BSS3, _START_BSS4, _END_MEM, +}; + +static void *const g_bssend[] = +{ + _END_BSS, _END_BSS2, _END_BSS3, _END_BSS4, _END_MEM, +}; + +static void *const g_heapend[] = +{ + _END_HEAP, _END_HEAP2, _END_HEAP3, _END_HEAP4, _END_MEM, +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct mm_heap_s *const g_mm_heap[] = +{ + MM_HEAP1, MM_HEAP2, MM_HEAP3, MM_HEAP4, NULL, +}; + +const struct userspace_s userspace __attribute__ ((section ("userspace"))) = +{ + /* General memory map */ + + .us_base = + { + .us_entrypoint = CONFIG_USER_ENTRYPOINT, + .us_textstart = (uintptr_t)g_textstart, + .us_textend = (uintptr_t)g_textend, + .us_datasource = (uintptr_t)g_datasource, + .us_datastart = (uintptr_t)g_datastart, + .us_dataend = (uintptr_t)g_dataend, + .us_bssstart = (uintptr_t)g_bssstart, + .us_bssend = (uintptr_t)g_bssend, + .us_heapend = (uintptr_t)g_heapend, + + /* Memory manager heap structure */ + + .us_heap = (struct mm_heap_s *)g_mm_heap, + + /* Task/thread startup routines */ + + .task_startup = task_startup, +#ifndef CONFIG_DISABLE_PTHREAD + .pthread_startup = pthread_startup, +#endif + + /* Signal handler trampoline */ + +#ifndef CONFIG_DISABLE_SIGNALS + .signal_handler = up_signal_handler, +#endif + + /* User-space work queue support (declared in include/nuttx/wqueue.h) */ + +#ifdef CONFIG_LIB_USRWORK + .work_usrstart = work_usrstart, +#endif + }, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_BUILD_PROTECTED */ diff --git a/arch/ceva/src/common/up_usestack.c b/arch/ceva/src/common/up_usestack.c new file mode 100644 index 0000000000..5bc8b119e7 --- /dev/null +++ b/arch/ceva/src/common/up_usestack.c @@ -0,0 +1,142 @@ +/**************************************************************************** + * arch/ceva/src/common/up_usestack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Macros + ****************************************************************************/ + +/* Stack alignment macros */ + +#define STACK_ALIGN_MASK (sizeof(uint32_t) - 1) +#define STACK_ALIGN_DOWN(a) ((a) & ~STACK_ALIGN_MASK) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_use_stack + * + * Description: + * Setup up stack-related information in the TCB using pre-allocated stack + * memory. This function is called only from task_init() when a task or + * kernel thread is started (never for pthreads). + * + * The following TCB fields must be initialized: + * + * - adj_stack_size: Stack size after adjustment for hardware, + * processor, etc. This value is retained only for debug + * purposes. + * - stack_alloc_ptr: Pointer to allocated stack + * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The + * initial value of the stack pointer. + * + * Inputs: + * - tcb: The TCB of new task + * - stack_size: The allocated stack size. + * + * NOTE: Unlike up_stack_create() and up_stack_release, this function + * does not require the task type (ttype) parameter. The TCB flags will + * always be set to provide the task type to up_use_stack() if it needs + * that information. + * + ****************************************************************************/ + +int up_use_stack(FAR struct tcb_s *tcb, FAR void *stack, size_t stack_size) +{ + FAR void *top_of_stack; + size_t size_of_stack; + +#ifdef CONFIG_TLS + /* Make certain that the user provided stack is properly aligned */ + + DEBUGASSERT((uintptr_t)stack & (B2C(TLS_STACK_ALIGN) - 1) == 0); +#else + DEBUGASSERT((uintptr_t)stack & STACK_ALIGN_MASK == 0); +#endif + + /* Is there already a stack allocated? */ + + if (tcb->stack_alloc_ptr) + { + /* Yes... Release the old stack allocation */ + + up_release_stack(tcb, tcb->flags & TCB_FLAG_TTYPE_MASK); + } + + /* Save the new stack allocation */ + + tcb->stack_alloc_ptr = stack; + + /* The CEVA uses a push-down stack: the stack grows toward lower addresses + * in memory. The stack pointer register, points to the lowest, valid + * work address (the "top" of the stack). Items on the stack are + * referenced as positive word offsets from sp. + */ + + /* The CEVA stack must be aligned to 4-byte alignment. + * If necessary size_of_stack must be rounded down to the next + * boundary + */ + + size_of_stack = STACK_ALIGN_DOWN(stack_size); + top_of_stack = tcb->stack_alloc_ptr + size_of_stack; + + /* Save the adjusted stack values in the struct tcb_s */ + + tcb->adj_stack_ptr = top_of_stack; + tcb->adj_stack_size = size_of_stack; + +#ifdef CONFIG_TLS + /* Initialize the TLS data structure */ + + memset(tcb->stack_alloc_ptr, 0, sizeof(struct tls_info_s)); +#endif + +#ifdef CONFIG_STACK_COLORATION + /* If stack debug is enabled, then fill the stack with a recognizable + * value that we can use later to test for high water marks. + */ + +#ifdef CONFIG_TLS + up_stack_color( + tcb->stack_alloc_ptr + sizeof(struct tls_info_s), + tcb->adj_stack_size - sizeof(struct tls_info_s)); +#else + up_stack_color(tcb->stack_alloc_ptr, tcb->adj_stack_size); +#endif +#endif + + return OK; +} diff --git a/arch/ceva/src/common/up_vfork.c b/arch/ceva/src/common/up_vfork.c new file mode 100644 index 0000000000..6f3800f5ac --- /dev/null +++ b/arch/ceva/src/common/up_vfork.c @@ -0,0 +1,208 @@ +/**************************************************************************** + * arch/ceva/src/common/up_vfork.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "sched/sched.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_vfork + * + * Description: + * The vfork() function has the same effect as fork(), except that the + * behavior is undefined if the process created by vfork() either modifies + * any data other than a variable of type pid_t used to store the return + * value from vfork(), or returns from the function in which vfork() was + * called, or calls any other function before successfully calling _exit() + * or one of the exec family of functions. + * + * The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_vfork()and calls nxtask_vforksetup(). + * 3) nxtask_vforksetup() allocates and configures the child task's TCB. + * This consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Setup the input parameters for the task. + * - Initialization of the TCB (including call to up_initial_state() + * 4) up_vfork() provides any additional operating context. up_vfork must: + * - Allocate and initialize the stack + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) up_vfork() then calls nxtask_vforkstart() + * 6) nxtask_vforkstart() then executes the child thread. + * + * nxtask_vforkabort() may be called if an error occurs between steps 3 & 6. + * + * Input Parameters: + * regs - Caller context information saved by vfork() + * + * Return: + * Upon successful completion, vfork() returns 0 to the child process and + * returns the process ID of the child process to the parent process. + * Otherwise, -1 is returned to the parent, no child process is created, + * and errno is set to indicate the error. + * + ****************************************************************************/ + +pid_t up_vfork(const uint32_t *regs) +{ +#ifdef CONFIG_SCHED_WAITPID + struct tcb_s *parent = this_task(); + struct task_tcb_s *child; + size_t stacksize; + const void *sp = regs + XCPTCONTEXT_REGS; + void *newsp; + uint32_t newfp; + uint32_t stackutil; + size_t argsize; + void *argv; + int ret; + + /* Allocate and initialize a TCB for the child task. */ + + child = nxtask_vforksetup(parent->start, &argsize); + if (!child) + { + serr("ERROR: nxtask_vforksetup failed\n"); + return (pid_t)ERROR; + } + + sinfo("TCBs: Parent=%p Child=%p\n", parent, child); + + /* Get the size of the parent task's stack. */ + + stacksize = parent->adj_stack_size; + + /* Allocate the stack for the TCB */ + + ret = up_create_stack((FAR struct tcb_s *)child, C2B(stacksize + argsize), + parent->flags & TCB_FLAG_TTYPE_MASK); + if (ret != OK) + { + serr("ERROR: up_create_stack failed: %d\n", ret); + nxtask_vforkabort(child, -ret); + return (pid_t)ERROR; + } + + /* Allocate the memory and copy argument from parent task */ + + argv = up_stack_frame((FAR struct tcb_s *)child, argsize); + memcpy(argv, parent->adj_stack_ptr, argsize); + + /* How much of the parent's stack was utilized? The CEVA uses + * a push-down stack so that the current stack pointer should + * be lower than the initial, adjusted stack pointer. The + * stack usage should be the difference between those two. + */ + + DEBUGASSERT(parent->adj_stack_ptr >= sp); + stackutil = parent->adj_stack_ptr - sp; + + sinfo("Parent: stacksize:%d stackutil:%d\n", stacksize, stackutil); + + /* Make some feeble effort to preserve the stack contents. This is + * feeble because the stack surely contains invalid pointers and other + * content that will not work in the child context. However, if the + * user follows all of the caveats of vfork() usage, even this feeble + * effort is overkill. + */ + + newsp = child->cmn.adj_stack_ptr - stackutil; + memcpy(newsp, sp, stackutil); + + /* Allocate the context and copy the parent snapshot */ + + newsp -= XCPTCONTEXT_SIZE; + memcpy(newsp, regs, XCPTCONTEXT_SIZE); + child->cmn.xcp.regs = newsp; + + /* Was there a frame pointer in place before? */ + + if (regs[REG_FP] <= (uint32_t)parent->adj_stack_ptr && + regs[REG_FP] >= (uint32_t)parent->adj_stack_ptr - stacksize) + { + uint32_t frameutil = (uint32_t)parent->adj_stack_ptr - regs[REG_FP]; + newfp = (uint32_t)child->cmn.adj_stack_ptr - frameutil; + } + else + { + newfp = regs[REG_FP]; + } + + sinfo("Parent: stack base:%08x SP:%08x FP:%08x\n", + parent->adj_stack_ptr, sp, regs[REG_FP]); + sinfo("Child: stack base:%08x SP:%08x FP:%08x\n", + child->cmn.adj_stack_ptr, newsp, newfp); + + /* Update the stack pointer, frame pointer, and the return value in A0 + * should be cleared to zero, providing the indication to the newly started + * child thread. + */ + + child->cmn.xcp.regs[REG_A0] = 0; /* Return value */ + child->cmn.xcp.regs[REG_FP] = newfp; /* Frame pointer */ + child->cmn.xcp.regs[REG_PC] = regs[REG_LR]; /* Program counter */ + child->cmn.xcp.regs[REG_SP] = (uint32_t)newsp; /* Stack pointer */ + +#ifdef CONFIG_LIB_SYSCALL + /* If we got here via a syscall, then we are going to have to setup some + * syscall return information as well. + */ + + if (parent->xcp.nsyscalls > 0) + { + int index; + for (index = 0; index < parent->xcp.nsyscalls; index++) + { + child->cmn.xcp.syscall[index] = parent->xcp.syscall[index]; + } + + child->cmn.xcp.nsyscalls = parent->xcp.nsyscalls; + } +#endif + + /* And, finally, start the child task. On a failure, nxtask_vforkstart() + * will discard the TCB by calling nxtask_vforkabort(). + */ + + return nxtask_vforkstart(child); +#else /* CONFIG_SCHED_WAITPID */ + return (pid_t)ERROR; +#endif +} diff --git a/arch/ceva/src/common/vintc.h b/arch/ceva/src/common/vintc.h new file mode 100644 index 0000000000..611902e548 --- /dev/null +++ b/arch/ceva/src/common/vintc.h @@ -0,0 +1,152 @@ +/**************************************************************************** + * arch/ceva/src/common/vintc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_COMMON_VINTC_H +#define __ARCH_CEVA_SRC_COMMON_VINTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: up_vintc_initialize + * + * Description: + * Initialize the VINTC. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_VINTC +void up_vintc_initialize(void); +#else +static inline void up_vintc_initialize(void) +{ +} +#endif + +/**************************************************************************** + * Name: up_vintc_enable_irq + * + * Description: + * On CEVA architectures, there are four levels of interrupt enabling: + * (1) at the global level(up_irq_enable) + * (2) at the DSP level(up_enable_irq) + * (2) at the VINTC level + * (3) at the device level + * In order to receive interrupts, they must be enabled at all four levels. + * + * This function implements enabling of the device specified by 'irq' + * at the VINTC level if supported by the architecture. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_VINTC +void up_vintc_enable_irq(int irq); +#else +static inline void up_vintc_enable_irq(int irq) +{ +} +#endif + +/**************************************************************************** + * Name: up_vintc_disable_irq + * + * Description: + * This function implements disabling of the device specified by 'irq' + * at the VINTC level if supported by the architecture(up_irq_save() + * supports the global level, the device level is hardware specific). + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_VINTC +void up_vintc_disable_irq(int irq); +#else +static inline void up_vintc_disable_irq(int irq) +{ +} +#endif + +/**************************************************************************** + * Name: up_vintc_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_HAVE_VINTC) && defined(CONFIG_ARCH_IRQPRIO) +int up_vintc_prioritize_irq(int irq, int priority); +#else +static inline int up_vintc_prioritize_irq(int irq, int priority) +{ + return 0; /* Not a critical error */ +} +#endif + +/**************************************************************************** + * Name: up_vintc_trigger_irq + * + * Description: + * Trigger an IRQ by software. + * + ****************************************************************************/ + +#if defined(CONFIG_ARCH_HAVE_VINTC) && defined(CONFIG_ARCH_HAVE_IRQTRIGGER) +void up_vintc_trigger_irq(int irq); +#else +static inline void up_vintc_trigger_irq(int irq) +{ +} +#endif + +/**************************************************************************** + * Name: up_vintc_handler + * + * Description: + * This function address must be sent from VINTC on VECTOR input in order + * to let DSP could jump to the appropriate interrupt handler location. + * Note that VINTC may pass this address to the hardware register, but + * ARCH specific code is responsible to implement this function. + * + ****************************************************************************/ + +void up_vintc_handler(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ARCH_CEVA_SRC_COMMON_VINTC_H */ diff --git a/arch/ceva/src/xc5/Kconfig b/arch/ceva/src/xc5/Kconfig new file mode 100644 index 0000000000..cedf186c51 --- /dev/null +++ b/arch/ceva/src/xc5/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +comment "XC5 Configuration Options" + +config XC5_PSU_ENABLE + bool "Enable power management of XC5" + ---help--- + Doze or idle mode of xc5 power managerment. diff --git a/arch/ceva/src/xc5/Toolchain.defs b/arch/ceva/src/xc5/Toolchain.defs new file mode 100644 index 0000000000..8427077fee --- /dev/null +++ b/arch/ceva/src/xc5/Toolchain.defs @@ -0,0 +1,68 @@ +############################################################################ +# arch/ceva/src/xc5/Toolchain.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +RTL_VERSION := $(CONFIG_ARCH_RTL_MAJOR).$(CONFIG_ARCH_RTL_MINOR).$(CONFIG_ARCH_RTL_REVISION) + +ITCM_KB := $(shell expr $(CONFIG_ARCH_ITCM_SIZE) / 1024) +DTCM_KB := $(shell expr $(CONFIG_ARCH_DTCM_SIZE) / 1024) + +# +# Supported toolchains +# +# Each toolchain definition should set: +# +# CROSSDEV The GNU toolchain triple (command prefix) +# ARCROSSDEV If required, an alternative prefix used when +# invoking ar and nm. +# ARCHCPUFLAGS CPU-specific flags selecting the instruction set +# FPU options, etc. +# MAXOPTIMIZATION The maximum optimization level that results in +# reliable code generation. +# + +ARCROSSDEV ?= $(CROSSDEV) +ifneq ($(CROSSDEV),) + export LD_LIBRARY_PATH := $(CROSSDEV):$(LD_LIBRARY_PATH) + export PATH := $(CROSSDEV):$(PATH) + export CEVAXMTOOLS := $(CROSSDEV) +endif + +ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y) + MAXOPTIMIZATION := $(CONFIG_DEBUG_OPTLEVEL) +else ifeq ($(CONFIG_DEBUG_FULLOPT),y) + MAXOPTIMIZATION := -O3 -Os3 +endif + +ARCHCPUFLAGS = -mrtl-version-$(RTL_VERSION) -Wa,-rtl$(RTL_VERSION) +ARCHCPUFLAGS += -Wa,-p -mmsg-full-path -TARG:arch=cevaxc5 -Wa,-vdiv4 -Wno-unused + +LDFLAGS = -alignAllSections,c:0x20,d:0x4 -cevaxc5 -removeUnRefFunc +LDFLAGS += -internalCode$(ITCM_KB) -internalData$(DTCM_KB) + +LIBGCC = $(CROSSDEV)libs/xc5/cevaxclib.lib +LIBGCC += $(CROSSDEV)libs/xc5/libcc.lib + +ifeq ($(CONFIG_WINDOWS_CYGWIN),y) + WINTOOL = y +endif + +CC = $(CROSSDEV)/cevaxccc -mquiet -Wa,-quiet +CXX = $(CROSSDEV)/cevaxccc -mquiet -Wa,-quiet -x c++ +CPP = $(CROSSDEV)/cevaxccc -mquiet -Wa,-quiet -E -P -x c diff --git a/arch/ceva/src/xc5/cpm.S b/arch/ceva/src/xc5/cpm.S new file mode 100644 index 0000000000..e861823540 --- /dev/null +++ b/arch/ceva/src/xc5/cpm.S @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/ceva/src/xc5/cpm.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + + .file "cpm.S" + + .text + .public _getcpm + .func_start 2 _getcpm +_getcpm: + push {dw} r0 + mov a0, r0 + nop + in {dw,cpm} (r0), r0 + nop + nop + nop + mov r0, a0 + pop {dw} r0 + ret + .func_end 2 _getcpm + + .public _putcpm + .func_start 2 _putcpm +_putcpm: + push {dw} r0 + push {dw} r1 + mov a0, r0 + mov a1, r1 + nop + out {dw,cpm} r1, (r0) + pop {dw} r1 + pop {dw} r0 + ret + .func_end 2 _putcpm + + .public _modifycpm + .func_start 2 _modifycpm +_modifycpm: + push {dw} r0 + push {dw} r1 + mov a0, r0 + nop + in {dw,cpm} (r0), r1 + nop + nop + nop + mov r1, a0 + not a1, a1 + and a0, a1, a0 + or a0, a2, a0 + nop + mov a0, r1 + nop + out {dw,cpm} r1, (r0) + pop {dw} r1 + pop {dw} r0 + ret + .func_end 2 _modifycpm diff --git a/arch/ceva/src/xc5/cpm.h b/arch/ceva/src/xc5/cpm.h new file mode 100644 index 0000000000..8e322573ea --- /dev/null +++ b/arch/ceva/src/xc5/cpm.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * arch/ceva/src/xc5/cpm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_XC5_CPM_H +#define __ARCH_CEVA_SRC_XC5_CPM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Inline functions + ****************************************************************************/ +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +uint32_t getcpm(uintptr_t addr); +void putcpm(uintptr_t addr, uint32_t value); +void modifycpm(uintptr_t addr, uint32_t clearbits, uint32_t setbits); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif + +#endif /* __ARCH_CEVA_SRC_XC5_CPM_H */ diff --git a/arch/ceva/src/xc5/psu.h b/arch/ceva/src/xc5/psu.h new file mode 100644 index 0000000000..4110b34ea8 --- /dev/null +++ b/arch/ceva/src/xc5/psu.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/ceva/src/xc5/psu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ARCH_CEVA_SRC_XC5_PSU_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define XC5_DOZE 0x1ff2 +#define XC5_IDLE 0x1ff3 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void up_psu_lp(int value); + +#endif /* __ARCH_CEVA_SRC_XC5_PSU_H */ diff --git a/arch/ceva/src/xc5/syscall.S b/arch/ceva/src/xc5/syscall.S new file mode 100644 index 0000000000..38f89d021e --- /dev/null +++ b/arch/ceva/src/xc5/syscall.S @@ -0,0 +1,78 @@ +/**************************************************************************** + * arch/ceva/src/xc5/syscall.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "syscall.S" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sys_callx + * + * Description: + * This function generate the trap exception with the specified number of + * parameters. + * + * a0 = SYS_ call number + * a1 = parm0 + * a2 = parm1 + * a3 = parm2 + * a4 = parm3 + * a5 = parm4 + * a6 = parm5 + * a7 = parm6 + * + ****************************************************************************/ + + .text + + .public _sys_call0 + .public _sys_call1 + .public _sys_call2 + .public _sys_call3 + .public _sys_call4 + .public _sys_call5 + .public _sys_call6 + + .func_start 2 _sys_call0 + +_sys_call0: +_sys_call1: +_sys_call2: +_sys_call3: +_sys_call4: +_sys_call5: +_sys_call6: + trap0 + nop + ret + + .func_end 2 _sys_call0 diff --git a/arch/ceva/src/xc5/up_hardfault.c b/arch/ceva/src/xc5/up_hardfault.c new file mode 100644 index 0000000000..e944109a7d --- /dev/null +++ b/arch/ceva/src/xc5/up_hardfault.c @@ -0,0 +1,93 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_hardfault.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define REG_P_MAPAR 0x00a0 +#define REG_P_MAPSR 0x00a4 +#define REG_UOP_STS 0x0238 +#define REG_UOP_PAR 0x023c +#define REG_DBG_GEN 0x028c + +#ifdef CONFIG_DEBUG_HARDFAULT +# define hfalert(format, ...) _alert(format, ##__VA_ARGS__) +#else +# define hfalert(x...) +#endif + +#define hfdumpreg1(reg) \ + hfalert("%s: %08x\n", \ + #reg, getcpm(REG_##reg)) + +#define hfdumpreg2(reg1, reg2) \ + hfalert("%s: %08x %s: %08x\n", \ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2)) + +#define hfdumpreg3(reg1, reg2, reg3) \ + hfalert("%s: %08x %s: %08x %s: %08x\n", \ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2), \ + #reg3, getcpm(REG_##reg3)) + +#define hfdumpreg4(reg1, reg2, reg3, reg4) \ + hfalert("%s: %08x %s: %08x %s: %08x %s: %08x\n",\ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2), \ + #reg3, getcpm(REG_##reg3), \ + #reg4, getcpm(REG_##reg4)) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_hardfault + * + * Description: + * This is Hard Fault exception handler. + * + ****************************************************************************/ + +int up_hardfault(int irq, FAR void *context, FAR void *arg) +{ + /* Dump some hard fault info */ + + hfalert("Hard Fault:\n"); + hfdumpreg4(P_MAPAR, P_MAPSR, UOP_STS, UOP_PAR); + hfdumpreg1(REG_DBG_GEN); + + PANIC(); + return OK; +} diff --git a/arch/ceva/src/xc5/up_head.S b/arch/ceva/src/xc5/up_head.S new file mode 100644 index 0000000000..0654c2a46d --- /dev/null +++ b/arch/ceva/src/xc5/up_head.S @@ -0,0 +1,302 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_head.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK == 0 +# undef CONFIG_ARCH_INTERRUPTSTACK +# define CONFIG_ARCH_INTERRUPTSTACK CONFIG_IDLETHREAD_STACKSIZE +#endif + +.MACRO IRQ_HANDLER irq retx + push {dw} retreg + push {16dw,l} r4, a8 + nop + mov #irq, a0 + call {t} INCODE exception_common + pop {16dw,l} r4, a8 + pop {dw} retreg + retx +.ENDM + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "up_head.S" + .extern _g_idle_topstack + .extern _g_idle_basestack + .extern _up_doirq + .extern _up_start + .extern _up_relocate + +/**************************************************************************** + * Interrupt Functions + ****************************************************************************/ + .CSECT inttbl + br {t} reset_handler + + .ORG 0x20 + IRQ_HANDLER IRQ_TRAPE, retb + + .ORG 0x40 + IRQ_HANDLER IRQ_TRAP, reti + + .ORG 0x60 + IRQ_HANDLER IRQ_NMI, retn + + .ORG 0x80 + IRQ_HANDLER IRQ_INT0, reti + + .ORG 0xc0 + IRQ_HANDLER IRQ_INT1, reti + + .ORG 0x100 + IRQ_HANDLER IRQ_INT2, reti + + .ORG 0x140 + IRQ_HANDLER IRQ_INT3, reti + + .ORG 0x180 + IRQ_HANDLER IRQ_INT4, reti + + .ORG 0x200 + IRQ_HANDLER IRQ_TRAP0, reti + + .ORG 0x240 + IRQ_HANDLER IRQ_TRAP1, reti + + .ORG 0x280 + IRQ_HANDLER IRQ_TRAP2, reti + + .ORG 0x2c0 + IRQ_HANDLER IRQ_TRAP3, reti + + .ORG 0x300 + .GLOBAL _up_vintc_handler +_up_vintc_handler: + IRQ_HANDLER IRQ_VINT, reti + + .CSECT resetsec +reset_handler: + mov #0x0, mod0 + mov #0x0, mod1 + mov #0x0, mod2 + mov modg, a0 + and a0, #0x300, a0 + or a0, #0x0000001b, a0 + mov a0, modg + mov #0xf0, modpb + ld {dw} (#_g_idle_topstack), a0 + nop + nop + nop + nop + mov a0, sp + nop + nop + push {dw} retreg + callr {t} _up_relocate + pop {dw} retreg + brr {t} _up_start + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Common exception handling logic, need sync with: + * arch/ceva/include/xc5/reg.h + */ + .func_start 3 exception_common + +exception_common: + /* Note: a0 contain exception number + * Complete the context save + */ + + push {16dw,h} auxreg1 + push {16dw,h} r4, a8 + push {dw} mod3 + push {4dw} modx + bkst + push {16dw,h} auxreg0 + push {16dw,h} auxreg2 + push {16dw,l} auxreg1 + push {16dw,l} auxreg0 + push {16dw,l} auxreg2 + nop + +/*#ifndef CONFIG_ARCH_XC5_NO_VPU + vpush{8dw} via0 + vpush{8dw} vib0 + vpush{8dw} vic0 + vpush{8dw} vid0 + vpush{8dw} vie0 + vpush{8dw} vif0 + vpush{8dw} vig0 + vpush{8dw} vih0 + vpush{8dw} voa0e + vpush{8dw} voa0 + vpush{8dw} vob0e + vpush{8dw} vob0 + vpush{8dw} vc0 + vpush{8dw} vpr0 + vpush{dw} modv0 + vpush{dw} modv1 +#endif*/ + + mov lci0, g4 + mov lci1, g5 || bkst + mov lci2, g6 + mov lci3, g7 + mov lcstep0, modu2 + mov lcstep1, modu3 + push {8dw} auxreg1 + nop + bkst + push {dw} bknest0 + push {dw} bknest1 + bkst + push {dw} bknest0 + push {dw} bknest1 + nop + nop + nop + + subsps #1 + nop + mov sp, r0 + nop + st {dw} sp, (r0) + + /* Prepare the C language environment */ + mov #0x0, mod0 + mov #0x0, mod1 + mov #0x0, mod2 + mov modg, a1 + and a1, #0x300, a1 + or a1, #0x0000001b, a1 + mov a1, modg + + /* There are two arguments to up_doirq: + * + * a0 = The IRQ number + * r0 = The top of the stack points to the saved state + */ + + /* Switch to the dedicated stack */ + + mov #_g_intstackbase, r1 + nop + mov r1, sp + nop + nop + + push {dw} retreg + mov #_up_doirq, r1 + nop + nop + callar r1 + pop {dw} retreg + + /* On return from up_doirq, r0 will hold a pointer to register context + * array to use for the interrupt return. + */ + + mov r0, sp + addsps #1 + nop + nop + + /* Unwind the same stack frame that we created at entry */ + + pop {dw} bknest1 + pop {dw} bknest0 + nop + nop + bkrest + pop {dw} bknest1 + pop {dw} bknest0 + nop + nop + bkrest + pop {8dw} auxreg1 + nop + nop + nop + bkrest + mov modu3, lcstep1 + mov modu2, lcstep0 + mov g7, lci3 + mov g6, lci2 + mov g5, lci1 + mov g4, lci0 + +/*#ifndef CONFIG_ARCH_XC5_NO_VPU + vpop{dw} modv1 + vpop{dw} modv0 + vpop{8dw} vpr0 + vpop{8dw} vc0 + vpop{8dw} vob0 + vpop{8dw} vob0e + vpop{8dw} voa0 + vpop{8dw} voa0e + vpop{8dw} vih0 + vpop{8dw} vig0 + vpop{8dw} vif0 + vpop{8dw} vie0 + vpop{8dw} vid0 + vpop{8dw} vic0 + vpop{8dw} vib0 + vpop{8dw} via0 +#endif*/ + + pop {16dw,l} auxreg2 + pop {16dw,l} auxreg0 + pop {16dw,l} auxreg1 + nop + nop + pop {16dw,h} auxreg2 + pop {16dw,h} auxreg0 + pop {4dw} modx + pop {dw} mod3 + pop {16dw,h} r4, a8 + bkrest + pop {16dw,h} auxreg1 + + ret + + .func_end 3 exception_common + + .bss + .public _g_intstackalloc + .public _g_intstackbase +_g_intstackalloc: + DD CONFIG_ARCH_INTERRUPTSTACK/4 dup ? +_g_intstackbase: diff --git a/arch/ceva/src/xc5/up_icache.c b/arch/ceva/src/xc5/up_icache.c new file mode 100644 index 0000000000..028f10496d --- /dev/null +++ b/arch/ceva/src/xc5/up_icache.c @@ -0,0 +1,294 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_icache.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MSS_PCR 0x0000 +#define P_ADD0_ATT0 0x0014 +#define P_CCOSAR 0x0090 +#define P_CCOCR 0x0094 +#define MSS_HDCFG 0x021c + +#define MSS_PCR_CAC_PFE 0x00000004 + +#define P_ADD0_ATT0_L1IC 0x00000001 +#define P_ADD0_ATT0_L1IC_LOCK 0x00000002 + +#define P_CCOCR_L1ICO 0x00000002 +#define P_CCOCR_OT_PREFETCH 0x00000004 +#define P_CCOCR_OT_LOCK 0x00000008 +#define P_CCOCR_OT_UNLOCK 0x0000000c +#define P_CCOCR_OT_INVALIDATE 0x00000010 +#define P_CCOCR_OT_MASK 0x0000003c +#define P_CCOCR_OS_ENTIRE 0x00000080 +#define P_CCOCR_NOBPL_SHIFT 16 +#define P_CCOCR_NOBPL_MASK 0xffff0000 + +#define MSS_HDCFG_PCAC_SZE_0KB 0x00000000 +#define MSS_HDCFG_PCAC_SZE_32KB 0x00001000 +#define MSS_HDCFG_PCAC_SZE_64KB 0x00002000 +#define MSS_HDCFG_PCAC_SZE_128KB 0x00003000 +#define MSS_HDCFG_PCAC_SZE_MASK 0x00007000 + +#define MSS_CACHE_BLOCK_SIZE 64 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_CEVA_ICACHE +static void maintain_icache_all(uint32_t op) +{ + irqstate_t flags; + + /* Disable irq */ + + flags = up_irq_save(); + + /* Start the operation on the entire cache */ + + putcpm(P_CCOCR, P_CCOCR_L1ICO | op | P_CCOCR_OS_ENTIRE); + + while (getcpm(P_CCOCR) & P_CCOCR_L1ICO) + { + /* Loop until the operation finish */; + } + + /* Restore irq */ + + up_irq_restore(flags); +} + +static void maintain_icache(uint32_t op, uintptr_t start, uintptr_t end) +{ + static size_t op_maxblocks; + + /* Initialize op_maxblocks if not yet */ + + if (op_maxblocks == 0) + { + switch (getcpm(MSS_HDCFG) & MSS_HDCFG_PCAC_SZE_MASK) + { + case MSS_HDCFG_PCAC_SZE_32KB: + op_maxblocks = 512; + break; + case MSS_HDCFG_PCAC_SZE_64KB: + op_maxblocks = 1024; + break; + case MSS_HDCFG_PCAC_SZE_128KB: + op_maxblocks = 2048; + break; + default: + op_maxblocks = 1; + break; + } + } + + /* Align the address to the cache block boundary */ + + start &= ~(MSS_CACHE_BLOCK_SIZE - 1); + end += (MSS_CACHE_BLOCK_SIZE - 1); + end &= ~(MSS_CACHE_BLOCK_SIZE - 1); + + /* Skip dtcm since it never put into dcache */ + + if (end > CONFIG_ARCH_ITCM_SIZE) + { + if (start < CONFIG_ARCH_ITCM_SIZE) + { + start = CONFIG_ARCH_ITCM_SIZE; + } + + while (start < end) + { + irqstate_t flags; + size_t op_blocks; + + /* Get the max blocks we can do in one iteration */ + + op_blocks = (end - start) / MSS_CACHE_BLOCK_SIZE; + if (op_blocks > op_maxblocks) + { + op_blocks = op_maxblocks; + } + + /* Disable irq */ + + flags = up_irq_save(); + + /* Set the cache address */ + + putcpm(P_CCOSAR, start); + + /* Start the cache operation */ + + putcpm(P_CCOCR, /* Address based operation */ + P_CCOCR_L1ICO | op | (op_blocks << P_CCOCR_NOBPL_SHIFT)); + + while (getcpm(P_CCOCR) & P_CCOCR_L1ICO) + { + /* Loop until the operation finish */; + } + + /* Restore irq */ + + up_irq_restore(flags); + + /* Prepare the next loop */ + + start += op_blocks * MSS_CACHE_BLOCK_SIZE; + } + } +} + +/**************************************************************************** + * Name: up_enable_icache + * + * Description: + * Enable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void up_enable_icache(void) +{ + /* Invalidate the entire icache */ + + maintain_icache_all(P_CCOCR_OT_INVALIDATE); + + /* Enable prefetch */ + + modifycpm(MSS_PCR, 0, MSS_PCR_CAC_PFE); + + /* Enable icache and disable lock */ + + modifycpm(P_ADD0_ATT0, P_ADD0_ATT0_L1IC_LOCK, P_ADD0_ATT0_L1IC); +} + +/**************************************************************************** + * Name: up_disable_icache + * + * Description: + * Disable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_disable_icache(void) +{ + /* Disable icache */ + + modifycpm(P_ADD0_ATT0, P_ADD0_ATT0_L1IC, 0); + + /* Invalidate the entire icache */ + + maintain_icache_all(P_CCOCR_OT_INVALIDATE); +} + +/**************************************************************************** + * Name: up_invalidate_icache + * + * Description: + * Invalidate the instruction cache within the specified region. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache(uintptr_t start, uintptr_t end) +{ + maintain_icache(P_CCOCR_OT_INVALIDATE, start, end); +} + +/**************************************************************************** + * Name: up_invalidate_icache_all + * + * Description: + * Invalidate the entire contents of I cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache_all(void) +{ + maintain_icache_all(P_CCOCR_OT_INVALIDATE); +} + +/**************************************************************************** + * Name: up_coherent_dcache + * + * Description: + * Ensure that the I and D caches are coherent within specified region + * by cleaning the D cache (i.e., flushing the D cache contents to memory + * and invalidating the I cache. This is typically used when code has been + * written to a memory region, and will be executed. + * + * Input Parameters: + * addr - virtual start address of region + * len - Size of the address region in bytes + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_coherent_dcache(uintptr_t addr, size_t len) +{ + /* Invalidate instruction cache is enough */ + + up_invalidate_icache(addr, addr + len); +} +#endif diff --git a/arch/ceva/src/xc5/up_initialstate.c b/arch/ceva/src/xc5/up_initialstate.c new file mode 100644 index 0000000000..8a86f98e21 --- /dev/null +++ b/arch/ceva/src/xc5/up_initialstate.c @@ -0,0 +1,88 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_initialstate.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_initial_state + * + * Description: + * A new thread is being started and a new TCB + * has been created. This function is called to initialize + * the processor specific portions of the new TCB. + * + * This function must setup the intial architecture registers + * and/or stack so that execution will begin at tcb->start + * on the next context switch. + * + ****************************************************************************/ + +void up_initial_state(struct tcb_s *tcb) +{ + struct xcptcontext *xcp = &tcb->xcp; + + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + + if (tcb->adj_stack_ptr) + { + xcp->regs = tcb->adj_stack_ptr - XCPTCONTEXT_SIZE; + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); + + /* Save the initial stack pointer */ + + xcp->regs[REG_SP] = (uint32_t)xcp->regs; + + /* Save the task entry point */ + + xcp->regs[REG_PC] = (uint32_t)tcb->start; + + /* Initialize all no zero registers */ + + xcp->regs[REG_MODP] = REG_MODP_DEFAULT; + + /* Initialize modg for saturation setting */ + + xcp->regs[REG_MODG] = REG_MODG_DEFAULT; + + /* All tasks start via a stub function in kernel space. + * So all tasks must start in privileged thread mode. + * If CONFIG_BUILD_PROTECTED is defined, + * then that stub function will switch to unprivileged + * mode before transferring control to the user task. + */ + + xcp->regs[REG_OM] = REG_OM_DEFAULT; + } +} diff --git a/arch/ceva/src/xc5/up_intc.c b/arch/ceva/src/xc5/up_intc.c new file mode 100644 index 0000000000..dffe36ac78 --- /dev/null +++ b/arch/ceva/src/xc5/up_intc.c @@ -0,0 +1,201 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_intc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" +#include "up_internal.h" +#include "vintc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * This function implements disabling of the device specified by 'irq' + * at the interrupt controller level if supported by the architecture + * (up_irq_save() supports the global level, the device level is hardware + * specific). + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_disable_irq(irq); + } + else if (irq >= IRQ_TRAP0) + { + switch (irq) + { + case IRQ_TRAP0: + __asm__ __volatile__("rst #0x01, imaskt"); + break; + case IRQ_TRAP1: + __asm__ __volatile__("rst #0x02, imaskt"); + break; + case IRQ_TRAP2: + __asm__ __volatile__("rst #0x04, imaskt"); + break; + case IRQ_TRAP3: + __asm__ __volatile__("rst #0x08, imaskt"); + break; + } + } +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * On many architectures, there are three levels of interrupt enabling: (1) + * at the global level, (2) at the level of the interrupt controller, + * and (3) at the device level. In order to receive interrupts, they + * must be enabled at all three levels. + * + * This function implements enabling of the device specified by 'irq' + * at the interrupt controller level if supported by the architecture + * (up_irq_restore() supports the global level, the device level is + * hardware specific). + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + /* Note: All INTx is enabled by REG_MODA_DEFAULT */ + + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_enable_irq(irq); + } + else if (irq >= IRQ_TRAP0) + { + switch (irq) + { + case IRQ_TRAP0: + __asm__ __volatile__("set #0x01, imaskt"); + break; + case IRQ_TRAP1: + __asm__ __volatile__("set #0x02, imaskt"); + break; + case IRQ_TRAP2: + __asm__ __volatile__("set #0x04, imaskt"); + break; + case IRQ_TRAP3: + __asm__ __volatile__("set #0x08, imaskt"); + break; + } + } +} + +/**************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQPRIO +int up_prioritize_irq(int irq, int priority) +{ + int ret = -EINVAL; + + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + ret = up_vintc_prioritize_irq(irq, priority); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: up_trigger_irq + * + * Description: + * Trigger an IRQ by software. May not be supported by all architectures. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_IRQTRIGGER +void up_trigger_irq(int irq) +{ + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_trigger_irq(irq); + } +} +#endif /* CONFIG_ARCH_HAVE_IRQTRIGGER */ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + /* Initialize the secondary interrupt controller */ + + up_vintc_initialize(); + + /* Attach and enable SVCall exception handler */ + + irq_attach(IRQ_TRAP0, up_svcall, NULL); + up_enable_irq(IRQ_TRAP0); + + /* Attach and enable Hard Fault exception handler */ + +#if CONFIG_ARCH_HARDFAULT_IRQ >= 0 + irq_attach(CONFIG_ARCH_HARDFAULT_IRQ, up_hardfault, NULL); + up_enable_irq(CONFIG_ARCH_HARDFAULT_IRQ); +#endif + + /* And finally, enable interrupts */ + + up_irq_enable(); +} diff --git a/arch/ceva/src/xc5/up_mpu.c b/arch/ceva/src/xc5/up_mpu.c new file mode 100644 index 0000000000..a5510a8f62 --- /dev/null +++ b/arch/ceva/src/xc5/up_mpu.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_mpu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "cpm.h" +#include "mpu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ARCH_MPU + +/**************************************************************************** + * Name: mpu_control + * + * Description: + * Configure and enable (or disable) the MPU + * + ****************************************************************************/ + +void mpu_control(bool enable) +{ +} + +/**************************************************************************** + * Name: mpu_user_code + * + * Description: + * Configure a region for user code + * + ****************************************************************************/ + +void mpu_user_code(const void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_priv_code + * + * Description: + * Configure a region for privileged code + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_code(const void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_user_data + * + * Description: + * Configure a region as user data + * + ****************************************************************************/ + +void mpu_user_data(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_priv_data + * + * Description: + * Configure a region as privileged data + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_data(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_peripheral + * + * Description: + * Configure a region as privileged peripheral address space + * + ****************************************************************************/ + +void mpu_peripheral(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_stronglyordered + * + * Description: + * Configure a region for privileged, strongly ordered memory + * + ****************************************************************************/ + +void mpu_stronglyordered(void *base, size_t size) +{ +} + +#endif diff --git a/arch/ceva/src/xc5/up_psu.c b/arch/ceva/src/xc5/up_psu.c new file mode 100644 index 0000000000..81b664457d --- /dev/null +++ b/arch/ceva/src/xc5/up_psu.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_psu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* disable psu function temporily */ + +#define CONFIG_XC5_PSU_ENABLE + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if CONFIG_XC5_PSU_ENABLE +static void up_cpu_pmod(uint32_t psvm) +{ + /* Core auto restore to DPS here after wakeup */ + + __asm__ __volatile__ + ( + "mov #0x2, mod2\n" + "mov #0x3f80, modp\n" /* Enable the interrupt */ + "mov %0, r0\n" /* Enter the low power mode */ + "mov #0x250, r1\n" + "out {dw,cpm} r0, (r1)\n" /* output to cpm register psmv */ + "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" + "mov #0x0080, modp" /* restore the interrupt */ + : : "r"(psvm) + ); +} +#else +static void up_cpu_pmod(uint32_t psvm) +{ +} +#endif /* CONFIG_XC5_PSU_ENABLE */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void up_psu_lp(int value) +{ + up_cpu_pmod(value); +} diff --git a/arch/ceva/src/xc5/up_relocate.c b/arch/ceva/src/xc5/up_relocate.c new file mode 100644 index 0000000000..7b8607d455 --- /dev/null +++ b/arch/ceva/src/xc5/up_relocate.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_relocate.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "cpm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MSS_PDEA 0x004 +#define MSS_PDIA 0x008 +#define MSS_PDTC 0x00c +#define MSS_PDTC_MASK 0xfffff +#define MSS_PDTC_PDST (1 << 29) +#define MSS_DDEA 0x208 +#define MSS_DDIA 0x20c +#define MSS_DDTC 0x210 +#define MSS_DDTC_MASK 0x1fffff +#define MSS_DDTC_PDST (1 << 29) +#define MSS_DDTC_BSZ_SHIFT 25 +#define MSS_DDTC_DDIR_SHIFT 30 + +#define BSZ_1_TRANS (0 << MSS_DDTC_BSZ_SHIFT) +#define BSZ_4_TRANS (6 << MSS_DDTC_BSZ_SHIFT) +#define BSZ_8_TRANS (10 << MSS_DDTC_BSZ_SHIFT) +#define BSZ_16_TRANS (14 << MSS_DDTC_BSZ_SHIFT) + +#define DDIR_EX2IN (0 << MSS_DDTC_DDIR_SHIFT) +#define DDIR_IN2EX (1 << MSS_DDTC_DDIR_SHIFT) + +#define _START_INTTBL ((void *)&_sinttbl) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern char _sinttbl; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void pdma_config(unsigned long iaddr, unsigned long eaddr, + uint32_t count) +{ + putcpm(MSS_PDIA, iaddr); + putcpm(MSS_PDEA, eaddr); + putcpm(MSS_PDTC, count & MSS_PDTC_MASK); +} + +static void pdma_wait_idle(void) +{ + while (getcpm(MSS_PDTC) & MSS_PDTC_PDST); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void up_relocate(void) +{ + pdma_config(0, (unsigned long)_START_INTTBL, 0x320); + pdma_wait_idle(); +} diff --git a/arch/ceva/src/xc5/up_signal_handler.S b/arch/ceva/src/xc5/up_signal_handler.S new file mode 100644 index 0000000000..8d29ba57e6 --- /dev/null +++ b/arch/ceva/src/xc5/up_signal_handler.S @@ -0,0 +1,99 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_signal_handler.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "svcall.h" + +#if (defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__)) && \ + !defined(CONFIG_DISABLE_SIGNALS) + +/**************************************************************************** + * File info + ****************************************************************************/ + + .file "up_signal_handler.S" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_dispatch() in user-mode. + * + * Input Parameters: + * r0 = sighand + * The address user-space signal handling function + * r1, r2, r3 = signo, info, and ucontext + * Standard arguments to be passed to the signal handling function. + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via the SYS_signal_handler_return (see svcall.h) + * + ****************************************************************************/ + + .text + .public _up_signal_handler + .func_start 3 _up_signal_handler + +_up_signal_handler: + + /* Save some register */ + + push retreg.ui /* Save LR on the stack */ + push {dw} retreg + /* Call the signal handler */ + + mov a0, a4 /* r4=sighand */ + mov a1, a0 /* r0=signo */ + mov a2, a1 /* r1=info */ + mov a3, a2 /* r2=ucontext */ + mov a4, r4 + nop + nop + nop + callar r4 /* Call the signal handler */ + + /* Restore the registers */ + + pop {dw} retreg + + /* Execute the SYS_signal_handler_return SVCall (will not return) */ + + mov #SYS_signal_handler_return, a0 + trap + + .func_end 3 _up_signal_handler + +#else /* Add dummy symbol to avoid cofflib crash */ + + .text +dummy_signal_handler: + +#endif diff --git a/arch/ceva/src/xc5/up_svcall_handler.S b/arch/ceva/src/xc5/up_svcall_handler.S new file mode 100644 index 0000000000..e955c5c58e --- /dev/null +++ b/arch/ceva/src/xc5/up_svcall_handler.S @@ -0,0 +1,110 @@ +/**************************************************************************** + * arch/ceva/src/xc5/up_svcall_handler.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "svcall.h" + +#ifdef CONFIG_LIB_SYSCALL + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "up_svcall_handler.S" + .extern _g_stublookup + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_svcall_handler + * + * Description: + * This function is the kernel-space, syscall handler trampoline function. It + * is called from up_svcall() in interrupt handler. + * + * Call the stub function corresponding to the system call. NOTE the non- + * standard parameter passing: + * + * r0 = SYS_ call number + * r1 = parm0 + * r2 = parm1 + * r3 = parm2 + * r4 = parm3 + * r5 = parm4 + * r6 = parm5 + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via the SYS_syscall_return (see svcall.h) + * + ****************************************************************************/ + + .text + .public _up_svcall_handler + .func_start 3 _up_svcall_handler + +_up_svcall_handler: + + /* Create a stack frame to hold LR */ + + push {dw} retreg + + /* Call the stub function */ + + mov #_g_stublookup, a8 + shift #0x02, a8 + add a8, a8 + nop + nop + mov a8, r4 + ld {dw} (r4), a8 + nop + nop + nop + nop + nop + mov a8, r4 + callar r4 + + /* Destroy the stack frame */ + + pop {dw} retreg + + /* Execute the SYS_syscall_return SVCall (will not return) */ + /* Save return value in r2 */ + mov a0, a2 /* will restore in up_svcall */ + mov #SYS_syscall_return, a0 + trap + + .func_end 3 _up_svcall_handler + +#else /* Add dummy symbol to avoid cofflib crash */ + + .text +dummy_svcall_handler: + +#endif /* CONFIG_LIB_SYSCALL */ diff --git a/arch/ceva/src/xc5/vfork.S b/arch/ceva/src/xc5/vfork.S new file mode 100644 index 0000000000..7a125ab46b --- /dev/null +++ b/arch/ceva/src/xc5/vfork.S @@ -0,0 +1,112 @@ +/**************************************************************************** + * arch/ceva/src/xc5/vfork.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "vfork.S" + .extern _up_vfork + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vfork + * + * Description: + * The vfork() function has the same effect as fork(), except that the behavior is + * undefined if the process created by vfork() either modifies any data other than + * a variable of type pid_t used to store the return value from vfork(), or returns + * from the function in which vfork() was called, or calls any other function before + * successfully calling _exit() or one of the exec family of functions. + * + * This thin layer implements vfork by simply calling up_vfork() with the vfork() + * context as an argument. The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_vfork()and calls nxtask_vforksetup(). + * 3) task_vforksetup() allocates and configures the child task's TCB. This + * consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Setup the intput parameters for the task. + * - Initialization of the TCB (including call to up_initial_state() + * 4) up_vfork() provides any additional operating context. up_vfork must: + * - Allocate and initialize the stack + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) up_vfork() then calls nxtask_vforkstart() + * 6) nxtask_vforkstart() then executes the child thread. + * + * Input Paremeters: + * None + * + * Return: + * Upon successful completion, vfork() returns 0 to the child process and returns + * the process ID of the child process to the parent process. Otherwise, -1 is + * returned to the parent, no child process is created, and errno is set to + * indicate the error. + * + ****************************************************************************/ + + .text + .public _vfork + .func_start 3 _vfork + +_vfork: + /* Create a stack frame */ + + subs sp, #XCPTCONTEXT_SIZE, sp + + /* Save the volatile registers by svcall(SYS_save_context) */ + + mov #SYS_save_context, a0 + mov sp, a1 + trap + + /* Then, call up_vfork(), passing it a pointer to the stack structure */ + + mov sp, a0 + nop + push {dw} retreg + callr {t} _up_vfork + pop {dw} retreg + nop + + /* Release the stack data and return the value returned by up_vfork */ + + adds sp, #XCPTCONTEXT_SIZE, sp + + ret + + .func_end 3 _vfork diff --git a/arch/ceva/src/xm6/Kconfig b/arch/ceva/src/xm6/Kconfig new file mode 100644 index 0000000000..cb0f20f536 --- /dev/null +++ b/arch/ceva/src/xm6/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +comment "XM6 Configuration Options" + +config ARCH_XM6_BUG001 + bool "Enable bug 001 workaround" + ---help--- + Read CEVA-XM6 Bug List for more information diff --git a/arch/ceva/src/xm6/Toolchain.defs b/arch/ceva/src/xm6/Toolchain.defs new file mode 100644 index 0000000000..14190aac8d --- /dev/null +++ b/arch/ceva/src/xm6/Toolchain.defs @@ -0,0 +1,73 @@ +############################################################################ +# arch/ceva/src/xm6/Toolchain.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +RTL_VERSION := $(CONFIG_ARCH_RTL_MAJOR).$(CONFIG_ARCH_RTL_MINOR).$(CONFIG_ARCH_RTL_REVISION) + +ITCM_KB := $(shell expr $(CONFIG_ARCH_ITCM_SIZE) / 1024) +DTCM_KB := $(shell expr $(CONFIG_ARCH_DTCM_SIZE) / 1024) + +# +# Supported toolchains +# +# Each toolchain definition should set: +# +# CROSSDEV The GNU toolchain triple (command prefix) +# ARCROSSDEV If required, an alternative prefix used when +# invoking ar and nm. +# ARCHCPUFLAGS CPU-specific flags selecting the instruction set +# FPU options, etc. +# MAXOPTIMIZATION The maximum optimization level that results in +# reliable code generation. +# + +ARCROSSDEV ?= $(CROSSDEV) +ifneq ($(CROSSDEV),) + export LD_LIBRARY_PATH := $(CROSSDEV):$(LD_LIBRARY_PATH) + export PATH := $(CROSSDEV):$(PATH) + export CEVAXMTOOLS := $(CROSSDEV) +endif + +ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y) + MAXOPTIMIZATION := $(CONFIG_DEBUG_OPTLEVEL) +else ifeq ($(CONFIG_DEBUG_FULLOPT),y) + MAXOPTIMIZATION := -O3 -Os3 +endif + +ARCHCPUFLAGS = -mrtl-version-$(RTL_VERSION) -Wa,-rtl$(RTL_VERSION) +ARCHCPUFLAGS += -Wa,-p + +LDFLAGS = -alignAllSections,c:0x20,d:0x20 +LDFLAGS += -internalCode$(ITCM_KB) -internalData$(DTCM_KB) + +LIBGCC = $(CROSSDEV)libs/cevaxm6/cevaxm6lib.lib +LIBGCC += $(CROSSDEV)libs/cevaxm6/complexlib.lib +LIBGCC += $(CROSSDEV)libs/cevaxm6/libcc.lib + +ifneq ($(CONFIG_ARCH_NR_FPUS),) + ARCHCPUFLAGS += -CG:SPU_FP_num=$(CONFIG_ARCH_NR_FPUS) -Wa,-fp=$(CONFIG_ARCH_NR_FPUS) +endif + +ifeq ($(CONFIG_WINDOWS_CYGWIN),y) + WINTOOL = y +endif + +CC = $(CROSSDEV)/cevaxm6cc -mquiet -Wa,-quiet +CXX = $(CROSSDEV)/cevaxm6cc -mquiet -Wa,-quiet -x c++ +CPP = $(CROSSDEV)/cevaxm6cc -mquiet -Wa,-quiet -E -P -x c diff --git a/arch/ceva/src/xm6/cpm.h b/arch/ceva/src/xm6/cpm.h new file mode 100644 index 0000000000..167476810f --- /dev/null +++ b/arch/ceva/src/xm6/cpm.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * arch/ceva/src/xm6/cpm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_CEVA_SRC_XM6_CPM_H +#define __ARCH_CEVA_SRC_XM6_CPM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +static inline uint32_t getcpm(uintptr_t addr) +{ + return in(cpm, (const volatile uint32_t *)addr); +} + +static inline void putcpm(uintptr_t addr, uint32_t value) +{ + out(cpm, value, (volatile uint32_t *)addr); +} + +static inline void modifycpm(uintptr_t addr, uint32_t clearbits, + uint32_t setbits) +{ + putcpm(addr, (getcpm(addr) & ~clearbits) | setbits); +} + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_CEVA_SRC_XM6_CPM_H */ diff --git a/arch/ceva/src/xm6/syscall.S b/arch/ceva/src/xm6/syscall.S new file mode 100644 index 0000000000..0026a7a880 --- /dev/null +++ b/arch/ceva/src/xm6/syscall.S @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/ceva/src/xm6/syscall.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +.IF CONFIG_ARCH_XM6_BUG001 + .EQU prx pr14 +.ELSE + .EQU prx pr15 +.ENDIF + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "syscall.S" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sys_callx + * + * Description: + * This function generate the trap exception with the specified number of + * parameters. + * + * r0 = SYS_ call number + * r1 = parm0 + * r2 = parm1 + * r3 = parm2 + * r4 = parm3 + * r5 = parm4 + * r6 = parm5 + * + ****************************************************************************/ + + .text + + .public _sys_call0 + .public _sys_call1 + .public _sys_call2 + .public _sys_call3 + .public _sys_call4 + .public _sys_call5 + .public _sys_call6 + + .func_start 3 _sys_call0 + +_sys_call0: +_sys_call1: +_sys_call2: +_sys_call3: +_sys_call4: +_sys_call5: +_sys_call6: + trap {t0} + nop + ret ?prx.b + + .func_end 3 _sys_call0 diff --git a/arch/ceva/src/xm6/up_hardfault.c b/arch/ceva/src/xm6/up_hardfault.c new file mode 100644 index 0000000000..367b2f16ec --- /dev/null +++ b/arch/ceva/src/xm6/up_hardfault.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_hardfault.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define REG_P_ECADD 0x051c +#define REG_P_MAPAR 0x0520 +#define REG_P_MAPSR 0x0524 +#define REG_P_MECCCOR 0x0530 +#define REG_D_ECCCOR 0x0784 +#define REG_D_ECCERR 0x0788 +#define REG_D_MECCCOR 0x078c +#define REG_D_MECCERR 0x0790 +#define REG_D_SECCCOR 0x0794 +#define REG_D_SECCERR 0x0798 +#define REG_UOP_STS 0x0c58 +#define REG_UOP_PAR 0x0c5c +#define REG_MAPAR 0x0c80 +#define REG_MAPSR 0x0c84 +#define REG_DBG_GEN 0x0d14 +#define REG_DBG_GEN_2 0x0d24 +#define REG_DBG_DUNMPD 0x0d30 +#define REG_HIST_OVERFLOW 0x0d4c +#define REG_DBG_DESC_ID 0x0d84 +#define REG_DBG_QMAN_ID 0x0d88 + +#ifdef CONFIG_DEBUG_HARDFAULT +# define hfalert(format, ...) _alert(format, ##__VA_ARGS__) +#else +# define hfalert(x...) +#endif + +#define hfdumpreg1(reg) \ + hfalert("%s: %08x\n", \ + #reg, getcpm(REG_##reg)) + +#define hfdumpreg2(reg1, reg2) \ + hfalert("%s: %08x %s: %08x\n", \ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2)) + +#define hfdumpreg3(reg1, reg2, reg3) \ + hfalert("%s: %08x %s: %08x %s: %08x\n", \ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2), \ + #reg3, getcpm(REG_##reg3)) + +#define hfdumpreg4(reg1, reg2, reg3, reg4) \ + hfalert("%s: %08x %s: %08x %s: %08x %s: %08x\n",\ + #reg1, getcpm(REG_##reg1), \ + #reg2, getcpm(REG_##reg2), \ + #reg3, getcpm(REG_##reg3), \ + #reg4, getcpm(REG_##reg4)) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_hardfault + * + * Description: + * This is Hard Fault exception handler. + * + ****************************************************************************/ + +int up_hardfault(int irq, FAR void *context, FAR void *arg) +{ + /* Dump some hard fault info */ + + hfalert("Hard Fault:\n"); + hfdumpreg4(P_ECADD P_MAPAR, P_MAPSR, P_MECCCOR); + hfdumpreg4(D_ECCCOR, D_ECCERR, D_MECCCOR, D_MECCERR); + hfdumpreg4(D_SECCCOR, D_SECCERR, UOP_STS, UOP_PAR); + hfdumpreg4(MAPAR, MAPSR, DBG_GEN, DBG_GEN_2); + hfdumpreg4(DBG_DUNMPD, HIST_OVERFLOW, DBG_DESC_ID, DBG_QMAN_ID); + + PANIC(); + return OK; +} diff --git a/arch/ceva/src/xm6/up_head.S b/arch/ceva/src/xm6/up_head.S new file mode 100644 index 0000000000..adbbb7caa5 --- /dev/null +++ b/arch/ceva/src/xm6/up_head.S @@ -0,0 +1,229 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_head.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK == 0 +# undef CONFIG_ARCH_INTERRUPTSTACK +# define CONFIG_ARCH_INTERRUPTSTACK CONFIG_IDLETHREAD_STACKSIZE +#endif + +.IF CONFIG_ARCH_XM6_BUG001 + .EQU prx pr14 +.ELSE + .EQU prx pr15 +.ENDIF + +.MACRO IRQ_HANDLER irq retx + push {auxreg10} + push {auxreg2} + mov #irq, r0.ui + callr #exception_common, ?prx.b + pop {auxreg10} + nop #0x04 + retx +.ENDM + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "up_head.S" + .extern _g_idle_topstack + .extern _g_idle_basestack + .extern _up_doirq + .extern _up_start + +/**************************************************************************** + * Interrupt Functions + ****************************************************************************/ + + .CSECT inttbl +.IF CONFIG_ARCH_XM6_BUG001 + cmp {eq} r0.ui, r0.ui, prx.b2, pr15.b2 +.ENDIF + br #reset_handler, #0x00, #0x00, ?prx.b + + .ORG 0x20 + IRQ_HANDLER IRQ_TRAPE, retb + + .ORG 0x40 + IRQ_HANDLER IRQ_TRAP, reti + + .ORG 0x60 + IRQ_HANDLER IRQ_NMI, retn + + .ORG 0x80 + IRQ_HANDLER IRQ_INT0, reti + + .ORG 0xc0 + IRQ_HANDLER IRQ_INT1, reti + + .ORG 0x100 + IRQ_HANDLER IRQ_INT2, reti + + .ORG 0x140 + IRQ_HANDLER IRQ_INT3, reti + + .ORG 0x180 + IRQ_HANDLER IRQ_INT4, reti + + .ORG 0x1c0 + .GLOBAL _up_vintc_handler +_up_vintc_handler: + IRQ_HANDLER IRQ_VINT, reti + + .ORG 0x200 + IRQ_HANDLER IRQ_TRAP0, reti + + .ORG 0x240 + IRQ_HANDLER IRQ_TRAP1, reti + + .ORG 0x280 + IRQ_HANDLER IRQ_TRAP2, reti + + .ORG 0x2c0 + IRQ_HANDLER IRQ_TRAP3, reti + +reset_handler: + /* Tricky for compiler bug: when codes are placed onto ddr memory, label + * address will be place at the back of its first code line, so when branch + * to this label, its first code line will be skipped. + */ + nop + nop + nop + nop + + /* Initialize the C language environment */ + ld (#_g_idle_topstack).ui, r0.ui + mov r0.ui, sp.ui + + br #_up_start, #0x00, #0x00, ?prx.b + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Common exception handling logic, need sync with: + * arch/ceva/include/xm6/reg.h + */ + + .func_start 3 exception_common + +exception_common: + /* Tricky for compiler bug: when codes are placed onto ddr memory, label address + * will be placed at the back of its first code line, so when branch to + * to this label, its first code line will be skipped. + */ + nop + nop + nop + nop + + /* Note: r0 contain exception number + * Complete the context save + */ + + push {auxreg3} + push {auxreg4} + push {auxreg5} + push {auxreg6} + push {auxreg7} + push {auxreg8} + push {auxreg9} + + push moda.ui + push modc.ui + push modd.ui + push mode.ui + push modg.ui + push modi.ui + + modr (sp.ui).ui +#-4 + mov sp.ui, r1.ui + st r1.ui, (r1.ui).ui + + /* Prepare the C language environment */ + + lbf {sv} #0x00 + + /* There are two arguments to up_doirq: + * + * r0 = The IRQ number + * r1 = The top of the stack points to the saved state + */ + + /* Switch to the dedicated stack */ + + mov #_g_intstackbase, r2.ui + mov r2.ui, sp.ui + + push retreg.ui + callr #_up_doirq, ?prx.b + pop retreg.ui + + /* On return from up_doirq, r0 will hold a pointer to register context + * array to use for the interrupt return. + */ + + modr (r0.ui).ui +#4 + + /* Restore the stack pointer */ + + mov r0.ui, sp.ui + + /* Unwind the same stack frame that we created at entry */ + + pop modi.ui + pop modg.ui + pop mode.ui + pop modd.ui + pop modc.ui + pop moda.ui + + pop {auxreg9} + pop {auxreg8} + pop {auxreg7} + pop {auxreg6} + pop {auxreg5} + pop {auxreg4} + pop {auxreg3} + pop {auxreg2} + + ret ?prx.b + + .func_end 3 exception_common + + .bss + .public _g_intstackalloc + .public _g_intstackbase +_g_intstackalloc: + DD CONFIG_ARCH_INTERRUPTSTACK/4 dup ? +_g_intstackbase: diff --git a/arch/ceva/src/xm6/up_icache.c b/arch/ceva/src/xm6/up_icache.c new file mode 100644 index 0000000000..ee70f5b99c --- /dev/null +++ b/arch/ceva/src/xm6/up_icache.c @@ -0,0 +1,298 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_icache.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MSS_PCR 0x0404 +#define P_ADD0_ATT0 0x0418 +#define P_CCOSAR 0x0514 +#define P_CCOCR 0x0518 +#define MSS_HDCFG 0x061c + +#define MSS_PCR_CAC_PFE 0x00000004 + +#define P_ADD0_ATT0_L1IC 0x00000001 +#define P_ADD0_ATT0_L1IC_LOCK 0x00000002 + +#define P_CCOCR_FLUSH 0x00000001 +#define P_CCOCR_L1ICO 0x00000002 +#define P_CCOCR_OT_PREFETCH 0x00000004 +#define P_CCOCR_OT_LOCK 0x00000008 +#define P_CCOCR_OT_UNLOCK 0x0000000c +#define P_CCOCR_OT_INVALIDATE 0x00000010 +#define P_CCOCR_OT_MASK 0x0000003c +#define P_CCOCR_OS_ENTIRE 0x00000080 +#define P_CCOCR_QFILL_SHIFT 12 +#define P_CCOCR_QFILL_MASK 0x00007000 +#define P_CCOCR_OF 0x00008000 +#define P_CCOCR_NOBPL_SHIFT 16 +#define P_CCOCR_NOBPL_MASK 0xffff0000 + +#define MSS_HDCFG_PCAC_SZE_0KB 0x00000000 +#define MSS_HDCFG_PCAC_SZE_32KB 0x00001000 +#define MSS_HDCFG_PCAC_SZE_64KB 0x00002000 +#define MSS_HDCFG_PCAC_SZE_128KB 0x00003000 +#define MSS_HDCFG_PCAC_SZE_MASK 0x00007000 + +#define MSS_CACHE_BLOCK_SIZE 64 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_CEVA_ICACHE +static void maintain_icache_all(uint32_t op) +{ + irqstate_t flags; + + /* Disable irq */ + + flags = up_irq_save(); + + /* Start the operation on the entire cache */ + + putcpm(P_CCOCR, P_CCOCR_L1ICO | op | P_CCOCR_OS_ENTIRE); + + while (getcpm(P_CCOCR) & P_CCOCR_L1ICO) + { + /* Loop until the operation finish */; + } + + /* Restore irq */ + + up_irq_restore(flags); +} + +static void maintain_icache(uint32_t op, uintptr_t start, uintptr_t end) +{ + static size_t op_maxblocks; + + /* Initialize op_maxblocks if not yet */ + + if (op_maxblocks == 0) + { + switch (getcpm(MSS_HDCFG) & MSS_HDCFG_PCAC_SZE_MASK) + { + case MSS_HDCFG_PCAC_SZE_32KB: + op_maxblocks = 512; + break; + case MSS_HDCFG_PCAC_SZE_64KB: + op_maxblocks = 1024; + break; + case MSS_HDCFG_PCAC_SZE_128KB: + op_maxblocks = 2048; + break; + default: + op_maxblocks = 1; + break; + } + } + + /* Align the address to the cache block boundary */ + + start &= ~(MSS_CACHE_BLOCK_SIZE - 1); + end += (MSS_CACHE_BLOCK_SIZE - 1); + end &= ~(MSS_CACHE_BLOCK_SIZE - 1); + + /* Skip dtcm since it never put into dcache */ + + if (end > CONFIG_ARCH_ITCM_SIZE) + { + if (start < CONFIG_ARCH_ITCM_SIZE) + { + start = CONFIG_ARCH_ITCM_SIZE; + } + + while (start < end) + { + irqstate_t flags; + size_t op_blocks; + + /* Get the max blocks we can do in one iteration */ + + op_blocks = (end - start) / MSS_CACHE_BLOCK_SIZE; + if (op_blocks > op_maxblocks) + { + op_blocks = op_maxblocks; + } + + /* Disable irq */ + + flags = up_irq_save(); + + /* Set the cache address */ + + putcpm(P_CCOSAR, start); + + /* Start the cache operation */ + + putcpm(P_CCOCR, /* Address based operation */ + P_CCOCR_L1ICO | op | (op_blocks << P_CCOCR_NOBPL_SHIFT)); + + while (getcpm(P_CCOCR) & P_CCOCR_L1ICO) + { + /* Loop until the operation finish */; + } + + /* Restore irq */ + + up_irq_restore(flags); + + /* Prepare the next loop */ + + start += op_blocks * MSS_CACHE_BLOCK_SIZE; + } + } +} + +/**************************************************************************** + * Name: up_enable_icache + * + * Description: + * Enable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void up_enable_icache(void) +{ + /* Invalidate the entire icache */ + + maintain_icache_all(P_CCOCR_OT_INVALIDATE); + + /* Enable prefetch */ + + modifycpm(MSS_PCR, 0, MSS_PCR_CAC_PFE); + + /* Enable icache and disable lock */ + + modifycpm(P_ADD0_ATT0, P_ADD0_ATT0_L1IC_LOCK, P_ADD0_ATT0_L1IC); +} + +/**************************************************************************** + * Name: up_disable_icache + * + * Description: + * Disable the I-Cache + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_disable_icache(void) +{ + /* Disable icache */ + + modifycpm(P_ADD0_ATT0, P_ADD0_ATT0_L1IC, 0); + + /* Invalidate the entire icache */ + + maintain_icache_all(P_CCOCR_OT_INVALIDATE); +} + +/**************************************************************************** + * Name: up_invalidate_icache + * + * Description: + * Invalidate the instruction cache within the specified region. + * + * Input Parameters: + * start - virtual start address of region + * end - virtual end address of region + 1 + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache(uintptr_t start, uintptr_t end) +{ + maintain_icache(P_CCOCR_OT_INVALIDATE, start, end); +} + +/**************************************************************************** + * Name: up_invalidate_icache_all + * + * Description: + * Invalidate the entire contents of I cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_invalidate_icache_all(void) +{ + maintain_icache_all(P_CCOCR_OT_INVALIDATE); +} + +/**************************************************************************** + * Name: up_coherent_dcache + * + * Description: + * Ensure that the I and D caches are coherent within specified region + * by cleaning the D cache (i.e., flushing the D cache contents to memory + * and invalidating the I cache. This is typically used when code has been + * written to a memory region, and will be executed. + * + * Input Parameters: + * addr - virtual start address of region + * len - Size of the address region in bytes + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_coherent_dcache(uintptr_t addr, size_t len) +{ + /* Invalidate instruction cache is enough */ + + up_invalidate_icache(addr, addr + len); +} +#endif diff --git a/arch/ceva/src/xm6/up_initialstate.c b/arch/ceva/src/xm6/up_initialstate.c new file mode 100644 index 0000000000..651a6c3e4f --- /dev/null +++ b/arch/ceva/src/xm6/up_initialstate.c @@ -0,0 +1,96 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_initialstate.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define REG_MODE_DEFAULT 0x40004000 /* PR14H and PR14L */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_initial_state + * + * Description: + * A new thread is being started and a new TCB + * has been created. This function is called to initialize + * the processor specific portions of the new TCB. + * + * This function must setup the intial architecture registers + * and/or stack so that execution will begin at tcb->start + * on the next context switch. + * + ****************************************************************************/ + +void up_initial_state(struct tcb_s *tcb) +{ + struct xcptcontext *xcp = &tcb->xcp; + + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + + if (tcb->adj_stack_ptr) + { + xcp->regs = tcb->adj_stack_ptr - XCPTCONTEXT_SIZE; + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); + + /* Save the initial stack pointer */ + + xcp->regs[REG_SP] = (uint32_t)xcp->regs; + + /* Save the task entry point */ + + xcp->regs[REG_PC] = (uint32_t)tcb->start; + + /* Initialize all no zero registers */ + + xcp->regs[REG_MODA] = REG_MODA_DEFAULT; + + /* All tasks start via a stub function in kernel space. + * So all tasks must start in privileged thread mode. + * If CONFIG_BUILD_PROTECTED is defined, + * then that stub function will switch to unprivileged + * mode before transferring control to the user task. + */ + + xcp->regs[REG_OM] = REG_OM_DEFAULT; + +#ifdef CONFIG_ARCH_XM6_BUG001 + /* See BUG 001 in CEVA-XM6 Bug List */ + + xcp->regs[REG_MODE] = REG_MODE_DEFAULT; +#endif + } +} diff --git a/arch/ceva/src/xm6/up_intc.c b/arch/ceva/src/xm6/up_intc.c new file mode 100644 index 0000000000..fb18382a07 --- /dev/null +++ b/arch/ceva/src/xm6/up_intc.c @@ -0,0 +1,217 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_intc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "cpm.h" +#include "up_internal.h" +#include "vintc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DBG_GEN_MASK 0x0d28 + +#define DBG_GEN_MASK_OVRFLW_EXCPTN 0x10000000 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * This function implements disabling of the device specified by 'irq' + * at the interrupt controller level if supported by the architecture + * (up_irq_save() supports the global level, the device level is hardware + * specific). + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_disable_irq(irq); + } + else if (irq >= IRQ_TRAP0) + { + switch (irq) + { + case IRQ_TRAP0: + __asm__ __volatile__("rstp {imaskt} #0x01"); + break; + case IRQ_TRAP1: + __asm__ __volatile__("rstp {imaskt} #0x02"); + break; + case IRQ_TRAP2: + __asm__ __volatile__("rstp {imaskt} #0x04"); + break; + case IRQ_TRAP3: + __asm__ __volatile__("rstp {imaskt} #0x08"); + break; + } + } +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * On many architectures, there are three levels of interrupt enabling: (1) + * at the global level, (2) at the level of the interrupt controller, + * and (3) at the device level. In order to receive interrupts, they + * must be enabled at all three levels. + * + * This function implements enabling of the device specified by 'irq' + * at the interrupt controller level if supported by the architecture + * (up_irq_restore() supports the global level, the device level is + * hardware specific). + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + /* Note: All INTx is enabled by REG_MODA_DEFAULT */ + + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_enable_irq(irq); + } + else if (irq >= IRQ_TRAP0) + { + switch (irq) + { + case IRQ_TRAP0: + __asm__ __volatile__("setp {imaskt} #0x01"); + break; + case IRQ_TRAP1: + __asm__ __volatile__("setp {imaskt} #0x02"); + break; + case IRQ_TRAP2: + __asm__ __volatile__("setp {imaskt} #0x04"); + break; + case IRQ_TRAP3: + __asm__ __volatile__("setp {imaskt} #0x08"); + break; + } + } +} + +/**************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQPRIO +int up_prioritize_irq(int irq, int priority) +{ + int ret = -EINVAL; + + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + ret = up_vintc_prioritize_irq(irq, priority); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: up_trigger_irq + * + * Description: + * Trigger an IRQ by software. May not be supported by all architectures. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_IRQTRIGGER +void up_trigger_irq(int irq) +{ + if (irq >= IRQ_VINT_FIRST) + { + /* Forward to the secondary interrupt controller */ + + up_vintc_trigger_irq(irq); + } +} +#endif /* CONFIG_ARCH_HAVE_IRQTRIGGER */ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + /* Set the INTBASE in case inttbl not equal zero. */ + + __asm__ __volatile__("movp #inttbl.0, modh.ui"); + + /* Disable the integer overflow exception. */ + + modifycpm(DBG_GEN_MASK, 0, DBG_GEN_MASK_OVRFLW_EXCPTN); + + /* Initialize the secondary interrupt controller */ + + up_vintc_initialize(); + + /* Attach and enable SVCall exception handler */ + + irq_attach(IRQ_TRAP0, up_svcall, NULL); + up_enable_irq(IRQ_TRAP0); + + /* Attach and enable Hard Fault exception handler */ + +#if CONFIG_ARCH_HARDFAULT_IRQ >= 0 + irq_attach(CONFIG_ARCH_HARDFAULT_IRQ, up_hardfault, NULL); + up_enable_irq(CONFIG_ARCH_HARDFAULT_IRQ); +#endif + + /* And finally, enable interrupts */ + + up_irq_enable(); +} diff --git a/arch/ceva/src/xm6/up_mpu.c b/arch/ceva/src/xm6/up_mpu.c new file mode 100644 index 0000000000..0a6db9e7d7 --- /dev/null +++ b/arch/ceva/src/xm6/up_mpu.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_mpu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "cpm.h" +#include "mpu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_ARCH_MPU + +/**************************************************************************** + * Name: mpu_control + * + * Description: + * Configure and enable (or disable) the MPU + * + ****************************************************************************/ + +void mpu_control(bool enable) +{ +} + +/**************************************************************************** + * Name: mpu_user_code + * + * Description: + * Configure a region for user code + * + ****************************************************************************/ + +void mpu_user_code(const void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_priv_code + * + * Description: + * Configure a region for privileged code + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_code(const void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_user_data + * + * Description: + * Configure a region as user data + * + ****************************************************************************/ + +void mpu_user_data(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_priv_data + * + * Description: + * Configure a region as privileged data + * + * Caution: + * The writable global variables aren't initialized yet. + * + ****************************************************************************/ + +void mpu_priv_data(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_peripheral + * + * Description: + * Configure a region as privileged peripheral address space + * + ****************************************************************************/ + +void mpu_peripheral(void *base, size_t size) +{ +} + +/**************************************************************************** + * Name: mpu_stronglyordered + * + * Description: + * Configure a region for privileged, strongly ordered memory + * + ****************************************************************************/ + +void mpu_stronglyordered(void *base, size_t size) +{ +} + +#endif diff --git a/arch/ceva/src/xm6/up_psu.c b/arch/ceva/src/xm6/up_psu.c new file mode 100644 index 0000000000..b7ee135e7e --- /dev/null +++ b/arch/ceva/src/xm6/up_psu.c @@ -0,0 +1,69 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_psu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* disable psu function temporily */ + +#define CEVAXM6_PSU_ENABLE 0 + +#if CEVAXM6_PSU_ENABLE + +/* Core auto restore to DPS here after wakeup */ + +#define up_cpu_pmod(pmod_inst) \ + __asm__ __volatile__ \ + ( \ + "nop #0x04\nnop\n" \ + "movp %0.ui, moda.ui\n" /* Enable the interrupt */ \ + pmod_inst /* Enter the low power mode */ \ + "nop #0x04\nnop #0x04\nnop\n" /* Clear the pipe of instruction */ \ + "movp %1.ui, moda.ui" /* restore the interrupt */ \ + : : "r"(REG_MODA_ENABLE), "r"(REG_MODA_DISABLE) \ + ) +#else +#define up_cpu_pmod(pmod_inst) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void up_cpu_doze(void) +{ + up_cpu_pmod("psu {lightsleep}\n"); +} + +void up_cpu_idle(void) +{ + up_cpu_pmod("psu {standby}\n"); +} diff --git a/arch/ceva/src/xm6/up_signal_handler.S b/arch/ceva/src/xm6/up_signal_handler.S new file mode 100644 index 0000000000..550405c6cb --- /dev/null +++ b/arch/ceva/src/xm6/up_signal_handler.S @@ -0,0 +1,96 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_signal_handler.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "svcall.h" + +#if (defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__)) && \ + !defined(CONFIG_DISABLE_SIGNALS) + +/**************************************************************************** + * File info + ****************************************************************************/ + + .file "up_signal_handler.S" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_dispatch() in user-mode. + * + * Inputs: + * r0 = sighand + * The address user-space signal handling function + * r1, r2, r3 = signo, info, and ucontext + * Standard arguments to be passed to the signal handling function. + * + * Return: + * None. This function does not return in the normal sense. It returns + * via the SYS_signal_handler_return (see svcall.h) + * + ****************************************************************************/ + + .text + .public _up_signal_handler + .func_start 3 _up_signal_handler + +_up_signal_handler: + + /* Save some register */ + + push retreg.ui /* Save LR on the stack */ + + /* Call the signal handler */ + + mov r0.ui, r4.ui /* r4=sighand */ + mov r1.ui, r0.ui /* r0=signo */ + mov r2.ui, r1.ui /* r1=info */ + mov r3.ui, r2.ui /* r2=ucontext */ + nop #0x03 + callar r4.ui /* Call the signal handler */ + + /* Restore the registers */ + + pop retreg.ui + + /* Execute the SYS_signal_handler_return SVCall (will not return) */ + + mov #SYS_signal_handler_return, r0.ui + trap {t0} + + .func_end 3 _up_signal_handler + +#else /* Add dummy symbol to avoid cofflib crash */ + + .text +dummy_signal_handler: + +#endif diff --git a/arch/ceva/src/xm6/up_svcall_handler.S b/arch/ceva/src/xm6/up_svcall_handler.S new file mode 100644 index 0000000000..9aa63d7187 --- /dev/null +++ b/arch/ceva/src/xm6/up_svcall_handler.S @@ -0,0 +1,103 @@ +/**************************************************************************** + * arch/ceva/src/xm6/up_svcall_handler.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "svcall.h" + +#ifdef CONFIG_LIB_SYSCALL + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "up_svcall_handler.S" + .extern _g_stublookup + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_svcall_handler + * + * Description: + * This function is the kernel-space, syscall handler trampoline function. It + * is called from up_svcall() in interrupt handler. + * + * Call the stub function corresponding to the system call. NOTE the non- + * standard parameter passing: + * + * r0 = SYS_ call number + * r1 = parm0 + * r2 = parm1 + * r3 = parm2 + * r4 = parm3 + * r5 = parm4 + * r6 = parm5 + * + * Return: + * None. This function does not return in the normal sense. It returns + * via the SYS_syscall_return (see svcall.h) + * + ****************************************************************************/ + + .text + .public _up_svcall_handler + .func_start 3 _up_svcall_handler + +_up_svcall_handler: + + /* Create a stack frame to hold LR */ + + push retreg.ui + + /* Call the stub function */ + + mov #_g_stublookup, r7.ui + shiftladd r0.ui, #0x02, r7.ui, r7.ui + nop #0x02 + ld (r7.ui).ui, r7.ui + nop #0x04 + nop + callar r7.ui + + /* Destroy the stack frame */ + + pop retreg.ui + + /* Execute the SYS_syscall_return SVCall (will not return) */ + /* Save return value in r2 */ + mov r0.ui, r2.ui /* will restore in up_svcall */ + mov #SYS_syscall_return, r0.ui + trap {t0} + + .func_end 3 _up_svcall_handler + +#else /* Add dummy symbol to avoid cofflib crash */ + + .text +dummy_svcall_handler: + +#endif /* CONFIG_LIB_SYSCALL */ diff --git a/arch/ceva/src/xm6/vfork.S b/arch/ceva/src/xm6/vfork.S new file mode 100644 index 0000000000..4982e4d9e5 --- /dev/null +++ b/arch/ceva/src/xm6/vfork.S @@ -0,0 +1,121 @@ +/**************************************************************************** + * arch/ceva/src/xm6/vfork.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +.IF CONFIG_ARCH_XM6_BUG001 + .EQU prx pr14 +.ELSE + .EQU prx pr15 +.ENDIF + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "vfork.S" + .extern _up_vfork + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: vfork + * + * Description: + * The vfork() function has the same effect as fork(), except that the behavior is + * undefined if the process created by vfork() either modifies any data other than + * a variable of type pid_t used to store the return value from vfork(), or returns + * from the function in which vfork() was called, or calls any other function before + * successfully calling _exit() or one of the exec family of functions. + * + * This thin layer implements vfork by simply calling up_vfork() with the vfork() + * context as an argument. The overall sequence is: + * + * 1) User code calls vfork(). vfork() collects context information and + * transfers control up up_vfork(). + * 2) up_vfork()and calls nxtask_vforksetup(). + * 3) task_vforksetup() allocates and configures the child task's TCB. This + * consists of: + * - Allocation of the child task's TCB. + * - Initialization of file descriptors and streams + * - Configuration of environment variables + * - Setup the intput parameters for the task. + * - Initialization of the TCB (including call to up_initial_state() + * 4) up_vfork() provides any additional operating context. up_vfork must: + * - Allocate and initialize the stack + * - Initialize special values in any CPU registers that were not + * already configured by up_initial_state() + * 5) up_vfork() then calls nxtask_vforkstart() + * 6) nxtask_vforkstart() then executes the child thread. + * + * Input Paremeters: + * None + * + * Return: + * Upon successful completion, vfork() returns 0 to the child process and returns + * the process ID of the child process to the parent process. Otherwise, -1 is + * returned to the parent, no child process is created, and errno is set to + * indicate the error. + * + ****************************************************************************/ + + .text + .public _vfork + .func_start 3 _vfork + +_vfork: + /* Create a stack frame */ + + modr (sp.ui).ui +#-XCPTCONTEXT_SIZE /* Allocate the structure on the stack */ + + /* Save the volatile registers by svcall(SYS_save_context) */ + + mov #SYS_save_context, r0.ui + mov sp.ui, r1.ui + trap {t0} + + /* Then, call up_vfork(), passing it a pointer to the stack structure */ + + mov sp.ui, r0.ui + nop + push retreg.ui + callr #_up_vfork, ?prx.b + pop retreg.ui + nop + + /* Release the stack data and return the value returned by up_vfork */ + + modr (sp.ui).ui +#XCPTCONTEXT_SIZE + ret ?prx.b + + .func_end 3 _vfork