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