1 #include <machine/asm.h>
2 #include <ucontextoffsets.h>
25 /* MCF_MAGIC value from <mcontext.h> */
26 #define MCF_MAGIC 0xc0ffee
28 /* Values from <sys/ucontext.h> */
29 #define UCF_IGNFPU 0x002
30 #define UCF_IGNSIGM 0x004
33 /* EINVAL from errno.h */
38 /* int getcontext(ucontext_t *ucp)
39 * Initialise the structure pointed to by ucp to the current user context
40 * of the calling thread. */
42 /* In case a process does not use the FPU and is neither interested in
43 * saving its signal mask, then we can skip the context switch to
44 * PM and kernel altogether and only save general-purpose registers. */
46 mov (%esp), %ecx /* Save return address:
47 * When setcontext or swapcontext is called,
48 * we jump to this address and continue
51 mov 4(%esp), %edx /* edx = ucp */
52 /* Check null pointer */
53 cmp $0, %edx /* edx == NULL? */
54 jne 3f /* Not null, continue */
55 movl $EFAULT, (_C_LABEL(errno))
57 dec %eax /* return -1 */
61 push %ecx /* save ecx */
62 push %ebx /* save ebx */
63 lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
64 mov (%ebx), %ecx /* ecx = ucp->uc_flags */
67 cmp %eax, %ecx /* is UCF_IGNFPU or UCF_IGNSIGM set? */
68 pop %ebx /* restore ebx */
69 pop %ecx /* restore ecx */
70 jz 1f /* Both are set, skip getuctx */
73 push %ecx /* Save ecx */
75 call _C_LABEL(getuctx) /* getuctx(ucp) */
76 pop %edx /* clean up stack and restore edx */
77 pop %ecx /* Restore ecx */
80 /* Save the context */
81 mov 4(%esp), %edx /* edx = ucp */
82 pop %eax /* retaddr */
83 mov %eax, PC(%edx) /* Save real RTA in mcp struct */
84 mov %esp, SP(%edx) /* Save stack pointer (now pointing to ucp) */
85 /* Save GP registers */
86 mov %ebp, BP(%edx) /* Save EBP */
87 mov %esi, SI(%edx) /* Save ESI */
88 mov %edi, DI(%edx) /* Save EDI */
89 mov %ebx, BX(%edx) /* Save EBX */
90 mov %ecx, CX(%edx) /* Save ECX */
91 movl $MCF_MAGIC, MAGIC(%edx) /* Set magic value */
92 push %eax /* Restore retaddr */
94 xor %eax, %eax /* Return 0 */
97 add $4, %esp /* Remove stale (setcontext) RTA */
98 jmp *%ecx /* Restore return address */
101 /* int setcontext(const ucontext_t *ucp)
102 * Restore the user context pointed to by ucp. A successful call to
103 * setcontext does not return; program execution resumes at the point
104 * specified by the ucp argument. If ucp was created with getcontext(),
105 * program execution continues as if the corresponding call of getcontext()
106 * had just returned. If ucp was created with makecontext(), program
107 * execution continues with the function passed to makecontext(). */
109 /* In case a process does not use the FPU and is neither interested in
110 * restoring its signal mask, then we can skip the context switch to
111 * PM and kernel altogether and restore state here. */
113 mov 4(%esp), %edx /* edx = ucp */
115 /* Check null pointer */
116 cmp $0, %edx /* edx == NULL? */
117 jnz 3f /* Not null, continue */
118 movl $EFAULT, (_C_LABEL(errno))
120 dec %eax /* return -1 */
124 push %ebx /* save ebx */
125 lea MAGIC(%edx), %ebx /* ebx = &(ucp->mc_context.mc_magic) */
126 mov (%ebx), %ecx /* ecx = ucp->mc_context.mc_magic */
127 pop %ebx /* restore ebx */
128 cmp $MCF_MAGIC, %ecx /* is the magic value set (is context valid)?*/
129 jz 4f /* is set, proceed */
130 movl $EINVAL, (_C_LABEL(errno)) /* not set, return error code */
132 dec %eax /* return -1 */
136 4: push %ebx /* save ebx */
137 lea UC_FLAGS(%edx), %ebx /* ebx = &(ucp->uc_flags) */
138 mov (%ebx), %ecx /* ecx = ucp->uc_flags */
139 pop %ebx /* restore ebx */
140 mov $UCF_IGNFPU, %eax
141 or $UCF_IGNSIGM, %eax
142 cmp %eax, %ecx /* Are UCF_IGNFPU and UCF_IGNSIGM flags set? */
143 jz 1f /* Both are set, so don't bother restoring FPU
144 * state and signal mask */
146 0: push %ecx /* Save ecx */
148 call _C_LABEL(setuctx) /* setuctx(ucp) */
149 pop %edx /* Clean up stack and restore edx */
150 pop %ecx /* Restore ecx */
152 1: /* Restore the registers */
153 mov 4(%esp), %edx /* edx = ucp */
154 mov CX(%edx), %ecx /* Restore ECX */
155 mov BX(%edx), %ebx /* Restore EBX */
156 mov DI(%edx), %edi /* Restore EDI */
157 mov SI(%edx), %esi /* Restore ESI */
158 mov BP(%edx), %ebp /* Restore EBP */
159 mov SP(%edx), %esp /* Restore stack pointer */
162 jmp *PC(%edx) /* Push RTA onto stack so we can return to it */
165 /* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn,
167 * A wrapper to start function `func'. ESI register will contain a pointer
168 * to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all
169 * arguments to `func' from the stack. Finally, a call to resumecontext
170 * will start the next context in the linked list (or exit the program if
171 * there is no context). */
177 * 4*(n+1)(esp) -> ucp */
179 pop %eax /* eax = func */
180 call *%eax /* func(arg1, ..., argn) */
181 mov %esi, %esp /* Clean up stack */
182 /* ucp is now at the top of the stack again */
183 call _C_LABEL(resumecontext) /* resumecontext(ucp) */
184 ret /* never reached */