kernel: arch: Clarify output switch handle requirements in arch_switch
The original intent was that the output handle be written through the pointer in the second argument, though not all architectures used that scheme. As it turns out, that write is becoming a synchronization signal, so it's no longer optional. Clarify the documentation in arch_switch() about this requirement, and add an instruction to the x86_64 context switch to implement it as original envisioned. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
74c582dc06
commit
86430d8d46
2 changed files with 32 additions and 6 deletions
|
@ -220,6 +220,13 @@ z_x86_switch:
|
|||
movq $X86_KERNEL_CS, _thread_offset_to_cs(%rsi)
|
||||
movq $X86_KERNEL_DS, _thread_offset_to_ss(%rsi)
|
||||
#endif
|
||||
/* Store the handle (i.e. our thread struct address) into the
|
||||
* switch handle field, this is a synchronization signal that
|
||||
* must occur after the last data from the old context is
|
||||
* saved.
|
||||
*/
|
||||
movq %rsi, ___thread_t_switch_handle_OFFSET(%rsi)
|
||||
|
||||
movq %gs:__x86_tss64_t_ist1_OFFSET, %rsp
|
||||
|
||||
/* fall through to __resume */
|
||||
|
|
|
@ -89,12 +89,31 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *pStack,
|
|||
* 3) Set the stack pointer to the value provided in switch_to
|
||||
* 4) Pop off all thread state from the stack we switched to and return.
|
||||
*
|
||||
* Some arches may implement thread->switch handle as a pointer to the thread
|
||||
* itself, and save context somewhere in thread->arch. In this case, on initial
|
||||
* context switch from the dummy thread, thread->switch handle for the outgoing
|
||||
* thread is NULL. Instead of dereferencing switched_from all the way to get
|
||||
* the thread pointer, subtract ___thread_t_switch_handle_OFFSET to obtain the
|
||||
* thread pointer instead.
|
||||
* Some arches may implement thread->switch handle as a pointer to the
|
||||
* thread itself, and save context somewhere in thread->arch. In this
|
||||
* case, on initial context switch from the dummy thread,
|
||||
* thread->switch handle for the outgoing thread is NULL. Instead of
|
||||
* dereferencing switched_from all the way to get the thread pointer,
|
||||
* subtract ___thread_t_switch_handle_OFFSET to obtain the thread
|
||||
* pointer instead. That is, such a scheme would have behavior like
|
||||
* (in C pseudocode):
|
||||
*
|
||||
* void arch_switch(void *switch_to, void **switched_from)
|
||||
* {
|
||||
* struct k_thread *new = switch_to;
|
||||
* struct k_thread *old = CONTAINER_OF(switched_from, struct k_thread,
|
||||
* switch_handle);
|
||||
*
|
||||
* // save old context...
|
||||
* *switched_from = old;
|
||||
* // restore new context...
|
||||
* }
|
||||
*
|
||||
* Note that, regardless of the underlying handle representation, the
|
||||
* incoming switched_from pointer MUST be written through with a
|
||||
* non-NULL value after all relevant thread state has been saved. The
|
||||
* kernel uses this as a synchronization signal to be able to wait for
|
||||
* switch completion from another CPU.
|
||||
*
|
||||
* @param switch_to Incoming thread's switch handle
|
||||
* @param switched_from Pointer to outgoing thread's switch handle storage
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue