/* switch.s * Machine dependent context switch routines. DO NOT MODIFY THESE! * * Context switching is inherently machine dependent, since * the registers to be saved, how to set up an initial * call frame, etc, are all specific to a processor architecture. * * This file currently supports the following architectures: * DEC MIPS * SUN SPARC * HP PA-RISC * Intel 386 * * We define two routines for each architecture: * * ThreadRoot(InitialPC, InitialArg, WhenDonePC, StartupPC) * InitialPC - The program counter of the procedure to run * in this thread. * InitialArg - The single argument to the thread. * WhenDonePC - The routine to call when the thread returns. * StartupPC - Routine to call when the thread is started. * * ThreadRoot is called from the SWITCH() routine to start * a thread for the first time. * * SWITCH(oldThread, newThread) * oldThread - The current thread that was running, where the * CPU register state is to be saved. * newThread - The new thread to be run, where the CPU register * state is to be loaded from. */ /* Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #include "copyright.h" #include "switch.h" .text .align 2 .globl ThreadRoot /* void ThreadRoot( void ) ** ** expects the following registers to be initialized: ** eax points to startup function (interrupt enable) ** edx contains inital argument to thread function ** esi points to thread function ** edi point to Thread::Finish() */ ThreadRoot: pushl %ebp movl %esp,%ebp pushl InitialArg call *StartupPC call *InitialPC call *WhenDonePC # NOT REACHED movl %ebp,%esp popl %ebp ret /* void SWITCH( thread *t1, thread *t2 ) ** ** on entry, stack looks like this: ** 8(esp) -> thread *t2 ** 4(esp) -> thread *t1 ** (esp) -> return address ** ** we push the current eax on the stack so that we can use it as ** a pointer to t1, this decrements esp by 4, so when we use it ** to reference stuff on the stack, we add 4 to the offset. */ .comm _eax_save,4 .globl SWITCH SWITCH: movl %eax,_eax_save # save the value of eax movl 4(%esp),%eax # move pointer to t1 into eax movl %ebx,_EBX(%eax) # save registers movl %ecx,_ECX(%eax) movl %edx,_EDX(%eax) movl %esi,_ESI(%eax) movl %edi,_EDI(%eax) movl %ebp,_EBP(%eax) movl %esp,_ESP(%eax) # save stack pointer movl _eax_save,%ebx # get the saved value of eax movl %ebx,_EAX(%eax) # store it movl 0(%esp),%ebx # get return address from stack into ebx movl %ebx,_PC(%eax) # save it into the pc storage movl 8(%esp),%eax # move pointer to t2 into eax movl _EAX(%eax),%ebx # get new value for eax into ebx movl %ebx,_eax_save # save it movl _EBX(%eax),%ebx # retore old registers movl _ECX(%eax),%ecx movl _EDX(%eax),%edx movl _ESI(%eax),%esi movl _EDI(%eax),%edi movl _EBP(%eax),%ebp movl _ESP(%eax),%esp # restore stack pointer movl _PC(%eax),%eax # restore return address into eax movl %eax,4(%esp) # copy over the ret address on the stack movl _eax_save,%eax ret