summaryrefslogtreecommitdiff
path: root/minix/lib/libc/arch/i386/sys/ucontext.S
blob: e72331a47867835a1dc910b098aaf80325f6eddc (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
144
#include <machine/asm.h>
#include <ucontextoffsets.h>

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

	.globl	_C_LABEL(__errno)

/* 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 4(%esp), %edx		/* edx = ucp */
	/* Check null pointer */
	cmp $0, %edx			/* edx == NULL? */
	jne 3f				/* Not null, continue */
	PIC_PROLOGUE
	call PIC_PLT(_C_LABEL(__errno))
	PIC_EPILOGUE
	movl $EFAULT, (%eax)
	xor %eax, %eax
	dec %eax			/* return -1 */
	ret
	
3:	/* Check flags */
	mov UC_FLAGS(%edx), %eax	/* eax = ucp->uc_flags */
	and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
	cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
	jz 5f				/* Ignore both, skip getuctx */
	PIC_PROLOGUE
	push %edx /* push a copy for us */
	push %edx /* push a copy as function argument */
	call PIC_PLT(_C_LABEL(getuctx))	/* getuctx(ucp) */
	pop %edx	/* clean up stack */
	pop %edx	/* clean up stack and  restore edx */
	PIC_EPILOGUE

5:
	/* Save the context */
	pop PC(%edx)			/* Save real RTA in mcp struct */
	mov %esp, SP(%edx)	/* Save stack pointer (now pointing to ucp) */
	/* Save GP registers (except EAX and EDX) */
	mov %ebp, BP(%edx)		/* Save EBP */
	mov %esi, SI(%edx)		/* Save ESI */
	mov %edi, DI(%edx)		/* Save EDI */
	mov %ebx, BX(%edx)		/* Save EBX */
	mov %ecx, CX(%edx)		/* Save ECX */
	movl $MCF_MAGIC, MAGIC(%edx)	/* Set magic value */
	xor %eax, %eax			/* Return 0 */
	jmp *PC(%edx)  			/* Return 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. */

	mov 4(%esp), %edx		/* edx = ucp */

	/* Check null pointer */
	cmp $0, %edx			/* edx == NULL? */
	jnz 3f				/* Not null, continue */
	movl $EFAULT, %edx
0:	push %edx			/* preserve errno */
	PIC_PROLOGUE
	call	PIC_PLT(_C_LABEL(__errno))
	PIC_EPILOGUE
	pop %edx
	movl %edx, (%eax)
	xor %eax, %eax
	dec %eax			/* return -1 */
	ret
	
3:	/* Check flags */
	cmpl $MCF_MAGIC, MAGIC(%edx)	/* is the magic value set (is context valid)?*/
	jz 4f				/* is set, proceed */
	movl $EINVAL, %edx		/* not set, return error code */
	jmp 0b


4:	mov UC_FLAGS(%edx), %eax	/* eax = ucp->uc_flags */
	and $[_UC_IGNFPU|_UC_IGNSIGM], %eax
	cmp $[_UC_IGNFPU|_UC_IGNSIGM], %eax
	jz 5f			/* Ignore both, so don't bother restoring FPU
				 * state and signal mask */

	PIC_PROLOGUE
	push %edx /* push a copy for us */
	push %edx /* push a copy as function argument */
	call PIC_PLT(_C_LABEL(setuctx))	/* setuctx(ucp) */
	pop %edx	/* clean up stack */
	pop %edx	/* clean up stack and  restore edx */
	PIC_EPILOGUE

5:	/* Restore the registers (except EAX and EDX) */
	mov CX(%edx), %ecx		/* Restore ECX */
	mov BX(%edx), %ebx		/* Restore EBX */
	mov DI(%edx), %edi		/* Restore EDI */
	mov SI(%edx), %esi		/* Restore ESI */
	mov BP(%edx), %ebp		/* Restore EBP */
	mov SP(%edx), %esp		/* Restore stack pointer */
	xor %eax, %eax			/* Return 0 */
	jmp *PC(%edx)  			/* Return to RTA */

/* void ctx_start((void *func)(int arg1, ..., argn), arg1, ..., argn,
 *		  ucontext_t *ucp)
 *	A wrapper to start function `func'. ESI register will contain a pointer
 *	to ucp on the stack. By setting ESP to ESI, we effectively 'remove' all
 *	arguments to `func' from the stack. Finally, a call to resumecontext
 *	will start the next context in the linked list (or exit the program if
 *	there is no context).
 *
 * Since PIC needs the EBX register, which is pushed on the stack by
 * PIC_PROLOGUE, we need an extra of salsa here.
 */
ENTRY(ctx_start)
	/* 0(esp) -> func
	 * 4(esp) -> arg1
	 * ...
	 * 4*n(esp) -> argn
	 * 4*(n+1)(esp) -> ucp */

	pop %eax			/* eax = func */
	call *%eax			/* func(arg1, ..., argn) */
	PIC_PROLOGUE		/* may push %ebx, but we do not care */
	mov %esi, %esp		/* Clean up stack, keep %ebx = &GOT */
	/* ucp is now at the top of the stack again */
	call PIC_PLT(_C_LABEL(resumecontext))	/* resumecontext(ucp) */
	ret			/* never reached */