1*433d6423SLionel Sambuc#include <machine/asm.h> 2*433d6423SLionel Sambuc#include <ucontextoffsets.h> 3*433d6423SLionel Sambuc 4*433d6423SLionel Sambuc 5*433d6423SLionel SambucIMPORT(getuctx) 6*433d6423SLionel SambucIMPORT(setuctx) 7*433d6423SLionel SambucIMPORT(resumecontext) 8*433d6423SLionel Sambuc 9*433d6423SLionel Sambuc 10*433d6423SLionel Sambuc/* int getcontext(ucontext_t *ucp) 11*433d6423SLionel Sambuc * Initialise the structure pointed to by ucp to the current user context 12*433d6423SLionel Sambuc * of the calling thread. */ 13*433d6423SLionel SambucENTRY(getcontext) 14*433d6423SLionel SambucENTRY(_getcontext) 15*433d6423SLionel Sambuc /* In case a process does not use the FPU and is neither interested in 16*433d6423SLionel Sambuc * saving its signal mask, then we can skip the context switch to 17*433d6423SLionel Sambuc * PM and kernel altogether and only save general-purpose registers. */ 18*433d6423SLionel Sambuc 19*433d6423SLionel Sambuc mov r3, lr /* Save return address: 20*433d6423SLionel Sambuc * When setcontext or swapcontext is called, 21*433d6423SLionel Sambuc * we jump to this address and continue 22*433d6423SLionel Sambuc * running. */ 23*433d6423SLionel Sambuc 24*433d6423SLionel Sambuc /* r0 = ucp */ 25*433d6423SLionel Sambuc 26*433d6423SLionel Sambuc /* Check null pointer */ 27*433d6423SLionel Sambuc cmp r0, #0 /* ucp == NULL? */ 28*433d6423SLionel Sambuc bne 3f /* Not null, continue */ 29*433d6423SLionel Sambuc mov r1, #EFAULT 30*433d6423SLionel Sambuc ldr r2, =_C_LABEL(errno) 31*433d6423SLionel Sambuc str r1, [r2] /* errno = EFAULT */ 32*433d6423SLionel Sambuc mov r0, #-1 /* return -1 */ 33*433d6423SLionel Sambuc bx lr 34*433d6423SLionel Sambuc 35*433d6423SLionel Sambuc3: /* Check flags */ 36*433d6423SLionel Sambuc ldr r1, [r0, #UC_FLAGS] /* r1 = ucp->uc_flags */ 37*433d6423SLionel Sambuc and r1, r1, #[_UC_IGNFPU|_UC_IGNSIGM] 38*433d6423SLionel Sambuc cmp r1, #[_UC_IGNFPU|_UC_IGNSIGM] /* Allowed to ignore both? */ 39*433d6423SLionel Sambuc beq 1f /* If so, skip getuctx */ 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc0: 42*433d6423SLionel Sambuc push {r0, r3} 43*433d6423SLionel Sambuc bl _C_LABEL(getuctx) /* getuctx(ucp) */ 44*433d6423SLionel Sambuc pop {r0, r3} 45*433d6423SLionel Sambuc 46*433d6423SLionel Sambuc1: 47*433d6423SLionel Sambuc /* Save the context */ 48*433d6423SLionel Sambuc mov lr, r3 /* Restore lr */ 49*433d6423SLionel Sambuc str lr, [r0, #LRREG] /* Save lr */ 50*433d6423SLionel Sambuc str lr, [r0, #PCREG] /* Save real RTA in mcp struct */ 51*433d6423SLionel Sambuc str sp, [r0, #SPREG] /* Save stack pointer */ 52*433d6423SLionel Sambuc str fp, [r0, #FPREG] /* Save fp */ 53*433d6423SLionel Sambuc str r4, [r0, #REG4] /* Save r4 */ 54*433d6423SLionel Sambuc str r5, [r0, #REG5] /* Save r5 */ 55*433d6423SLionel Sambuc str r6, [r0, #REG6] /* Save r6 */ 56*433d6423SLionel Sambuc str r7, [r0, #REG7] /* Save r7 */ 57*433d6423SLionel Sambuc str r8, [r0, #REG8] /* Save r8 */ 58*433d6423SLionel Sambuc str r9, [r0, #REG9] /* Save r9 */ 59*433d6423SLionel Sambuc str r10, [r0, #REG10] /* Save r10 */ 60*433d6423SLionel Sambuc 61*433d6423SLionel Sambuc ldr r1, =MCF_MAGIC 62*433d6423SLionel Sambuc str r1, [r0, #MAGIC] /* Set magic value */ 63*433d6423SLionel Sambuc 64*433d6423SLionel Sambuc mov r1, #0 65*433d6423SLionel Sambuc str r1, [r0, #REG0] /* Return 0 */ 66*433d6423SLionel Sambuc mov r0, #0 /* Return 0 */ 67*433d6423SLionel Sambuc 68*433d6423SLionel Sambuc2: 69*433d6423SLionel Sambuc bx lr /* Restore return address */ 70*433d6423SLionel Sambuc 71*433d6423SLionel Sambuc 72*433d6423SLionel Sambuc/* int setcontext(const ucontext_t *ucp) 73*433d6423SLionel Sambuc * Restore the user context pointed to by ucp. A successful call to 74*433d6423SLionel Sambuc * setcontext does not return; program execution resumes at the point 75*433d6423SLionel Sambuc * specified by the ucp argument. If ucp was created with getcontext(), 76*433d6423SLionel Sambuc * program execution continues as if the corresponding call of getcontext() 77*433d6423SLionel Sambuc * had just returned. If ucp was created with makecontext(), program 78*433d6423SLionel Sambuc * execution continues with the function passed to makecontext(). */ 79*433d6423SLionel SambucENTRY(setcontext) 80*433d6423SLionel Sambuc /* In case a process does not use the FPU and is neither interested in 81*433d6423SLionel Sambuc * restoring its signal mask, then we can skip the context switch to 82*433d6423SLionel Sambuc * PM and kernel altogether and restore state here. */ 83*433d6423SLionel Sambuc 84*433d6423SLionel Sambuc /* r0 = ucp */ 85*433d6423SLionel Sambuc 86*433d6423SLionel Sambuc /* Check null pointer */ 87*433d6423SLionel Sambuc cmp r0, #0 /* ucp == NULL? */ 88*433d6423SLionel Sambuc bne 3f /* Not null, continue */ 89*433d6423SLionel Sambuc mov r1, #EFAULT 90*433d6423SLionel Sambuc ldr r2, =_C_LABEL(errno) 91*433d6423SLionel Sambuc str r1, [r2] /* errno = EFAULT */ 92*433d6423SLionel Sambuc mov r0, #-1 /* return -1 */ 93*433d6423SLionel Sambuc bx lr 94*433d6423SLionel Sambuc 95*433d6423SLionel Sambuc3: /* Check flags */ 96*433d6423SLionel Sambuc ldr r1, [r0, #MAGIC] /* r1 = ucp->mc_context.mc_magic */ 97*433d6423SLionel Sambuc ldr r2, =MCF_MAGIC 98*433d6423SLionel Sambuc cmp r1, r2 /* is the magic value set (is context valid)?*/ 99*433d6423SLionel Sambuc beq 4f /* is set, proceed */ 100*433d6423SLionel Sambuc mov r1, #EINVAL /* not set, return error code */ 101*433d6423SLionel Sambuc ldr r2, =_C_LABEL(errno) 102*433d6423SLionel Sambuc str r1, [r2] /* errno = EINVAL */ 103*433d6423SLionel Sambuc mov r0, #-1 /* return -1 */ 104*433d6423SLionel Sambuc bx lr 105*433d6423SLionel Sambuc 106*433d6423SLionel Sambuc 107*433d6423SLionel Sambuc4: ldr r1, [r0, #UC_FLAGS] /* r1 = ucp->uc_flags */ 108*433d6423SLionel Sambuc and r1, r1, #[_UC_IGNFPU|_UC_IGNSIGM] 109*433d6423SLionel Sambuc cmp r1, #[_UC_IGNFPU|_UC_IGNSIGM] /* Allowed to ignore both? */ 110*433d6423SLionel Sambuc beq 1f /* Neither are set, so don't bother restoring FPU 111*433d6423SLionel Sambuc * state and signal mask */ 112*433d6423SLionel Sambuc 113*433d6423SLionel Sambuc push {r0, r3} 114*433d6423SLionel Sambuc0: bl _C_LABEL(setuctx) /* setuctx(ucp) */ 115*433d6423SLionel Sambuc pop {r0, r3} 116*433d6423SLionel Sambuc 117*433d6423SLionel Sambuc1: /* Restore the registers */ 118*433d6423SLionel Sambuc ldr r4, [r0, #REG4] /* Restore r4 */ 119*433d6423SLionel Sambuc ldr r5, [r0, #REG5] /* Restore r5 */ 120*433d6423SLionel Sambuc ldr r6, [r0, #REG6] /* Restore r6 */ 121*433d6423SLionel Sambuc ldr r7, [r0, #REG7] /* Restore r7 */ 122*433d6423SLionel Sambuc ldr r8, [r0, #REG8] /* Restore r8 */ 123*433d6423SLionel Sambuc ldr r9, [r0, #REG9] /* Restore r9 */ 124*433d6423SLionel Sambuc ldr r10, [r0, #REG10] /* Restore r10 */ 125*433d6423SLionel Sambuc ldr r12, [r0, #REG12] /* Restore r12 */ 126*433d6423SLionel Sambuc ldr fp, [r0, #FPREG] /* Restore fp */ 127*433d6423SLionel Sambuc ldr sp, [r0, #SPREG] /* Restore sp */ 128*433d6423SLionel Sambuc ldr lr, [r0, #LRREG] /* Restore lr */ 129*433d6423SLionel Sambuc mov r3, r0 130*433d6423SLionel Sambuc ldr r0, [r3, #REG0] /* Restore r0 */ 131*433d6423SLionel Sambuc2: 132*433d6423SLionel Sambuc ldr pc, [r3, #PCREG] /* Restore pc */ 133*433d6423SLionel Sambuc 134*433d6423SLionel Sambuc 135*433d6423SLionel Sambuc/* void ctx_start() 136*433d6423SLionel Sambuc * A wrapper to call resumecontext. Makecontext puts the ucp in r4. 137*433d6423SLionel Sambuc * This function moves the ucp into r0 so that the ucp is the first 138*433d6423SLionel Sambuc * parameter for resumecontext. The call to resumecontext will start 139*433d6423SLionel Sambuc * the next context in the linked list (or exit the program if there 140*433d6423SLionel Sambuc * is no context). */ 141*433d6423SLionel SambucENTRY(ctx_start) 142*433d6423SLionel Sambuc mov r0, r4 143*433d6423SLionel Sambuc b _C_LABEL(resumecontext) 144