minix/lib/libc/arch/arm/sys-minix/ucontext.S
Ben Gras cdf2f55a90 kernel, arm ucontext: ARM DBG=-g run fixes
kernel:
	. modules can be as big as the space (8MB) between them
	  instead of 4MB; memory is slightly bigger with DBG=-g

arm ucontext:
	. r4 is clobbered by the restore function, as it's
	  used as a scratch register, causing problems for the
	  DBG=-g build
	. r1-r3 are safe for scratch registers, as they are
	  caller-save, so use r3 instead; and don't bother
	  restoring r1-r3, but preserve r4

vfs:
	. improve TLL pointer sanity check a bit

Change-Id: I0e3cfc367fdc14477e40d04b5e044f288ca4cc7d
2013-06-24 16:57:30 +02:00

154 lines
4.5 KiB
ArmAsm

#include <machine/asm.h>
#include <ucontextoffsets.h>
IMPORT(getuctx)
IMPORT(setuctx)
IMPORT(resumecontext)
/* 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 r3, lr /* Save return address:
* When setcontext or swapcontext is called,
* we jump to this address and continue
* running. */
/* r0 = ucp */
/* Check null pointer */
cmp r0, #0 /* ucp == NULL? */
bne 3f /* Not null, continue */
mov r1, #EFAULT
ldr r2, =_C_LABEL(errno)
str r1, [r2] /* errno = EFAULT */
mov r0, #-1 /* return -1 */
bx lr
3: /* Check flags */
ldr r1, [r0, #UC_FLAGS] /* r1 = ucp->uc_flags */
mov r2, #(UCF_IGNFPU | UCF_IGNSIGM)
cmp r1, r2 /* is UCF_IGNFPU or UCF_IGNSIGM set? */
beq 1f /* Both are set, skip getuctx */
0:
push {r0, r3}
bl _C_LABEL(getuctx) /* getuctx(ucp) */
pop {r0, r3}
1:
/* Save the context */
mov lr, r3 /* Restore lr */
str lr, [r0, #LRREG] /* Save lr */
str lr, [r0, #PCREG] /* Save real RTA in mcp struct */
str sp, [r0, #SPREG] /* Save stack pointer */
str fp, [r0, #FPREG] /* Save fp */
str r4, [r0, #REG4] /* Save r4 */
str r5, [r0, #REG5] /* Save r5 */
str r6, [r0, #REG6] /* Save r6 */
str r7, [r0, #REG7] /* Save r7 */
str r8, [r0, #REG8] /* Save r8 */
str r9, [r0, #REG9] /* Save r9 */
str r10, [r0, #REG10] /* Save r10 */
ldr r1, =MCF_MAGIC
str r1, [r0, #MAGIC] /* Set magic value */
mov r1, #0
str r1, [r0, #REG0] /* Return 0 */
mov r0, #0 /* Return 0 */
2:
bx lr /* 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. */
/* r0 = ucp */
/* Check null pointer */
cmp r0, #0 /* ucp == NULL? */
bne 3f /* Not null, continue */
mov r1, #EFAULT
ldr r2, =_C_LABEL(errno)
str r1, [r2] /* errno = EFAULT */
mov r0, #-1 /* return -1 */
bx lr
3: /* Check flags */
ldr r1, [r0, #MAGIC] /* r1 = ucp->mc_context.mc_magic */
ldr r2, =MCF_MAGIC
cmp r1, r2 /* is the magic value set (is context valid)?*/
beq 4f /* is set, proceed */
mov r1, #EINVAL /* not set, return error code */
ldr r2, =_C_LABEL(errno)
str r1, [r2] /* errno = EINVAL */
mov r0, #-1 /* return -1 */
bx lr
4: ldr r1, [r0, #UC_FLAGS] /* r1 = ucp->uc_flags */
mov r2, #(UCF_IGNFPU | UCF_IGNSIGM)
cmp r1, r2 /* Are UCF_IGNFPU and UCF_IGNSIGM flags set? */
beq 1f /* Both are set, so don't bother restoring FPU
* state and signal mask */
push {r0, r3}
0: bl _C_LABEL(setuctx) /* setuctx(ucp) */
pop {r0, r3}
1: /* Restore the registers */
ldr r4, [r0, #REG4] /* Restore r4 */
ldr r5, [r0, #REG5] /* Restore r5 */
ldr r6, [r0, #REG6] /* Restore r6 */
ldr r7, [r0, #REG7] /* Restore r7 */
ldr r8, [r0, #REG8] /* Restore r8 */
ldr r9, [r0, #REG9] /* Restore r9 */
ldr r10, [r0, #REG10] /* Restore r10 */
ldr r12, [r0, #REG12] /* Restore r12 */
ldr fp, [r0, #FPREG] /* Restore fp */
ldr sp, [r0, #SPREG] /* Restore sp */
ldr lr, [r0, #LRREG] /* Restore lr */
mov r3, r0
ldr r0, [r3, #REG0] /* Restore r0 */
2:
ldr pc, [r3, #PCREG] /* Restore pc */
/* void ctx_start()
* A wrapper to call resumecontext. Makecontext puts the ucp in r4.
* This function moves the ucp into r0 so that the ucp is the first
* parameter for resumecontext. The call to resumecontext will start
* the next context in the linked list (or exit the program if there
* is no context). */
ENTRY(ctx_start)
mov r0, r4
b _C_LABEL(resumecontext)