minix/lib/libc/arch/i386/sys-minix/ucontext.S
Ben Gras 2fe8fb192f Full switch to clang/ELF. Drop ack. Simplify.
There is important information about booting non-ack images in
docs/UPDATING. ack/aout-format images can't be built any more, and
booting clang/ELF-format ones is a little different. Updating to the
new boot monitor is recommended.

Changes in this commit:

	. drop boot monitor -> allowing dropping ack support
	. facility to copy ELF boot files to /boot so that old boot monitor
	  can still boot fairly easily, see UPDATING
	. no more ack-format libraries -> single-case libraries
	. some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases
	. drop several ack toolchain commands, but not all support
	  commands (e.g. aal is gone but acksize is not yet).
	. a few libc files moved to netbsd libc dir
	. new /bin/date as minix date used code in libc/
	. test compile fix
	. harmonize includes
	. /usr/lib is no longer special: without ack, /usr/lib plays no
	  kind of special bootstrapping role any more and bootstrapping
	  is done exclusively through packages, so releases depend even
	  less on the state of the machine making them now.
	. rename nbsd_lib* to lib*
	. reduce mtree
2012-02-14 14:52:02 +01:00

211 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 */