xref: /minix/minix/lib/libc/arch/i386/sys/ucontext.S (revision 83133719)
1#include <machine/asm.h>
2#include <ucontextoffsets.h>
3
4IMPORT(getuctx)
5IMPORT(setuctx)
6IMPORT(resumecontext)
7
8	.globl	_C_LABEL(__errno)
9
10/* int getcontext(ucontext_t *ucp)
11 *	Initialise the structure pointed to by ucp to the current user context
12 *	of the calling thread. */
13ENTRY(getcontext)
14ENTRY(_getcontext)
15	/* In case a process does not use the FPU and is neither interested in
16	 * saving its signal mask, then we can skip the context switch to
17	 * PM and kernel altogether and only save general-purpose registers. */
18
19	mov 4(%esp), %edx		/* edx = ucp */
20	/* Check null pointer */
21	cmp $0, %edx			/* edx == NULL? */
22	jne 3f				/* Not null, continue */
23	PIC_PROLOGUE
24	call PIC_PLT(_C_LABEL(__errno))
25	PIC_EPILOGUE
26	movl $EFAULT, (%eax)
27	xor %eax, %eax
28	dec %eax			/* return -1 */
29	ret
30
313:	/* Check flags */
32	mov UC_FLAGS(%edx), %eax	/* eax = ucp->uc_flags */
33	and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
34	cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
35	jz 5f				/* Ignore both, skip getuctx */
36	PIC_PROLOGUE
37	push %edx /* push a copy for us */
38	push %edx /* push a copy as function argument */
39	call PIC_PLT(_C_LABEL(getuctx))	/* getuctx(ucp) */
40	pop %edx	/* clean up stack */
41	pop %edx	/* clean up stack and  restore edx */
42	PIC_EPILOGUE
43
445:
45	/* Save the context */
46	pop PC(%edx)			/* Save real RTA in mcp struct */
47	mov %esp, SP(%edx)	/* Save stack pointer (now pointing to ucp) */
48	/* Save GP registers (except EAX and EDX) */
49	mov %ebp, BP(%edx)		/* Save EBP */
50	mov %esi, SI(%edx)		/* Save ESI */
51	mov %edi, DI(%edx)		/* Save EDI */
52	mov %ebx, BX(%edx)		/* Save EBX */
53	mov %ecx, CX(%edx)		/* Save ECX */
54	movl $MCF_MAGIC, MAGIC(%edx)	/* Set magic value */
55	xor %eax, %eax			/* Return 0 */
56	jmp *PC(%edx)  			/* Return return address */
57
58
59/* int setcontext(const ucontext_t *ucp)
60 *	Restore the user context pointed to by ucp. A successful call to
61 *	setcontext does not return; program execution resumes at the point
62 *	specified by the ucp argument. If ucp was created with getcontext(),
63 *	program execution continues as if the corresponding call of getcontext()
64 *	had just returned. If ucp was created with makecontext(), program
65 *	execution continues with the function passed to makecontext(). */
66ENTRY(setcontext)
67	/* In case a process does not use the FPU and is neither interested in
68	 * restoring its signal mask, then we can skip the context switch to
69	 * PM and kernel altogether and restore state here. */
70
71	mov 4(%esp), %edx		/* edx = ucp */
72
73	/* Check null pointer */
74	cmp $0, %edx			/* edx == NULL? */
75	jnz 3f				/* Not null, continue */
76	movl $EFAULT, %edx
770:	push %edx			/* preserve errno */
78	PIC_PROLOGUE
79	call	PIC_PLT(_C_LABEL(__errno))
80	PIC_EPILOGUE
81	pop %edx
82	movl %edx, (%eax)
83	xor %eax, %eax
84	dec %eax			/* return -1 */
85	ret
86
873:	/* Check flags */
88	cmpl $MCF_MAGIC, MAGIC(%edx)	/* is the magic value set (is context valid)?*/
89	jz 4f				/* is set, proceed */
90	movl $EINVAL, %edx		/* not set, return error code */
91	jmp 0b
92
93
944:	mov UC_FLAGS(%edx), %eax	/* eax = ucp->uc_flags */
95	and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
96	cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
97	jz 5f			/* Ignore both, so don't bother restoring FPU
98				 * state and signal mask */
99
100	PIC_PROLOGUE
101	push %edx /* push a copy for us */
102	push %edx /* push a copy as function argument */
103	call PIC_PLT(_C_LABEL(setuctx))	/* setuctx(ucp) */
104	pop %edx	/* clean up stack */
105	pop %edx	/* clean up stack and  restore edx */
106	PIC_EPILOGUE
107
1085:	/* Restore the registers (except EAX and EDX) */
109	mov CX(%edx), %ecx		/* Restore ECX */
110	mov BX(%edx), %ebx		/* Restore EBX */
111	mov DI(%edx), %edi		/* Restore EDI */
112	mov SI(%edx), %esi		/* Restore ESI */
113	mov BP(%edx), %ebp		/* Restore EBP */
114	mov SP(%edx), %esp		/* Restore stack pointer */
115	xor %eax, %eax			/* Return 0 */
116	jmp *PC(%edx)  			/* Return to RTA */
117
118/* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn,
119 *		  ucontext_t *ucp)
120 *	A wrapper to start function `func'. ESI register will contain a pointer
121 *	to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all
122 *	arguments to `func' from the stack. Finally, a call to resumecontext
123 *	will start the next context in the linked list (or exit the program if
124 *	there is no context).
125 *
126 * Since PIC needs the EBX register, which is pushed on the stack by
127 * PIC_PROLOGUE, we need an extra of salsa here.
128 */
129ENTRY(ctx_start)
130	/* 0(esp) -> func
131	 * 4(esp) -> arg1
132	 * ...
133	 * 4*n(esp) -> argn
134	 * 4*(n+1)(esp) -> ucp */
135
136	pop %eax			/* eax = func */
137	call *%eax			/* func(arg1, ..., argn) */
138	PIC_PROLOGUE		/* may push %ebx, but we do not care */
139	mov %esi, %esp		/* Clean up stack, keep %ebx = &GOT */
140	/* ucp is now at the top of the stack again */
141	call PIC_PLT(_C_LABEL(resumecontext))	/* resumecontext(ucp) */
142	ret			/* never reached */
143
144
145