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