text: /*
   * Copyright (c) 2015 Intel Corporation
   *
   * 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.
   */
  
  #ifdef CONFIG_MICROKERNEL
  #include <microkernel.h>
  #include <micro_private_types.h>
  #endif /* CONFIG_MICROKERNEL */
  #ifdef CONFIG_INIT_STACKS
  #include <string.h>
  #endif /* CONFIG_INIT_STACKS */
  
  #include <toolchain.h>
  #include <sections.h>
  #include <nano_private.h>
  #include <wait_q.h>
  
  /* the one and only nanokernel control structure */
  
  tNANO _nanokernel = {0};
  
  /* forward declaration to asm function to adjust setup the arguments
   * to _thread_entry()
   */
  void _thread_entry_wrapper(_thread_entry_t, _thread_arg_t,
  			   _thread_arg_t, _thread_arg_t);
  
  /**
   *
   * @brief Create a new kernel execution context
   *
   * This function initializes a thread control structure (TCS) for a
   * new kernel execution context. A fake stack frame is created as if
   * the context had been "swapped out" via _Swap()
   *
   * @param stack_memory pointer to the context stack area
   * @param stack_size size of contexts stack area
   * @param thread_func new contexts entry function
   * @param parameter1 first entry function parameter
   * @param parameter2 second entry function parameter
   * @param parameter3 third entry function parameter
   * @param priority Priority of the new context
   * @param options Additional options for the context
   *
   * @return none
   *
   * \NOMANUAL
   */
  
  void _new_thread(char *stack_memory, unsigned stack_size,
  		 void *uk_task_ptr, _thread_entry_t thread_func,
  		 void *parameter1, void *parameter2, void *parameter3,
  		 int priority, unsigned options)
  {
  	unsigned long *thread_context;
  	struct tcs *tcs = (struct tcs *)stack_memory;
  
  	ARG_UNUSED(options);
  
  #ifdef CONFIG_INIT_STACKS
  	memset(stack_memory, 0xaa, stack_size);
  #endif
  
  	tcs->link = (struct tcs *)NULL; /* thread not inserted into list yet */
  	tcs->prio = priority;
  
  	if (priority == -1) {
  		tcs->flags = PREEMPTIBLE | TASK;
  	} else {
  		tcs->flags = FIBER;
  	}
  
  #ifdef CONFIG_THREAD_CUSTOM_DATA
  	/* Initialize custom data field (value is opaque to kernel) */
  
  	tcs->custom_data = NULL;
  #endif
  
  	/* carve the thread entry struct from the "base" of the stack */
  
  	thread_context =
  		(unsigned long *)STACK_ROUND_DOWN(stack_memory + stack_size);
  
  	/*
  	 * Create an initial context on the stack expected by the _Swap()
  	 * primitive.
  	 * Given that both task and fibers execute at privilege 0, the
  	 * setup for both threads are equivalent.
  	 */
  
  	/* push arguments required by _thread_entry() */
  
  	*--thread_context = (unsigned long)parameter3;
  	*--thread_context = (unsigned long)parameter2;
  	*--thread_context = (unsigned long)parameter1;
  	*--thread_context = (unsigned long)thread_func;
  
  	/* push initial EFLAGS; only modify IF and IOPL bits */
  
  	*--thread_context = (unsigned long)_thread_entry_wrapper;
  	*--thread_context = (EflagsGet() & ~EFLAGS_MASK) | EFLAGS_INITIAL;
  	*--thread_context = 0;
  	*--thread_context = 0;
  	*--thread_context = 0;
  	--thread_context;
  	*thread_context = (unsigned long)(thread_context + 4);
  	*--thread_context = 0;
  
  #ifdef CONFIG_MICROKERNEL
  	tcs->uk_task_ptr = uk_task_ptr;
  #else
  	ARG_UNUSED(uk_task_ptr);
  #endif
  	tcs->coopReg.esp = (unsigned long)thread_context;
  #if defined(CONFIG_THREAD_MONITOR)
  	{
  		unsigned int imask;
  
  		/*
  		 * Add the newly initialized thread to head of the
  		 * list of threads. This singly linked list of threads
  		 * maintains ALL the threads in the system: both tasks
  		 * and fibers regardless of whether they are runnable.
  		 */
  
  		imask = irq_lock();
  		tcs->next_thread = _nanokernel.threads;
  		_nanokernel.threads = tcs;
  		irq_unlock(imask);
  	}
  #endif /* CONFIG_THREAD_MONITOR */
  
  	_nano_timeout_tcs_init(tcs);
  }
  