]>
Commit | Line | Data |
---|---|---|
63d143a2 CM |
1 | /* Copyright (C) 2011 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
3 | Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
16 | License along with the GNU C Library. If not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
63d143a2 CM |
18 | |
19 | #include <sysdep.h> | |
20 | #include <asm/errno.h> | |
21 | #include <arch/spr_def.h> | |
22 | #include <arch/abi.h> | |
23 | ||
24 | #include "ucontext_i.h" | |
25 | ||
26 | /* PL to return to via iret in setcontext */ | |
27 | #define RETURN_PL 0 | |
28 | ||
29 | /* int setcontext (const ucontext_t *ucp) */ | |
30 | ||
31 | .text | |
32 | ENTRY (__setcontext) | |
33 | FEEDBACK_ENTER(__setcontext) | |
34 | ||
35 | /* See if this is a true signal context (flags == 0). | |
36 | If so, restore by invoking rt_sigreturn(). */ | |
37 | #if UC_FLAGS_OFFSET != 0 | |
38 | # error "Add offset to r0 prior to load." | |
39 | #endif | |
0adc5f38 | 40 | LD_PTR r10, r0 |
63d143a2 CM |
41 | { |
42 | BEQZ r10, .Lsigreturn | |
43 | addi r10, r10, -1 /* Confirm that it has value "1". */ | |
44 | } | |
45 | BNEZ r10, .Lbadcontext | |
46 | ||
47 | /* Save lr and r0 briefly on the stack and set the signal mask: | |
48 | rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG / 8). */ | |
49 | { | |
50 | ST sp, lr | |
51 | ADDI_PTR r11, sp, -(2 * REGSIZE) | |
52 | move r10, sp | |
53 | } | |
0adc5f38 CM |
54 | ADDI_PTR sp, sp, -(3 * REGSIZE) |
55 | cfi_def_cfa_offset (3 * REGSIZE) | |
63d143a2 CM |
56 | cfi_offset (lr, 0) |
57 | { | |
58 | ST r11, r10 | |
0adc5f38 | 59 | ADDI_PTR r10, sp, (2 * REGSIZE) |
63d143a2 | 60 | } |
63d143a2 CM |
61 | { |
62 | ST r10, r0 | |
63 | ADDLI_PTR r1, r0, UC_SIGMASK_OFFSET | |
64 | } | |
65 | cfi_offset (r0, -REGSIZE) | |
66 | { | |
67 | movei r3, _NSIG / 8 | |
68 | movei r2, 0 | |
69 | } | |
70 | { | |
71 | movei r0, SIG_SETMASK | |
72 | moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigprocmask | |
73 | } | |
74 | swint1 | |
0adc5f38 | 75 | ADDI_PTR r11, sp, 2 * REGSIZE /* Restore uc_context to r11. */ |
63d143a2 | 76 | { |
0adc5f38 | 77 | LD r11, r11 |
63d143a2 | 78 | ADDI_PTR sp, sp, 3 * REGSIZE |
63d143a2 CM |
79 | } |
80 | cfi_def_cfa_offset (0) | |
81 | LD lr, sp | |
63d143a2 CM |
82 | { |
83 | ADDI_PTR r10, r11, UC_REG(0) | |
84 | BNEZ r1, .Lsyscall_error | |
85 | } | |
86 | ||
87 | /* Restore the argument registers; note they will be random | |
88 | unless makecontext() has been called. */ | |
89 | { LD r0, r10; ADDI_PTR r10, r10, REGSIZE } | |
90 | { LD r1, r10; ADDI_PTR r10, r10, REGSIZE } | |
91 | { LD r2, r10; ADDI_PTR r10, r10, REGSIZE } | |
92 | { LD r3, r10; ADDI_PTR r10, r10, REGSIZE } | |
93 | { LD r4, r10; ADDI_PTR r10, r10, REGSIZE } | |
94 | { LD r5, r10; ADDI_PTR r10, r10, REGSIZE } | |
95 | { LD r6, r10; ADDI_PTR r10, r10, REGSIZE } | |
96 | { LD r7, r10; ADDI_PTR r10, r10, REGSIZE } | |
97 | { LD r8, r10; ADDI_PTR r10, r10, REGSIZE } | |
98 | { LD r9, r10; ADDLI_PTR r10, r10, UC_REG(30) - UC_REG(9) } | |
99 | ||
100 | /* Restore the callee-saved GPRs. */ | |
101 | { LD r30, r10; ADDI_PTR r10, r10, REGSIZE } | |
102 | { LD r31, r10; ADDI_PTR r10, r10, REGSIZE } | |
103 | { LD r32, r10; ADDI_PTR r10, r10, REGSIZE } | |
104 | { LD r33, r10; ADDI_PTR r10, r10, REGSIZE } | |
105 | { LD r34, r10; ADDI_PTR r10, r10, REGSIZE } | |
106 | { LD r35, r10; ADDI_PTR r10, r10, REGSIZE } | |
107 | { LD r36, r10; ADDI_PTR r10, r10, REGSIZE } | |
108 | { LD r37, r10; ADDI_PTR r10, r10, REGSIZE } | |
109 | { LD r38, r10; ADDI_PTR r10, r10, REGSIZE } | |
110 | { LD r39, r10; ADDI_PTR r10, r10, REGSIZE } | |
111 | { LD r40, r10; ADDI_PTR r10, r10, REGSIZE } | |
112 | { LD r41, r10; ADDI_PTR r10, r10, REGSIZE } | |
113 | { LD r42, r10; ADDI_PTR r10, r10, REGSIZE } | |
114 | { LD r43, r10; ADDI_PTR r10, r10, REGSIZE } | |
115 | { LD r44, r10; ADDI_PTR r10, r10, REGSIZE } | |
116 | { LD r45, r10; ADDI_PTR r10, r10, REGSIZE } | |
117 | { LD r46, r10; ADDI_PTR r10, r10, REGSIZE } | |
118 | { LD r47, r10; ADDI_PTR r10, r10, REGSIZE } | |
119 | { LD r48, r10; ADDI_PTR r10, r10, REGSIZE } | |
120 | { LD r49, r10; ADDI_PTR r10, r10, REGSIZE } | |
121 | { LD r50, r10; ADDI_PTR r10, r10, REGSIZE } | |
122 | { LD r51, r10; ADDI_PTR r10, r10, REGSIZE } | |
123 | { LD r52, r10; ADDI_PTR r10, r10, REGSIZE * 2 } | |
124 | /* Skip tp since it must not change for a given thread. */ | |
125 | { LD sp, r10; ADDI_PTR r10, r10, REGSIZE } | |
126 | { LD lr, r10; ADDI_PTR r10, r10, REGSIZE } | |
127 | { LD r11, r10; ADDI_PTR r10, r10, REGSIZE } | |
128 | ||
129 | /* Construct an iret context; we set ICS so we can validly load | |
130 | EX_CONTEXT for iret without being interrupted halfway through. */ | |
131 | { | |
132 | LD r12, r10 | |
133 | movei r13, 1 | |
134 | } | |
135 | { | |
136 | mtspr INTERRUPT_CRITICAL_SECTION, r13 | |
137 | shli r12, r12, SPR_EX_CONTEXT_0_1__ICS_SHIFT | |
138 | } | |
139 | { | |
140 | mtspr EX_CONTEXT_0_0, r11 | |
141 | ori r12, r12, RETURN_PL | |
142 | } | |
143 | mtspr EX_CONTEXT_0_1, r12 | |
144 | iret | |
145 | jrp lr /* keep the backtracer happy */ | |
146 | ||
147 | .Lsigreturn: | |
148 | /* This is a context obtained from a signal handler. | |
149 | Perform a full restore by pushing the context | |
150 | passed onto a simulated signal frame on the stack | |
151 | and call the signal return syscall as if a signal | |
152 | handler exited normally. */ | |
153 | { | |
154 | ADDLI_PTR sp, sp, -(C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE) | |
155 | ADDLI_PTR r1, sp, -UC_SIZE | |
156 | } | |
157 | cfi_def_cfa_offset (C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE) | |
158 | moveli r2, UC_SIZE / REGSIZE | |
159 | 0: { | |
160 | LD r10, r0 | |
161 | ADDI_PTR r0, r0, REGSIZE | |
162 | } | |
163 | { | |
164 | ST r1, r10 | |
165 | ADDI_PTR r1, r1, REGSIZE | |
166 | addi r2, r2, -1 | |
167 | } | |
168 | BNEZ r2, 0b | |
169 | moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigreturn | |
170 | swint1 | |
171 | ||
172 | /* Restore the stack and fall through to the error | |
173 | path. Successful rt_sigreturn never returns to | |
174 | its calling place. */ | |
175 | ADDLI_PTR sp, sp, (C_ABI_SAVE_AREA_SIZE + SI_MAX_SIZE + UC_SIZE) | |
176 | cfi_def_cfa_offset (0) | |
177 | ||
178 | .Lsyscall_error: | |
179 | j SYSCALL_ERROR_NAME | |
180 | ||
181 | .Lbadcontext: | |
182 | { | |
183 | movei r1, EINVAL | |
184 | j SYSCALL_ERROR_NAME | |
185 | } | |
186 | ||
187 | END (__setcontext) | |
188 | ||
189 | .hidden __setcontext | |
190 | weak_alias (__setcontext, setcontext) | |
191 | ||
192 | ENTRY (__startcontext) | |
193 | FEEDBACK_ENTER(__startcontext) | |
194 | BEQZ r30, 1f | |
195 | { | |
196 | move r0, r30 | |
197 | jal __setcontext | |
198 | } | |
199 | 1: j HIDDEN_JUMPTARGET(exit) | |
200 | END (__startcontext) | |
201 | .hidden __startcontext |