/** * * @brief Create a new kernel execution thread * * This function is utilized to create execution threads for both fiber * threads and kernel tasks. * * The "thread control block" (TCS) is carved from the "end" of the specified * thread stack memory. * * @param pStackmem the pointer to aligned stack memory * @param stackSize the stack size in bytes * @param pEntry thread entry point routine * @param parameter1 first param to entry point * @param parameter2 second param to entry point * @param parameter3 third param to entry point * @param priority thread priority * @param options thread options: USE_FP, USE_SSE * * * @return opaque pointer to initialized TCS structure */ void _new_thread(char *pStackMem, unsigned stackSize, _thread_entry_t pEntry, void *parameter1, void *parameter2, void *parameter3, int priority, unsigned options) { unsigned long *pInitialThread; #ifdef CONFIG_INIT_STACKS memset(pStackMem, 0xaa, stackSize); #endif /* carve the thread entry struct from the "base" of the stack */ pInitialThread = (unsigned long *)STACK_ROUND_DOWN(pStackMem + stackSize); /* * 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() */ *--pInitialThread = (unsigned long)parameter3; *--pInitialThread = (unsigned long)parameter2; *--pInitialThread = (unsigned long)parameter1; *--pInitialThread = (unsigned long)pEntry; /* push initial EFLAGS; only modify IF and IOPL bits */ *--pInitialThread = (EflagsGet() & ~EFLAGS_MASK) | EFLAGS_INITIAL; #ifdef CONFIG_GDB_INFO /* * Arrange for the _thread_entry_wrapper() function to be called * to adjust the stack before _thread_entry() is invoked. */ *--pInitialThread = (unsigned long)_thread_entry_wrapper; #else /* CONFIG_GDB_INFO */ *--pInitialThread = (unsigned long)_thread_entry; #endif /* CONFIG_GDB_INFO */ /* * note: stack area for edi, esi, ebx, ebp, and eax registers can be * left * uninitialized, since _thread_entry() doesn't care about the values * of these registers when it begins execution */ /* * For kernel tasks and fibers the thread the thread control struct (TCS) * is located at the "low end" of memory set aside for the thread's stack. */ _new_thread_internal(pStackMem, stackSize, priority, options); }
void _NewContext( char *pStackMem, /* pointer to aligned stack memory */ unsigned stackSize, /* size of stack in bytes */ _ContextEntry pEntry, /* context entry point function */ void *parameter1, /* first parameter to context entry point function */ void *parameter2, /* second parameter to context entry point function */ void *parameter3, /* third parameter to context entry point function */ int priority, /* context priority */ unsigned options /* context options: USE_FP, USE_SSE */ ) { unsigned long *pInitialContext; #ifdef CONFIG_INIT_STACKS k_memset(pStackMem, 0xaa, stackSize); #endif /* carve the context entry struct from the "base" of the stack */ pInitialContext = (unsigned long *)STACK_ROUND_DOWN(pStackMem + stackSize); /* * Create an initial context on the stack expected by the _Swap() * primitive. * Given that both task and fiber contexts execute at privilege 0, the * setup for both contexts are equivalent. */ /* push arguments required by _context_entry() */ *--pInitialContext = (unsigned long)parameter3; *--pInitialContext = (unsigned long)parameter2; *--pInitialContext = (unsigned long)parameter1; *--pInitialContext = (unsigned long)pEntry; /* push initial EFLAGS; only modify IF and IOPL bits */ *--pInitialContext = (EflagsGet() & ~EFLAGS_MASK) | EFLAGS_INITIAL; #ifdef CONFIG_GDB_INFO /* * Arrange for the _ContextEntryWrapper() function to be called * to adjust the stack before _context_entry() is invoked. */ *--pInitialContext = (unsigned long)_ContextEntryWrapper; #else /* CONFIG_GDB_INFO */ *--pInitialContext = (unsigned long)_context_entry; #endif /* CONFIG_GDB_INFO */ /* * note: stack area for edi, esi, ebx, ebp, and eax registers can be * left * uninitialized, since _context_entry() doesn't care about the values * of these registers when it begins execution */ /* * For kernel tasks and fibers the context the context control struct * (CCS) * is located at the "low end" of memory set aside for the context's * stack */ _NewContextInternal(pStackMem, stackSize, priority, options); }