4f294c247f
This patch mainly copies and modifies files existing in the current libc implementing minix specific functions. To keep consisten with the NetBSD libc, we remove namespace stubs and we use "namespace.h" and weak links.
210 lines
5.7 KiB
ArmAsm
210 lines
5.7 KiB
ArmAsm
#include <machine/asm.h>
|
|
|
|
#ifdef __ACK__
|
|
.text
|
|
begtext:
|
|
#ifdef __ACK__
|
|
.rom
|
|
#else
|
|
.data
|
|
#endif
|
|
begrom:
|
|
.data
|
|
begdata:
|
|
.bss
|
|
begbss:
|
|
#endif
|
|
|
|
|
|
IMPORT(getuctx)
|
|
IMPORT(setuctx)
|
|
IMPORT(resumecontext)
|
|
|
|
|
|
/* Offsets into ucontext_t structure. Keep in sync with <sys/ucontext.h>! */
|
|
#define UC_FLAGS 0
|
|
#define UC_LINK UC_FLAGS + 4
|
|
#define MCTX UC_LINK + 4
|
|
#define MAGIC MCTX
|
|
#define GS MAGIC+4
|
|
#define FS GS+2
|
|
#define ES FS+2
|
|
#define DS ES+2
|
|
#define DI DS+2
|
|
#define SI DI+4
|
|
#define BP SI+4
|
|
#define ST BP+4 /* Hole for another SP */
|
|
#define BX ST+4
|
|
#define DX BX+4
|
|
#define CX DX+4
|
|
#define AX CX+4
|
|
#define RETADR AX+4
|
|
#define PC RETADR+4
|
|
#define CS PC+4
|
|
#define PSW CS+4
|
|
#define SP PSW+4
|
|
#define SS SP+4
|
|
|
|
|
|
/* MCF_MAGIC value from <mcontext.h> */
|
|
#define MCF_MAGIC 0xc0ffee
|
|
|
|
/* Values from <sys/ucontext.h> */
|
|
#define UCF_IGNFPU 0x002
|
|
#define UCF_IGNSIGM 0x004
|
|
|
|
|
|
/* EINVAL from errno.h */
|
|
#define EFAULT 14
|
|
#define EINVAL 22
|
|
|
|
|
|
/* int getcontext(ucontext_t *ucp)
|
|
* Initialise the structure pointed to by ucp to the current user context
|
|
* of the calling thread. */
|
|
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 (%esp), %ecx /* Save return address:
|
|
* When setcontext or swapcontext is called,
|
|
* we jump to this address and continue
|
|
* running. */
|
|
|
|
mov 4(%esp), %edx /* edx = ucp */
|
|
/* Check null pointer */
|
|
cmp $0, %edx /* edx == NULL? */
|
|
jne 3f /* Not null, continue */
|
|
movl $EFAULT, (_C_LABEL(errno))
|
|
xor %eax, %eax
|
|
dec %eax /* return -1 */
|
|
ret
|
|
|
|
3: /* Check flags */
|
|
push %ecx /* save ecx */
|
|
push %ebx /* save ebx */
|
|
lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
|
|
mov (%ebx), %ecx /* ecx = ucp->uc_flags */
|
|
mov $UCF_IGNFPU, %eax
|
|
or $UCF_IGNSIGM, %eax
|
|
cmp %eax, %ecx /* is UCF_IGNFPU or UCF_IGNSIGM set? */
|
|
pop %ebx /* restore ebx */
|
|
pop %ecx /* restore ecx */
|
|
jz 1f /* Both are set, skip getuctx */
|
|
|
|
0:
|
|
push %ecx /* Save ecx */
|
|
push %edx
|
|
call _C_LABEL(getuctx) /* getuctx(ucp) */
|
|
pop %edx /* clean up stack and restore edx */
|
|
pop %ecx /* Restore ecx */
|
|
|
|
1:
|
|
/* Save the context */
|
|
mov 4(%esp), %edx /* edx = ucp */
|
|
pop %eax /* retaddr */
|
|
mov %eax, PC(%edx) /* Save real RTA in mcp struct */
|
|
mov %esp, SP(%edx) /* Save stack pointer (now pointing to ucp) */
|
|
/* Save GP registers */
|
|
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 */
|
|
push %eax /* Restore retaddr */
|
|
|
|
xor %eax, %eax /* Return 0 */
|
|
|
|
2:
|
|
add $4, %esp /* Remove stale (setcontext) RTA */
|
|
jmp *%ecx /* Restore 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, (_C_LABEL(errno))
|
|
xor %eax, %eax
|
|
dec %eax /* return -1 */
|
|
ret
|
|
|
|
3: /* Check flags */
|
|
push %ebx /* save ebx */
|
|
lea MAGIC(%edx), %ebx /* ebx = &(ucp->mc_context.mc_magic) */
|
|
mov (%ebx), %ecx /* ecx = ucp->mc_context.mc_magic */
|
|
pop %ebx /* restore ebx */
|
|
cmp $MCF_MAGIC, %ecx /* is the magic value set (is context valid)?*/
|
|
jz 4f /* is set, proceed */
|
|
movl $EINVAL, (_C_LABEL(errno)) /* not set, return error code */
|
|
xor %eax, %eax
|
|
dec %eax /* return -1 */
|
|
ret
|
|
|
|
|
|
4: push %ebx /* save ebx */
|
|
lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
|
|
mov (%ebx), %ecx /* ecx = ucp->uc_flags */
|
|
pop %ebx /* restore ebx */
|
|
mov $UCF_IGNFPU, %eax
|
|
or $UCF_IGNSIGM, %eax
|
|
cmp %eax, %ecx /* Are UCF_IGNFPU and UCF_IGNSIGM flags set? */
|
|
jz 1f /* Both are set, so don't bother restoring FPU
|
|
* state and signal mask */
|
|
|
|
0: push %ecx /* Save ecx */
|
|
push %edx
|
|
call _C_LABEL(setuctx) /* setuctx(ucp) */
|
|
pop %edx /* Clean up stack and restore edx */
|
|
pop %ecx /* Restore ecx */
|
|
|
|
1: /* Restore the registers */
|
|
mov 4(%esp), %edx /* edx = ucp */
|
|
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 */
|
|
|
|
2:
|
|
jmp *PC(%edx) /* Push RTA onto stack so we can return to it */
|
|
|
|
|
|
/* 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). */
|
|
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) */
|
|
mov %esi, %esp /* Clean up stack */
|
|
/* ucp is now at the top of the stack again */
|
|
call _C_LABEL(resumecontext) /* resumecontext(ucp) */
|
|
ret /* never reached */
|
|
|
|
|