summaryrefslogtreecommitdiff
path: root/minix/lib/libc/arch/arm/sys/ucontext.S
blob: 48a29718c7f2f011a02e9a7cd19c9f13ea86da0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <machine/asm.h>
#include <ucontextoffsets.h>


IMPORT(getuctx)
IMPORT(setuctx)
IMPORT(resumecontext)


/* int getcontext(ucontext_t *ucp)
 *	Initialise the structure pointed to by ucp to the current user context
 *	of the calling thread. */
ENTRY(getcontext)
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 */
	and r1, r1, #[_UC_IGNFPU|_UC_IGNSIGM]
	cmp r1, #[_UC_IGNFPU|_UC_IGNSIGM] /* Allowed to ignore both? */
	beq 1f				/* If so, 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 */
	and r1, r1, #[_UC_IGNFPU|_UC_IGNSIGM]
	cmp r1, #[_UC_IGNFPU|_UC_IGNSIGM] /* Allowed to ignore both? */
	beq 1f			/* Neither 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)