minix3/lib/libc/arch/i386/sys/ucontext.S

145 lines
4.6 KiB
ArmAsm

#include <machine/asm.h>
#include <ucontextoffsets.h>
IMPORT(getuctx)
IMPORT(setuctx)
IMPORT(resumecontext)
.globl _C_LABEL(__errno)
/* int getcontext(ucontext_t *ucp)
* Initialise the structure pointed to by ucp to the current user context
* of the calling thread. */
ENTRY(getcontext)
ENTRY(_getcontext)
/* In case a process does not use the FPU and is neither interested in
* saving its signal mask, then we can skip the context switch to
* PM and kernel altogether and only save general-purpose registers. */
mov 4(%esp), %edx /* edx = ucp */
/* Check null pointer */
cmp $0, %edx /* edx == NULL? */
jne 3f /* Not null, continue */
PIC_PROLOGUE
call PIC_PLT(_C_LABEL(__errno))
PIC_EPILOGUE
movl $EFAULT, (%eax)
xor %eax, %eax
dec %eax /* return -1 */
ret
3: /* Check flags */
mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */
and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
jz 5f /* Ignore both, skip getuctx */
PIC_PROLOGUE
push %edx /* push a copy for us */
push %edx /* push a copy as function argument */
call PIC_PLT(_C_LABEL(getuctx)) /* getuctx(ucp) */
pop %edx /* clean up stack */
pop %edx /* clean up stack and restore edx */
PIC_EPILOGUE
5:
/* Save the context */
pop PC(%edx) /* Save real RTA in mcp struct */
mov %esp, SP(%edx) /* Save stack pointer (now pointing to ucp) */
/* Save GP registers (except EAX and EDX) */
mov %ebp, BP(%edx) /* Save EBP */
mov %esi, SI(%edx) /* Save ESI */
mov %edi, DI(%edx) /* Save EDI */
mov %ebx, BX(%edx) /* Save EBX */
mov %ecx, CX(%edx) /* Save ECX */
movl $MCF_MAGIC, MAGIC(%edx) /* Set magic value */
xor %eax, %eax /* Return 0 */
jmp *PC(%edx) /* Return return address */
/* int setcontext(const ucontext_t *ucp)
* Restore the user context pointed to by ucp. A successful call to
* setcontext does not return; program execution resumes at the point
* specified by the ucp argument. If ucp was created with getcontext(),
* program execution continues as if the corresponding call of getcontext()
* had just returned. If ucp was created with makecontext(), program
* execution continues with the function passed to makecontext(). */
ENTRY(setcontext)
/* In case a process does not use the FPU and is neither interested in
* restoring its signal mask, then we can skip the context switch to
* PM and kernel altogether and restore state here. */
mov 4(%esp), %edx /* edx = ucp */
/* Check null pointer */
cmp $0, %edx /* edx == NULL? */
jnz 3f /* Not null, continue */
movl $EFAULT, %edx
0: push %edx /* preserve errno */
PIC_PROLOGUE
call PIC_PLT(_C_LABEL(__errno))
PIC_EPILOGUE
pop %edx
movl %edx, (%eax)
xor %eax, %eax
dec %eax /* return -1 */
ret
3: /* Check flags */
cmpl $MCF_MAGIC, MAGIC(%edx) /* is the magic value set (is context valid)?*/
jz 4f /* is set, proceed */
movl $EINVAL, %edx /* not set, return error code */
jmp 0b
4: mov UC_FLAGS(%edx), %eax /* eax = ucp->uc_flags */
and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
jz 5f /* Ignore both, so don't bother restoring FPU
* state and signal mask */
PIC_PROLOGUE
push %edx /* push a copy for us */
push %edx /* push a copy as function argument */
call PIC_PLT(_C_LABEL(setuctx)) /* setuctx(ucp) */
pop %edx /* clean up stack */
pop %edx /* clean up stack and restore edx */
PIC_EPILOGUE
5: /* Restore the registers (except EAX and EDX) */
mov CX(%edx), %ecx /* Restore ECX */
mov BX(%edx), %ebx /* Restore EBX */
mov DI(%edx), %edi /* Restore EDI */
mov SI(%edx), %esi /* Restore ESI */
mov BP(%edx), %ebp /* Restore EBP */
mov SP(%edx), %esp /* Restore stack pointer */
xor %eax, %eax /* Return 0 */
jmp *PC(%edx) /* Return to RTA */
/* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn,
* ucontext_t *ucp)
* A wrapper to start function `func'. ESI register will contain a pointer
* to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all
* arguments to `func' from the stack. Finally, a call to resumecontext
* will start the next context in the linked list (or exit the program if
* there is no context).
*
* Since PIC needs the EBX register, which is pushed on the stack by
* PIC_PROLOGUE, we need an extra of salsa here.
*/
ENTRY(ctx_start)
/* 0(esp) -> func
* 4(esp) -> arg1
* ...
* 4*n(esp) -> argn
* 4*(n+1)(esp) -> ucp */
pop %eax /* eax = func */
call *%eax /* func(arg1, ..., argn) */
PIC_PROLOGUE /* may push %ebx, but we do not care */
mov %esi, %esp /* Clean up stack, keep %ebx = &GOT */
/* ucp is now at the top of the stack again */
call PIC_PLT(_C_LABEL(resumecontext)) /* resumecontext(ucp) */
ret /* never reached */