Skip to content

Latest commit

 

History

History
109 lines (96 loc) · 3.04 KB

context_switch.md

File metadata and controls

109 lines (96 loc) · 3.04 KB
/*
 * Switch to a new thread.
 * Save the old thread`s kernel state or continuation,
 * and return it.
 */
thread_t
machine_switch_context(
	thread_t			old,
	thread_continue_t	continuation,
	thread_t			new)
{
	assert(current_cpu_datap()->cpu_active_stack == old->kernel_stack);

#if KPC
	kpc_off_cpu(old);
#endif /* KPC */

	/*
	 *	Save FP registers if in use.
	 */
	fpu_switch_context(old, new);

	old->machine.specFlags &= ~OnProc;
	new->machine.specFlags |= OnProc;

	/*
	 * Monitor the stack depth and report new max,
	 * not worrying about races.
	 */
	vm_offset_t	depth = current_stack_depth();
	if (depth > kernel_stack_depth_max) {
		kernel_stack_depth_max = depth;
		KERNEL_DEBUG_CONSTANT(
			MACHDBG_CODE(DBG_MACH_SCHED, MACH_STACK_DEPTH),
			(long) depth, 0, 0, 0, 0);
	}

	/*
	 *	Switch address maps if need be, even if not switching tasks.
	 *	(A server activation may be "borrowing" a client map.)
	 */
	pmap_switch_context(old, new, cpu_number());

	/*
	 *	Load the rest of the user state for the new thread
	 */
	act_machine_switch_pcb(old, new);

#if HYPERVISOR
	ml_hv_cswitch(old, new);
#endif

	return(Switch_context(old, continuation, new));
}

/*
 * thread_t Switch_context(
 *		thread_t old,				// %rsi
 *		thread_continue_t continuation,		// %rdi
 *		thread_t new)				// %rdx
 */
Entry(Switch_context)
	popq	%rax				/* pop return PC */

	/* Test for a continuation and skip all state saving if so... */
	cmpq	$0, %rsi
	jne 	5f
	movq	%gs:CPU_KERNEL_STACK,%rcx	/* get old kernel stack top */
	movq	%rbx,KSS_RBX(%rcx)		/* save registers */
	movq	%rbp,KSS_RBP(%rcx)
	movq	%r12,KSS_R12(%rcx)
	movq	%r13,KSS_R13(%rcx)
	movq	%r14,KSS_R14(%rcx)
	movq	%r15,KSS_R15(%rcx)
	movq	%rax,KSS_RIP(%rcx)		/* save return PC */
	movq	%rsp,KSS_RSP(%rcx)		/* save SP */
5:
	movq	%rdi,%rax			/* return old thread */
	/* new thread in %rdx */
	movq    %rdx,%gs:CPU_ACTIVE_THREAD      /* new thread is active */
	movq	TH_KERNEL_STACK(%rdx),%rdx	/* get its kernel stack */
	lea	-IKS_SIZE(%rdx),%rcx
	add	EXT(kernel_stack_size)(%rip),%rcx /* point to stack top */

	movq	%rdx,%gs:CPU_ACTIVE_STACK	/* set current stack */
	movq	%rcx,%gs:CPU_KERNEL_STACK	/* set stack top */

	movq	KSS_RSP(%rcx),%rsp		/* switch stacks */
	movq	KSS_RBX(%rcx),%rbx		/* restore registers */
	movq	KSS_RBP(%rcx),%rbp
	movq	KSS_R12(%rcx),%r12
	movq	KSS_R13(%rcx),%r13
	movq	KSS_R14(%rcx),%r14
	movq	KSS_R15(%rcx),%r15
	jmp	*KSS_RIP(%rcx)			/* return old thread */
  
/*
 * KSS_* are offsets from the top of the kernel stack (cpu_kernel_stack)
 */
DECLARE("KSS_RBX",	offsetof(struct thread_kernel_state, machine.k_rbx));
DECLARE("KSS_RSP",	offsetof(struct thread_kernel_state, machine.k_rsp));
DECLARE("KSS_RBP",	offsetof(struct thread_kernel_state, machine.k_rbp));
DECLARE("KSS_R12",	offsetof(struct thread_kernel_state, machine.k_r12));
DECLARE("KSS_R13",	offsetof(struct thread_kernel_state, machine.k_r13));
DECLARE("KSS_R14",	offsetof(struct thread_kernel_state, machine.k_r14));
DECLARE("KSS_R15",	offsetof(struct thread_kernel_state, machine.k_r15));
DECLARE("KSS_RIP",	offsetof(struct thread_kernel_state, machine.k_rip));