diff --git a/arch/arm/core/Makefile b/arch/arm/core/Makefile index dbd21abd076..73a6f06d7d7 100644 --- a/arch/arm/core/Makefile +++ b/arch/arm/core/Makefile @@ -1,17 +1,27 @@ +ifeq ($(CONFIG_KERNEL_V2),y) +ccflags-y += -I$(srctree)/kernel/unified/include +else ccflags-y += -I$(srctree)/kernel/nanokernel/include ccflags-y += -I$(srctree)/kernel/microkernel/include +endif asflags-y := ${ccflags-y} obj-y = exc_exit.o irq_init.o \ - fiber_abort.o swap.o \ + swap.o \ fault.o \ irq_manage.o thread.o cpu_idle.o \ fault_s.o isr_wrapper.o \ fatal.o sys_fatal_error_handler.o +ifeq ($(CONFIG_KERNEL_V2),y) +obj-y += thread_abort.o +else +obj-y += fiber_abort.o +obj-$(CONFIG_MICROKERNEL) += task_abort.o +endif + obj-$(CONFIG_GDB_INFO) += gdb_stub_irq_vector_table.o gdb_stub.o obj-$(CONFIG_CPLUSPLUS) += __aeabi_atexit.o -obj-$(CONFIG_MICROKERNEL) += task_abort.o obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o obj-$(CONFIG_CPU_CORTEX_M) += cortex_m/ diff --git a/arch/arm/core/cortex_m/Makefile b/arch/arm/core/cortex_m/Makefile index 0551cc3fc3f..48468bb4846 100644 --- a/arch/arm/core/cortex_m/Makefile +++ b/arch/arm/core/cortex_m/Makefile @@ -1,6 +1,10 @@ ccflags-y +=-I$(srctree)/include/drivers ccflags-y +=-I$(srctree)/arch/arm/soc/$(SOC_PATH) +ifeq ($(CONFIG_KERNEL_V2),y) +ccflags-y +=-I$(srctree)/kernel/unified/include +else ccflags-y +=-I$(srctree)/kernel/nanokernel/include +endif asflags-y = $(ccflags-y) diff --git a/arch/arm/core/exc_exit.S b/arch/arm/core/exc_exit.S index 29d5cf5a8c8..8643a6b81e2 100644 --- a/arch/arm/core/exc_exit.S +++ b/arch/arm/core/exc_exit.S @@ -37,6 +37,10 @@ GTEXT(_ExcExit) GTEXT(_IntExit) GDATA(_nanokernel) +#ifdef CONFIG_KERNEL_V2 +GTEXT(__must_switch_threads) +#endif + #if CONFIG_GDB_INFO #define _EXIT_EXC_IF_FIBER_PREEMPTED beq _ExcExitWithGdbStub #else @@ -92,6 +96,31 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, _ExcExit) ldr r1, =_nanokernel +#ifdef CONFIG_KERNEL_V2 + ldr r1, [r1, #__tNANO_current_OFFSET] + + ldr r2, [r1, #__tTCS_prio_OFFSET] + ldr r3, [r1, #__tTCS_sched_locked_OFFSET] + + /* coop thread ? do not schedule */ + cmp r2, #0 + it lt + bxlt lr + + /* scheduler locked ? do not schedule */ + cmp r3, #0 + it gt + bxgt lr + + push {lr} + blx __must_switch_threads + pop {lr} + cmp r0, #0 + it eq + bxeq lr + +#else + /* is the current thread preemptible (task) ? */ ldr r2, [r1, #__tNANO_flags_OFFSET] ands.w r2, #PREEMPTIBLE @@ -102,6 +131,8 @@ SECTION_SUBSEC_FUNC(TEXT, _HandlerModeExit, _ExcExit) cmp r2, #0 _EXIT_EXC_IF_FIBER_NOT_READY +#endif + /* context switch required, pend the PendSV exception */ ldr r1, =_SCS_ICSR ldr r2, =_SCS_ICSR_PENDSV diff --git a/arch/arm/core/offsets/offsets.c b/arch/arm/core/offsets/offsets.c index 6cc38e92edf..6d3c1c042f5 100644 --- a/arch/arm/core/offsets/offsets.c +++ b/arch/arm/core/offsets/offsets.c @@ -39,7 +39,9 @@ /* ARM-specific tNANO structure member offsets */ +#if !defined(CONFIG_KERNEL_V2) GEN_OFFSET_SYM(tNANO, flags); +#endif #ifdef CONFIG_SYS_POWER_MANAGEMENT GEN_OFFSET_SYM(tNANO, idle); #endif diff --git a/arch/arm/core/swap.S b/arch/arm/core/swap.S index cfa4f8b54ad..8762dce3fe5 100644 --- a/arch/arm/core/swap.S +++ b/arch/arm/core/swap.S @@ -34,6 +34,10 @@ _ASM_FILE_PROLOGUE GTEXT(_Swap) GTEXT(__svc) GTEXT(__pendsv) +#ifdef CONFIG_KERNEL_V2 +GTEXT(_get_next_ready_thread) +GDATA(_k_neg_eagain) +#endif GDATA(_nanokernel) @@ -97,6 +101,12 @@ SECTION_FUNC(TEXT, __pendsv) /* find out incoming thread (fiber or task) */ +#ifdef CONFIG_KERNEL_V2 + push {lr} + blx _get_next_ready_thread + pop {lr} + movs.n r2, r0 +#else /* is there a fiber ready ? */ ldr r2, [r1, #__tNANO_fiber_OFFSET] cmp r2, #0 @@ -109,10 +119,13 @@ SECTION_FUNC(TEXT, __pendsv) ldrne.w r0, [r2, #__tTCS_link_OFFSET] /* then */ strne.w r0, [r1, #__tNANO_fiber_OFFSET] /* then */ ldreq.w r2, [r1, #__tNANO_task_OFFSET] /* else */ +#endif /* r2 contains the new thread */ +#if !defined(CONFIG_KERNEL_V2) ldr r0, [r2, #__tTCS_flags_OFFSET] str r0, [r1, #__tNANO_flags_OFFSET] +#endif str r2, [r1, #__tNANO_current_OFFSET] /* @@ -189,6 +202,18 @@ SECTION_FUNC(TEXT, __svc) _context_switch: #endif +#if CONFIG_KERNEL_V2 + /* + * Set _Swap()'s default return code to -EAGAIN. This eliminates the + * need for the timeout code to invoke fiberRtnValueSet(). + */ + + mrs r2, PSP /* thread mode, stack frame is on PSP */ + ldr r3, =_k_neg_eagain + ldr r3, [r3, #0] + str r3, [r2, #__tESF_a1_OFFSET] +#endif + /* * Unlock interrupts: * - in a SVC call, so protected against context switches diff --git a/arch/arm/core/sys_fatal_error_handler.c b/arch/arm/core/sys_fatal_error_handler.c index 25359dfaed2..6f693657baf 100644 --- a/arch/arm/core/sys_fatal_error_handler.c +++ b/arch/arm/core/sys_fatal_error_handler.c @@ -26,6 +26,10 @@ #include #include +#ifdef CONFIG_KERNEL_V2 +#include +#endif + #ifdef CONFIG_PRINTK #include #define PRINTK(...) printk(__VA_ARGS__) @@ -34,11 +38,16 @@ #endif #ifdef CONFIG_MICROKERNEL -extern void _TaskAbort(void); static inline void nonEssentialTaskAbort(void) { PRINTK("Fatal fault in task ! Aborting task.\n"); + +#if defined(CONFIG_KERNEL_V2) + k_thread_abort(_current); +#else + extern void _TaskAbort(void); _TaskAbort(); +#endif } #define NON_ESSENTIAL_TASK_ABORT() nonEssentialTaskAbort() #else diff --git a/arch/arm/core/thread.c b/arch/arm/core/thread.c index c5c07722726..d70df235871 100644 --- a/arch/arm/core/thread.c +++ b/arch/arm/core/thread.c @@ -94,8 +94,8 @@ static ALWAYS_INLINE void _thread_monitor_init(struct tcs *tcs /* thread */ * @param parameter1 entry point to the first param * @param parameter2 entry point to the second param * @param parameter3 entry point to the third param - * @param priority thread priority (-1 for tasks) - * @param misc options (future use) + * @param priority thread priority + * @param options thread options: ESSENTIAL, USE_FP * * @return N/A */ @@ -130,8 +130,18 @@ void _new_thread(char *pStackMem, unsigned stackSize, pInitCtx->xpsr = 0x01000000UL; /* clear all, thumb bit is 1, even if RO */ +#ifdef CONFIG_KERNEL_V2 + /* k_q_node initialized upon first insertion in a list */ + tcs->flags = options | K_PRESTART; + tcs->sched_locked = 0; + + /* static threads overwrite it afterwards with real value */ + tcs->init_data = NULL; + tcs->fn_abort = NULL; +#else tcs->link = NULL; tcs->flags = priority == -1 ? TASK | PREEMPTIBLE : FIBER; +#endif tcs->prio = priority; #ifdef CONFIG_THREAD_CUSTOM_DATA @@ -148,7 +158,7 @@ void _new_thread(char *pStackMem, unsigned stackSize, tcs->entry = (struct __thread_entry *)(pInitCtx); #endif -#ifdef CONFIG_MICROKERNEL +#if !defined(CONFIG_KERNEL_V2) && defined(CONFIG_MICROKERNEL) tcs->uk_task_ptr = uk_task_ptr; #else ARG_UNUSED(uk_task_ptr); diff --git a/arch/arm/core/thread_abort.c b/arch/arm/core/thread_abort.c new file mode 100644 index 00000000000..6f41c91d3ab --- /dev/null +++ b/arch/arm/core/thread_abort.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Wind River Systems, Inc. + * + * Licensed 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 + * @brief ARM Cortex-M k_thread_abort() routine + * + * The ARM Cortex-M architecture provides its own k_thread_abort() to deal + * with different CPU modes (handler vs thread) when a thread aborts. When its + * entry point returns or when it aborts itself, the CPU is in thread mode and + * must call _Swap() (which triggers a service call), but when in handler + * mode, the CPU must exit handler mode to cause the context switch, and thus + * must queue the PendSV exception. + */ + +#include +#include +#include +#include +#include +#include + +extern void _k_thread_single_abort(struct tcs *thread); + +void k_thread_abort(k_tid_t thread) +{ + unsigned int key; + + key = irq_lock(); + + _k_thread_single_abort(thread); + + if (_current == thread) { + if (_ScbIsInThreadMode()) { + _Swap(key); + CODE_UNREACHABLE; + } else { + _ScbPendsvSet(); + } + } + + /* The abort handler might have altered the ready queue. */ + _reschedule_threads(key); +} diff --git a/arch/arm/include/nano_private.h b/arch/arm/include/nano_private.h index 6be231a8e4e..649313682e6 100644 --- a/arch/arm/include/nano_private.h +++ b/arch/arm/include/nano_private.h @@ -39,9 +39,15 @@ extern "C" { #include #ifndef _ASMLANGUAGE +#ifdef CONFIG_KERNEL_V2 +#include +#include <../../../kernel/unified/include/nano_internal.h> +#else #include <../../../kernel/nanokernel/include/nano_internal.h> +#endif #include #include +#include #endif #ifndef _ASMLANGUAGE @@ -93,17 +99,32 @@ typedef struct preempt tPreempt; /* Bitmask definitions for the struct tcs.flags bit field */ +#ifdef CONFIG_KERNEL_V2 +#define K_STATIC 0x00000800 + +#define K_READY 0x00000000 /* Thread is ready to run */ +#define K_TIMING 0x00001000 /* Thread is waiting on a timeout */ +#define K_PENDING 0x00002000 /* Thread is waiting on an object */ +#define K_PRESTART 0x00004000 /* Thread has not yet started */ +#define K_DEAD 0x00008000 /* Thread has terminated */ +#define K_SUSPENDED 0x00010000 /* Thread is suspended */ +#define K_DUMMY 0x00020000 /* Not a real thread */ +#define K_EXECUTION_MASK (K_TIMING | K_PENDING | K_PRESTART | \ + K_DEAD | K_SUSPENDED | K_DUMMY) +#else #define FIBER 0x000 #define TASK 0x001 /* 1 = task, 0 = fiber */ -#define INT_ACTIVE 0x002 /* 1 = executing context is interrupt handler */ -#define EXC_ACTIVE 0x004 /* 1 = executing context is exception handler */ -#define USE_FP 0x010 /* 1 = thread uses floating point unit */ +#define INT_ACTIVE 0x002 /* 1 = executino context is interrupt handler */ +#define EXC_ACTIVE 0x004 /* 1 = executino context is exception handler */ #define PREEMPTIBLE \ 0x020 /* 1 = preemptible thread \ * NOTE: the value must be < 0x100 to be able to \ * use a small thumb instr with immediate \ * when loading PREEMPTIBLE in a GPR \ */ +#endif + +#define USE_FP 0x010 /* 1 = thread uses floating point unit */ #define ESSENTIAL 0x200 /* 1 = system thread that must not abort */ #define NO_METRICS 0x400 /* 1 = _Swap() not to update task metrics */ @@ -140,11 +161,28 @@ struct preemp_float { }; #endif +#if CONFIG_KERNEL_V2 +/* 'struct tcs_base' must match the beginning of 'struct tcs' */ +struct tcs_base { + sys_dnode_t k_q_node; + uint32_t flags; + int prio; + void *swap_data; +}; +#endif + struct tcs { +#if CONFIG_KERNEL_V2 + sys_dnode_t k_q_node; /* node object in any kernel queue */ + uint32_t flags; + int prio; + void *swap_data; +#else struct tcs *link; /* singly-linked list in _nanokernel.fibers */ uint32_t flags; - uint32_t basepri; int prio; +#endif + uint32_t basepri; #ifdef CONFIG_THREAD_CUSTOM_DATA void *custom_data; /* available for custom use */ #endif @@ -154,15 +192,25 @@ struct tcs { struct __thread_entry *entry; /* thread entry and parameters description */ struct tcs *next_thread; /* next item in list of ALL fiber+tasks */ #endif -#ifdef CONFIG_NANO_TIMEOUTS +#if !defined(CONFIG_KERNEL_V2) && defined(CONFIG_NANO_TIMEOUTS) struct _nano_timeout nano_timeout; #endif #ifdef CONFIG_ERRNO int errno_var; #endif +#if !defined(CONFIG_KERNEL_V2) #ifdef CONFIG_MICROKERNEL void *uk_task_ptr; #endif +#endif +#ifdef CONFIG_KERNEL_V2 +#ifdef CONFIG_NANO_TIMEOUTS + struct _timeout timeout; +#endif + atomic_t sched_locked; + void *init_data; + void (*fn_abort)(void); +#endif #ifdef CONFIG_FLOAT /* * No cooperative floating point register set structure exists for @@ -173,11 +221,22 @@ struct tcs { #endif }; +#ifdef CONFIG_KERNEL_V2 +struct ready_q { + uint32_t prio_bmap[1]; + sys_dlist_t q[K_NUM_PRIORITIES]; +}; +#endif + struct s_NANO { +#if !defined(CONFIG_KERNEL_V2) struct tcs *fiber; /* singly linked list of runnable fiber */ struct tcs *task; /* pointer to runnable task */ +#endif struct tcs *current; /* currently scheduled thread (fiber or task) */ +#if !defined(CONFIG_KERNEL_V2) int flags; /* struct tcs->flags of 'current' thread */ +#endif #if defined(CONFIG_THREAD_MONITOR) struct tcs *threads; /* singly linked list of ALL fiber+tasks */ @@ -195,6 +254,9 @@ struct s_NANO { sys_dlist_t timeout_q; int32_t task_timeout; #endif +#ifdef CONFIG_KERNEL_V2 + struct ready_q ready_q; +#endif }; typedef struct s_NANO tNANO; @@ -207,7 +269,9 @@ extern void _FaultInit(void); extern void _CpuIdleInit(void); static ALWAYS_INLINE void nanoArchInit(void) { +#if !defined(CONFIG_KERNEL_V2) _nanokernel.flags = FIBER; +#endif _InterruptStackSetup(); _ExcSetup(); _FaultInit(); @@ -235,9 +299,25 @@ static ALWAYS_INLINE void fiberRtnValueSet(struct tcs *fiber, pEsf->a1 = value; } +#ifdef CONFIG_KERNEL_V2 + #define _current _nanokernel.current + #define _ready_q _nanokernel.ready_q + #define _timeout_q _nanokernel.timeout_q + #define _set_thread_return_value fiberRtnValueSet +static ALWAYS_INLINE void +_set_thread_return_value_with_data(struct k_thread *thread, unsigned int value, + void *data) +{ + _set_thread_return_value(thread, value); + thread->swap_data = data; +} + #define _IDLE_THREAD_PRIO (CONFIG_NUM_PREEMPT_PRIORITIES) +#endif /* CONFIG_KERNEL_V2 */ + extern void nano_cpu_atomic_idle(unsigned int); #define _IS_IN_ISR() _IsInIsr() +#define _is_in_isr() _IsInIsr() extern void _IntLibInit(void);