/* i386.s - intel 80386 context switching code for Sequent Symmetry * * (This should work also for other Intel 80386/486/Pentium machines * if they use the same calling sequences and register conventions.) * * A context array is laid out like this: * * saved registers (%ebp, %ebx, %esi, %edi) * magic word for checking integrity * unused stack space * saved %esp <--- saved ebp points here * saved pc (return address) * error routine addr (if code returns, which is an error, it will go here) * arguments from mpd_build_context call * * Registers %ebp, %ebx, %esi, and %edi are saved at the base of the array. * %eax, %ecx, and %edx aren't saved because C doesn't expect them to survive * over function calls. %esp is saved on the stack at subroutine entry. * * Empirical testing (7/91) seems to show that no floating point registers * need be saved for either cc or gcc, either with or without -O. */ #define MAGIC 79797979 /* any unlikely long integer */ #define DMAGIC $79797979 #define RSIZE 16 /* size of register save area */ #define DRSIZE $16 .text #ifdef sequent .align 2 #else .align 4 #endif /* mpd_build_context(code,buf,bufsize,a1,a2,a3,a4) -- create a new context. * * code entry point of the code to be executed in the context * buf buffer for holding the context array * bufsize size of the buffer * a1 - a4 four int-sized arguments to be passed to the code */ .globl MPD_BUILD_CONTEXT MPD_BUILD_CONTEXT: pushl %ebp /* save caller's frame pointer */ movl %esp,%ebp /* save caller's stack pointer */ movl 12(%ebp), %eax /* %eax = pointer to context array */ movl %eax, %esp addl 16(%ebp), %esp /* point stack to end of context array */ pushl 32(%ebp) /* push arg4 */ pushl 28(%ebp) /* push arg3 */ pushl 24(%ebp) /* push arg2 */ pushl 20(%ebp) /* push arg1 */ pushl $under /* push error addr in case context returns */ pushl 8(%ebp) /* push address for startind execution */ pushl $0 /* push dummy frame pointer */ movl %esp, (%eax) /* set initial frame pointer*/ movl DMAGIC, RSIZE(%eax) /* store magic word for integrity check */ movl %ebp,%esp /* restore stack and frame pointers */ popl %ebp ret /* return */ /* mpd_chg_context(newstk,oldstk) -- switch context to the specified stack */ .globl MPD_CHG_CONTEXT MPD_CHG_CONTEXT: pushl %ebp /* save old frame pointer */ movl %esp,%ebp /* save old stack pointer in frame pointer */ movl 12(%ebp),%eax /* load address of current context stack */ cmpl $0,%eax je first /* skip if we don't want to save it */ movl %ebp, 0(%eax) /* save registers in user context block */ movl %ebx, 4(%eax) movl %esi, 8(%eax) movl %edi, 12(%eax) addl DRSIZE,%eax cmpl %eax,%esp /* check that stack isn't overflowing */ jbe over cmpl DMAGIC,(%eax) /* catch earlier overflow (maybe) */ jne over first: movl 8(%ebp), %eax /* load address of new context */ cmpl DMAGIC, RSIZE(%eax) /* make sure new stack looks okay */ jne bad movl 0(%eax), %ebp /* load registers for new context */ movl 4(%eax), %ebx movl 8(%eax), %esi movl 12(%eax), %edi movl %ebp,%esp /* restore %esp and %ebp */ popl %ebp ret /* return into new context */ /* mpd_check_stk(context) -- check that the stack is not overflowing */ .globl MPD_CHECK_STK MPD_CHECK_STK: movl 4(%esp), %eax addl DRSIZE, %eax cmpl %eax, %esp jbe over ret /* stack problem handlers (these calls do not return) */ over: call MPD_STK_OVERFLOW under: call MPD_STK_UNDERFLOW bad: call MPD_STK_CORRUPTED