summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/sparc/setcontext.S
blob: 48ab5f719c598b2eb99f787c0c47bccd17b3f9bd (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
/* Install given context.
   Copyright (C) 2008-2016 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by David S. Miller <davem@davemloft.net>, 2008.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#include <sysdep.h>

#include "ucontext_i.h"

#define ST_FLUSH_WINDOWS 3

/*  int __setcontext (const ucontext_t *ucp)

  Restores the machine context in UCP and thereby resumes execution
  in that context.

  This implementation is intended to be used for *synchronous* context
  switches only.  Therefore, it does not have to restore anything
  other than the PRESERVED state.  */

ENTRY(__setcontext)
	save	%sp, -112, %sp

	mov	SIG_SETMASK, %o0
	add	%i0, UC_SIGMASK, %o1
	clr	%o2
	mov	8, %o3
	mov	__NR_rt_sigprocmask, %g1
	ta	0x10

	/* This is a bit on the expensive side, and we could optimize
	   the unwind similar to how the 32-bit sparc longjmp code
	   does if performance of this routine really matters.  */
	ta	ST_FLUSH_WINDOWS

	ldub	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_EN], %g1
	cmp	%g1, 0
	be	1f
	 nop
	ld	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_FSR], %fsr
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D0], %f0
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D2], %f2
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D4], %f4
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D6], %f6
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D8], %f8
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D10], %f10
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D12], %f12
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D14], %f14
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D16], %f16
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D18], %f18
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D20], %f20
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D22], %f22
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D24], %f24
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D26], %f26
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D28], %f28
	ldd	[%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D30], %f30
1:
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_Y], %g1
	wr	%g1, 0x0, %y

	/* We specifically do not restore %g1 since we need it here as
	   a temporary.  */
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G2], %g2
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G3], %g3
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G4], %g4
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G5], %g5
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G6], %g6
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_G7], %g7
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O1], %i1
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O2], %i2
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O3], %i3
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O4], %i4
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O5], %i5
	ld	[%i0 + UC_MCONTEXT + MC_GREGS + GREG_O6], %i6
	restore
	ld	[%o0 + UC_MCONTEXT + MC_GREGS + GREG_O7], %o7
	ld	[%o0 + UC_MCONTEXT + MC_GREGS + GREG_PC], %g1
	jmpl	%g1, %g0
	 ld	[%o0 + UC_MCONTEXT + MC_GREGS + GREG_O0], %o0
END(__setcontext)

weak_alias (__setcontext, setcontext)

/* We add an NOP here to separate between __setcontext/__startcontext. The
   wanted behavior that happens is: when unwinding from a function called
   inside a makecontext() context, FDE lookup will use '&__startcontext - 1',
   then returns NULL for no FDE found, and immediately ends the unwind, in
   a normal fashion.

   If this NOP word does not exist, FDE lookup just repeatedly finds
   __setcontext's FDE in an infinite loop, due to the convention of using
   'address - 1' for FDE lookup. Modifiying/deleting the below
   __startcontext's FDE has no help on this.  */

	nop

/* This is the helper code which gets called if a function which is
   registered with 'makecontext' returns.  In this case we have to
   install the context listed in the uc_link element of the context
   'makecontext' manipulated at the time of the 'makecontext' call.
   If the pointer is NULL the process must terminate.  */

ENTRY(__start_context)
	ld	[%sp + (16 * 4)], %g1
	cmp	%g1, 0
	be,a	1f
	 clr	%o0
	call	__setcontext
	 mov	%g1, %o0
	/* If this returns (which can happen if the syscall fails) we'll
	   exit the program with the return error value (-1).  */
1:	call	HIDDEN_JUMPTARGET(exit)
	 nop
	/* The 'exit' call should never return.  In case it does cause
	   the process to terminate.  */
	unimp
END(__start_context)