xref: /minix3/minix/lib/libc/arch/arm/sys/ucontext.S (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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