1*433d6423SLionel Sambuc#include <machine/asm.h> 2*433d6423SLionel Sambuc#include <ucontextoffsets.h> 3*433d6423SLionel Sambuc 4*433d6423SLionel SambucIMPORT(getuctx) 5*433d6423SLionel SambucIMPORT(setuctx) 6*433d6423SLionel SambucIMPORT(resumecontext) 7*433d6423SLionel Sambuc 8*433d6423SLionel Sambuc .globl _C_LABEL(__errno) 9*433d6423SLionel Sambuc 10*433d6423SLionel Sambuc/* int getcontext(ucontext_t *ucp) 11*433d6423SLionel Sambuc * Initialise the structure pointed to by ucp to the current user context 12*433d6423SLionel Sambuc * of the calling thread. */ 13*433d6423SLionel SambucENTRY(getcontext) 14*433d6423SLionel SambucENTRY(_getcontext) 15*433d6423SLionel Sambuc /* In case a process does not use the FPU and is neither interested in 16*433d6423SLionel Sambuc * saving its signal mask, then we can skip the context switch to 17*433d6423SLionel Sambuc * PM and kernel altogether and only save general-purpose registers. */ 18*433d6423SLionel Sambuc 19*433d6423SLionel Sambuc mov 4(%esp), %edx /* edx = ucp */ 20*433d6423SLionel Sambuc /* Check null pointer */ 21*433d6423SLionel Sambuc cmp $0, %edx /* edx == NULL? */ 22*433d6423SLionel Sambuc jne 3f /* Not null, continue */ 23*433d6423SLionel Sambuc PIC_PROLOGUE 24*433d6423SLionel Sambuc call PIC_PLT(_C_LABEL(__errno)) 25*433d6423SLionel Sambuc PIC_EPILOGUE 26*433d6423SLionel Sambuc movl $EFAULT, (%eax) 27*433d6423SLionel Sambuc xor %eax, %eax 28*433d6423SLionel Sambuc dec %eax /* return -1 */ 29*433d6423SLionel Sambuc ret 30*433d6423SLionel Sambuc 31*433d6423SLionel Sambuc3: /* Check flags */ 32*433d6423SLionel Sambuc mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */ 33*433d6423SLionel Sambuc and $[_UC_IGNFPU|_UC_IGNSIGM], %eax 34*433d6423SLionel Sambuc cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax 35*433d6423SLionel Sambuc jz 5f /* Ignore both, skip getuctx */ 36*433d6423SLionel Sambuc PIC_PROLOGUE 37*433d6423SLionel Sambuc push %edx /* push a copy for us */ 38*433d6423SLionel Sambuc push %edx /* push a copy as function argument */ 39*433d6423SLionel Sambuc call PIC_PLT(_C_LABEL(getuctx)) /* getuctx(ucp) */ 40*433d6423SLionel Sambuc pop %edx /* clean up stack */ 41*433d6423SLionel Sambuc pop %edx /* clean up stack and restore edx */ 42*433d6423SLionel Sambuc PIC_EPILOGUE 43*433d6423SLionel Sambuc 44*433d6423SLionel Sambuc5: 45*433d6423SLionel Sambuc /* Save the context */ 46*433d6423SLionel Sambuc pop PC(%edx) /* Save real RTA in mcp struct */ 47*433d6423SLionel Sambuc mov %esp, SP(%edx) /* Save stack pointer (now pointing to ucp) */ 48*433d6423SLionel Sambuc /* Save GP registers (except EAX and EDX) */ 49*433d6423SLionel Sambuc mov %ebp, BP(%edx) /* Save EBP */ 50*433d6423SLionel Sambuc mov %esi, SI(%edx) /* Save ESI */ 51*433d6423SLionel Sambuc mov %edi, DI(%edx) /* Save EDI */ 52*433d6423SLionel Sambuc mov %ebx, BX(%edx) /* Save EBX */ 53*433d6423SLionel Sambuc mov %ecx, CX(%edx) /* Save ECX */ 54*433d6423SLionel Sambuc movl $MCF_MAGIC, MAGIC(%edx) /* Set magic value */ 55*433d6423SLionel Sambuc xor %eax, %eax /* Return 0 */ 56*433d6423SLionel Sambuc jmp *PC(%edx) /* Return return address */ 57*433d6423SLionel Sambuc 58*433d6423SLionel Sambuc 59*433d6423SLionel Sambuc/* int setcontext(const ucontext_t *ucp) 60*433d6423SLionel Sambuc * Restore the user context pointed to by ucp. A successful call to 61*433d6423SLionel Sambuc * setcontext does not return; program execution resumes at the point 62*433d6423SLionel Sambuc * specified by the ucp argument. If ucp was created with getcontext(), 63*433d6423SLionel Sambuc * program execution continues as if the corresponding call of getcontext() 64*433d6423SLionel Sambuc * had just returned. If ucp was created with makecontext(), program 65*433d6423SLionel Sambuc * execution continues with the function passed to makecontext(). */ 66*433d6423SLionel SambucENTRY(setcontext) 67*433d6423SLionel Sambuc /* In case a process does not use the FPU and is neither interested in 68*433d6423SLionel Sambuc * restoring its signal mask, then we can skip the context switch to 69*433d6423SLionel Sambuc * PM and kernel altogether and restore state here. */ 70*433d6423SLionel Sambuc 71*433d6423SLionel Sambuc mov 4(%esp), %edx /* edx = ucp */ 72*433d6423SLionel Sambuc 73*433d6423SLionel Sambuc /* Check null pointer */ 74*433d6423SLionel Sambuc cmp $0, %edx /* edx == NULL? */ 75*433d6423SLionel Sambuc jnz 3f /* Not null, continue */ 76*433d6423SLionel Sambuc movl $EFAULT, %edx 77*433d6423SLionel Sambuc0: push %edx /* preserve errno */ 78*433d6423SLionel Sambuc PIC_PROLOGUE 79*433d6423SLionel Sambuc call PIC_PLT(_C_LABEL(__errno)) 80*433d6423SLionel Sambuc PIC_EPILOGUE 81*433d6423SLionel Sambuc pop %edx 82*433d6423SLionel Sambuc movl %edx, (%eax) 83*433d6423SLionel Sambuc xor %eax, %eax 84*433d6423SLionel Sambuc dec %eax /* return -1 */ 85*433d6423SLionel Sambuc ret 86*433d6423SLionel Sambuc 87*433d6423SLionel Sambuc3: /* Check flags */ 88*433d6423SLionel Sambuc cmpl $MCF_MAGIC, MAGIC(%edx) /* is the magic value set (is context valid)?*/ 89*433d6423SLionel Sambuc jz 4f /* is set, proceed */ 90*433d6423SLionel Sambuc movl $EINVAL, %edx /* not set, return error code */ 91*433d6423SLionel Sambuc jmp 0b 92*433d6423SLionel Sambuc 93*433d6423SLionel Sambuc 94*433d6423SLionel Sambuc4: mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */ 95*433d6423SLionel Sambuc and $[_UC_IGNFPU|_UC_IGNSIGM], %eax 96*433d6423SLionel Sambuc cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax 97*433d6423SLionel Sambuc jz 5f /* Ignore both, so don't bother restoring FPU 98*433d6423SLionel Sambuc * state and signal mask */ 99*433d6423SLionel Sambuc 100*433d6423SLionel Sambuc PIC_PROLOGUE 101*433d6423SLionel Sambuc push %edx /* push a copy for us */ 102*433d6423SLionel Sambuc push %edx /* push a copy as function argument */ 103*433d6423SLionel Sambuc call PIC_PLT(_C_LABEL(setuctx)) /* setuctx(ucp) */ 104*433d6423SLionel Sambuc pop %edx /* clean up stack */ 105*433d6423SLionel Sambuc pop %edx /* clean up stack and restore edx */ 106*433d6423SLionel Sambuc PIC_EPILOGUE 107*433d6423SLionel Sambuc 108*433d6423SLionel Sambuc5: /* Restore the registers (except EAX and EDX) */ 109*433d6423SLionel Sambuc mov CX(%edx), %ecx /* Restore ECX */ 110*433d6423SLionel Sambuc mov BX(%edx), %ebx /* Restore EBX */ 111*433d6423SLionel Sambuc mov DI(%edx), %edi /* Restore EDI */ 112*433d6423SLionel Sambuc mov SI(%edx), %esi /* Restore ESI */ 113*433d6423SLionel Sambuc mov BP(%edx), %ebp /* Restore EBP */ 114*433d6423SLionel Sambuc mov SP(%edx), %esp /* Restore stack pointer */ 115*433d6423SLionel Sambuc xor %eax, %eax /* Return 0 */ 116*433d6423SLionel Sambuc jmp *PC(%edx) /* Return to RTA */ 117*433d6423SLionel Sambuc 118*433d6423SLionel Sambuc/* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn, 119*433d6423SLionel Sambuc * ucontext_t *ucp) 120*433d6423SLionel Sambuc * A wrapper to start function `func'. ESI register will contain a pointer 121*433d6423SLionel Sambuc * to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all 122*433d6423SLionel Sambuc * arguments to `func' from the stack. Finally, a call to resumecontext 123*433d6423SLionel Sambuc * will start the next context in the linked list (or exit the program if 124*433d6423SLionel Sambuc * there is no context). 125*433d6423SLionel Sambuc * 126*433d6423SLionel Sambuc * Since PIC needs the EBX register, which is pushed on the stack by 127*433d6423SLionel Sambuc * PIC_PROLOGUE, we need an extra of salsa here. 128*433d6423SLionel Sambuc */ 129*433d6423SLionel SambucENTRY(ctx_start) 130*433d6423SLionel Sambuc /* 0(esp) -> func 131*433d6423SLionel Sambuc * 4(esp) -> arg1 132*433d6423SLionel Sambuc * ... 133*433d6423SLionel Sambuc * 4*n(esp) -> argn 134*433d6423SLionel Sambuc * 4*(n+1)(esp) -> ucp */ 135*433d6423SLionel Sambuc 136*433d6423SLionel Sambuc pop %eax /* eax = func */ 137*433d6423SLionel Sambuc call *%eax /* func(arg1, ..., argn) */ 138*433d6423SLionel Sambuc PIC_PROLOGUE /* may push %ebx, but we do not care */ 139*433d6423SLionel Sambuc mov %esi, %esp /* Clean up stack, keep %ebx = &GOT */ 140*433d6423SLionel Sambuc /* ucp is now at the top of the stack again */ 141*433d6423SLionel Sambuc call PIC_PLT(_C_LABEL(resumecontext)) /* resumecontext(ucp) */ 142*433d6423SLionel Sambuc ret /* never reached */ 143*433d6423SLionel Sambuc 144*433d6423SLionel Sambuc 145