some coverity fixes.
[minix.git] / lib / libc / sys-minix / _ucontext.c
blob7d9d11d37be65c2942bf48aa44ce0f31c761a687
1 #include <sys/cdefs.h>
2 #include <namespace.h>
3 #include <lib.h>
4 #include <machine/stackframe.h>
5 #include <ucontext.h>
6 #include <signal.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdint.h>
11 #include <stdio.h>
13 void ctx_start(void (*)(void), int, ...);
15 /*===========================================================================*
16 * setuctx *
17 *===========================================================================*/
18 int setuctx(const ucontext_t *ucp)
20 int r;
22 if (ucp == NULL) {
23 errno = EFAULT;
24 return(-1);
27 if (!(ucp->uc_flags & UCF_IGNSIGM)) {
28 /* Set signal mask */
29 if ((r = sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL)) == -1)
30 return(r);
33 if (!(ucp->uc_flags & UCF_IGNFPU)) {
34 if ((r = setmcontext(&(ucp->uc_mcontext))) == -1)
35 return(r);
38 return(0);
42 /*===========================================================================*
43 * getuctx *
44 *===========================================================================*/
45 int getuctx(ucontext_t *ucp)
47 int r;
49 if (ucp == NULL) {
50 errno = EFAULT;
51 return(-1);
54 if (!(ucp->uc_flags & UCF_IGNSIGM)) {
55 /* Get signal mask */
56 if ((r = sigprocmask(0, NULL, &ucp->uc_sigmask)) == -1)
57 return(r);
60 if (!(ucp->uc_flags & UCF_IGNFPU)) {
61 if ((r = getmcontext(&(ucp->uc_mcontext))) != 0)
62 return(r);
65 return(0);
69 /*===========================================================================*
70 * makecontext *
71 *===========================================================================*/
72 void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
74 va_list ap;
75 unsigned int *stack_top;
77 /* There are a number of situations that are erroneous, but we can't actually
78 tell the caller something is wrong, because this is a void function.
79 Instead, mcontext_t contains a magic field that has to be set
80 properly before it can be used. */
81 if (ucp == NULL) {
82 return;
83 } else if ((ucp->uc_stack.ss_sp == NULL) ||
84 (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
85 ucp->uc_mcontext.mc_magic = 0;
86 ucp->uc_mcontext.mc_p_reg.sp = 0;
87 return;
90 if (ucp->uc_mcontext.mc_magic == MCF_MAGIC) {
91 #if defined(__i386__)
92 /* The caller provides a pointer to a stack that we can use to run our
93 context on. When the context starts, control is given to a wrapped
94 start routine, which calls a function and cleans up the stack
95 afterwards. The wrapper needs the address of that function on the
96 stack.
97 The stack will be prepared as follows:
98 func() - start routine
99 arg1 - first argument
101 argn - last argument
102 ucp - context, esp points here when `func' returns
103 _ctx_start pops the address of `func' from the stack and calls it.
104 The stack will then be setup with all arguments for `func'. When
105 `func' returns, _ctx_start cleans up the stack such that ucp is at
106 the top of the stack, ready to be used by resumecontext.
107 Resumecontext, in turn, checks whether another context is ready to
108 be executed (i.e., uc_link != NULL) or exit(2)s the process. */
110 /* Find the top of the stack from which we grow downwards. */
111 stack_top = (unsigned int *) ((uintptr_t ) ucp->uc_stack.ss_sp +
112 ucp->uc_stack.ss_size);
114 /* Align the arguments to 16 bytes (we might lose a few bytes of stack
115 space here).*/
116 stack_top = (unsigned int *) ((uintptr_t) stack_top & ~0xf);
118 /* Make room for 'func', the `func' routine arguments, and ucp. */
119 stack_top -= (1 + argc + 1);
121 /* Adjust the machine context to point to the top of this stack and the
122 program counter to the context start wrapper. */
123 ucp->uc_mcontext.mc_p_reg.fp = 0; /* Clear frame pointer */
124 ucp->uc_mcontext.mc_p_reg.sp = (reg_t) stack_top;
125 ucp->uc_mcontext.mc_p_reg.pc = (reg_t) ctx_start;
127 *stack_top++ = (uintptr_t) func;
129 /* Copy arguments to the stack. */
130 va_start(ap, argc);
131 while (argc-- > 0) {
132 *stack_top++ = va_arg(ap, uintptr_t);
134 va_end(ap);
136 /* Store ucp on the stack */
137 *stack_top = (uintptr_t) ucp;
139 /* Set ESI to point to the base of the stack where ucp is stored, so
140 that the wrapper function knows how to clean up the stack after
141 calling `func' (i.e., how to adjust ESP). */
142 ucp->uc_mcontext.mc_p_reg.si = (reg_t) stack_top;
145 /* If we ran out of stack space, invalidate stack pointer. Eventually,
146 swapcontext will choke on this and return ENOMEM. */
147 if (stack_top == ucp->uc_stack.ss_sp)
148 ucp->uc_mcontext.mc_p_reg.sp = 0;
149 #elif defined(__arm__)
150 /* The caller provides a pointer to a stack that we can use to run our
151 context on. When the context starts, control is given to the
152 requested function. When the function finishes, it returns to the
153 _ctx_start wrapper that calls resumecontext (after setting up
154 resumecontext's parameter).
156 The first four arguments for the function will be passed in
157 regs r0-r3 as specified by the ABI, and the rest will go on
158 the stack. The ucp is saved in r4 so that we can
159 eventually pass it to resumecontext. The r4 register is
160 callee-preserved, so the ucp will remain valid in r4 when
161 _ctx_start runs. _ctx_start will move the ucp from r4 into
162 r0, so that the ucp is the first paramater for resumecontext.
163 Then, _ctx_start will call resumecontext. Resumecontext, in turn,
164 checks whether another context is ready to be executed
165 (i.e., uc_link != NULL) or exit(2)s the process. */
167 /* Find the top of the stack from which we grow downwards. */
168 stack_top = (unsigned int *) ((uintptr_t ) ucp->uc_stack.ss_sp +
169 ucp->uc_stack.ss_size);
171 /* Align the arguments to 16 bytes (we might lose a few bytes of stack
172 space here).*/
173 stack_top = (unsigned int *) ((uintptr_t) stack_top & ~0xf);
175 /* Make room for `func' routine arguments that don't fit in r0-r3 */
176 if (argc > 4)
177 stack_top -= argc - 4;
179 /* Adjust the machine context to point to the top of this stack and the
180 program counter to the 'func' entry point. Set lr to ctx_start, so
181 ctx_start runs after 'func'. Save ucp in r4 */
182 ucp->uc_mcontext.mc_p_reg.fp = 0; /* Clear frame pointer */
183 ucp->uc_mcontext.mc_p_reg.sp = (reg_t) stack_top;
184 ucp->uc_mcontext.mc_p_reg.pc = (reg_t) func;
185 ucp->uc_mcontext.mc_p_reg.lr = (reg_t) ctx_start;
186 ucp->uc_mcontext.mc_p_reg.r4 = (reg_t) ucp;
188 /* Copy arguments to r0-r3 and stack. */
189 va_start(ap, argc);
190 /* Pass up to four arguments in registers. */
191 if (argc-- > 0)
192 ucp->uc_mcontext.mc_p_reg.retreg = va_arg(ap, uintptr_t);
193 if (argc-- > 0)
194 ucp->uc_mcontext.mc_p_reg.r1 = va_arg(ap, uintptr_t);
195 if (argc-- > 0)
196 ucp->uc_mcontext.mc_p_reg.r2 = va_arg(ap, uintptr_t);
197 if (argc-- > 0)
198 ucp->uc_mcontext.mc_p_reg.r3 = va_arg(ap, uintptr_t);
199 /* Pass the rest on the stack. */
200 while (argc-- > 0) {
201 *stack_top++ = va_arg(ap, uintptr_t);
203 va_end(ap);
205 /* If we ran out of stack space, invalidate stack pointer. Eventually,
206 swapcontext will choke on this and return ENOMEM. */
207 if (stack_top == ucp->uc_stack.ss_sp)
208 ucp->uc_mcontext.mc_p_reg.sp = 0;
209 #else
210 # error "Unsupported platform"
211 #endif
216 /*===========================================================================*
217 * swapcontext *
218 *===========================================================================*/
219 int swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
221 int r;
223 if ((oucp == NULL) || (ucp == NULL)) {
224 errno = EFAULT;
225 return(-1);
228 if (ucp->uc_mcontext.mc_p_reg.sp == 0) {
229 /* No stack space. Bail out. */
230 errno = ENOMEM;
231 return(-1);
234 oucp->uc_flags &= ~UCF_SWAPPED;
235 r = getcontext(oucp);
236 if ((r == 0) && !(oucp->uc_flags & UCF_SWAPPED)) {
237 oucp->uc_flags |= UCF_SWAPPED;
238 r = setcontext(ucp);
241 return(r);
245 /*===========================================================================*
246 * resumecontext *
247 *===========================================================================*/
248 void resumecontext(ucontext_t *ucp)
250 if (ucp->uc_link == NULL) exit(0);
252 /* Error handling? Where should the error go to? */
253 (void) setcontext((const ucontext_t *) ucp->uc_link);
255 exit(1); /* Never reached */