]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/mach/hurd/alpha/trampoline.c
Update.
[thirdparty/glibc.git] / sysdeps / mach / hurd / alpha / trampoline.c
CommitLineData
28f540f4 1/* Set thread_state for sighandler, and sigcontext to recover. Alpha version.
7ce241a0 2 Copyright (C) 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
478b92f0 3 This file is part of the GNU C Library.
28f540f4 4
478b92f0
UD
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
28f540f4 9
478b92f0
UD
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 Library General Public License for more details.
28f540f4 14
478b92f0
UD
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
28f540f4
RM
19
20#include <hurd/signal.h>
21#include "thread_state.h"
22#include <mach/machine/alpha_instruction.h>
23#include "hurdfault.h"
24#include <assert.h>
25
26struct mach_msg_trap_args
27 {
28 /* This is the order of arguments to mach_msg_trap. */
29 mach_msg_header_t *msg;
30 mach_msg_option_t option;
31 mach_msg_size_t send_size;
32 mach_msg_size_t rcv_size;
33 mach_port_t rcv_name;
34 mach_msg_timeout_t timeout;
35 mach_port_t notify;
36 };
37
38
39struct sigcontext *
40_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
41 int signo, long int sigcode,
42 int rpc_wait,
43 struct machine_thread_all_state *state)
44{
45 __label__ trampoline, rpc_wait_trampoline;
46 void *sigsp;
47 struct sigcontext *scp;
48
49 if (ss->context)
50 {
51 /* We have a previous sigcontext that sigreturn was about
52 to restore when another signal arrived. We will just base
53 our setup on that. */
54 if (_hurdsig_catch_fault (SIGSEGV))
55 assert (_hurdsig_fault_sigcode >= (long int) ss->context &&
56 _hurdsig_fault_sigcode < (long int) (ss->context + 1));
57 else
58 {
59 memcpy (&state->basic, &ss->context->sc_alpha_thread_state,
60 sizeof (state->basic));
61 memcpy (&state->exc, &ss->context->sc_alpha_exc_state,
62 sizeof (state->exc));
63 state->set = (1 << ALPHA_THREAD_STATE) | (1 << ALPHA_EXC_STATE);
64 if (state->exc.used_fpa)
65 {
66 memcpy (&state->fpu, &ss->context->sc_alpha_float_state,
67 sizeof (state->fpu));
68 state->set |= (1 << ALPHA_FLOAT_STATE);
69 }
70 assert (! rpc_wait);
71 /* The intr_port slot was cleared before sigreturn sent us the
72 sig_post that made us notice this pending signal, so
73 _hurd_internal_post_signal wouldn't do interrupt_operation.
74 After we return, our caller will set SCP->sc_intr_port (in the
75 new context) from SS->intr_port and clear SS->intr_port. Now
76 that we are restoring this old context recorded by sigreturn,
77 we want to restore its intr_port too; so store it in
78 SS->intr_port now, so it will end up in SCP->sc_intr_port
79 later. */
80 ss->intr_port = ss->context->sc_intr_port;
81 }
82 /* If the sigreturn context was bogus, just ignore it. */
83 ss->context = NULL;
84 }
85 else if (! machine_get_basic_state (ss->thread, state))
86 return NULL;
87
88 if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
7ce241a0 89 !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
28f540f4
RM
90 {
91 sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
7ce241a0 92 ss->sigaltstack.ss_flags |= SS_ONSTACK;
28f540f4
RM
93 /* XXX need to set up base of new stack for
94 per-thread variables, cthreads. */
95 }
96 else
97 sigsp = (char *) state->basic.SP;
98
99 /* Set up the sigcontext structure on the stack. This is all the stack
100 needs, since the args are passed in registers (below). */
101 sigsp -= sizeof (*scp);
102 scp = sigsp;
103
104 if (_hurdsig_catch_fault (SIGSEGV))
105 {
106 assert (_hurdsig_fault_sigcode >= (long int) scp &&
107 _hurdsig_fault_sigcode < (long int) (scp + 1));
108 /* We got a fault trying to write the stack frame.
109 We cannot set up the signal handler.
110 Returning NULL tells our caller, who will nuke us with a SIGILL. */
111 return NULL;
112 }
113 else
114 {
115 /* Set up the sigcontext from the current state of the thread. */
116
7ce241a0 117 scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
28f540f4
RM
118
119 /* struct sigcontext is laid out so that starting at sc_regs
120 mimics a struct alpha_thread_state. */
121 memcpy (&scp->sc_alpha_thread_state,
122 &state->basic, sizeof (state->basic));
123
124 /* struct sigcontext is laid out so that starting at sc_badvaddr
125 mimics a struct mips_exc_state. */
126 if (! machine_get_state (ss->thread, state, ALPHA_EXC_STATE,
127 &state->exc, &scp->sc_alpha_exc_state,
128 sizeof (state->exc)))
129 return NULL;
130
131 if (state->exc.used_fpa &&
132 /* struct sigcontext is laid out so that starting at sc_fpregs
133 mimics a struct alpha_float_state. This state
134 is only meaningful if the coprocessor was used. */
135 ! machine_get_state (ss->thread, state, ALPHA_FLOAT_STATE,
136 &state->fpu,
137 &scp->sc_alpha_float_state,
138 sizeof (state->fpu)))
139 return NULL;
140 }
141
142 /* Modify the thread state to call the trampoline code on the new stack. */
143 if (rpc_wait)
144 {
145 /* The signalee thread was blocked in a mach_msg_trap system call,
146 still waiting for a reply. We will have it run the special
147 trampoline code which retries the message receive before running
148 the signal handler.
478b92f0 149
28f540f4
RM
150 To do this we change the OPTION argument in its registers to
151 enable only message reception, since the request message has
152 already been sent. */
153
154 /* The system call arguments are stored in consecutive registers
155 starting with a0 ($16). */
156 struct mach_msg_trap_args *args = (void *) &state->basic.r16;
157
158 assert (args->option & MACH_RCV_MSG);
159 /* Disable the message-send, since it has already completed. The
160 calls we retry need only wait to receive the reply message. */
161 args->option &= ~MACH_SEND_MSG;
162
54da5be3
RM
163 /* Limit the time to receive the reply message, in case the server
164 claimed that `interrupt_operation' succeeded but in fact the RPC
165 is hung. */
166 args->option |= MACH_RCV_TIMEOUT;
167 args->timeout = _hurd_interrupted_rpc_timeout;
168
28f540f4
RM
169 state->basic.pc = (long int) &&rpc_wait_trampoline;
170 /* After doing the message receive, the trampoline code will need to
171 update the v0 ($0) value to be restored by sigreturn. To simplify
172 the assembly code, we pass the address of its slot in SCP to the
173 trampoline code in at ($28). */
174 state->basic.r28 = (long int) &scp->sc_regs[0];
175 /* We must preserve the mach_msg_trap args in a0..a5 and t0
176 ($16..$21, $1). Pass the handler args to the trampoline code in
177 t8..t10 ($22.$24). */
178 state->basic.r22 = signo;
179 state->basic.r23 = sigcode;
180 state->basic.r24 = (long int) scp;
181 }
182 else
183 {
184 state->basic.pc = (long int) &&trampoline;
185 state->basic.r16 = signo;
186 state->basic.r17 = sigcode;
187 state->basic.r18 = (long int) scp;
188 }
189
190 state->basic.r30 = (long int) sigsp; /* $30 is the stack pointer. */
191
192 /* We pass the handler function to the trampoline code in ra ($26). */
193 state->basic.r26 = (long int) handler;
194 /* In the callee-saved register t12/pv ($27), we store the
195 address of __sigreturn itself, for the trampoline code to use. */
196 state->basic.r27 = (long int) &__sigreturn;
197 /* In the callee-saved register t11/ai ($25), we save the SCP value to pass
198 to __sigreturn after the handler returns. */
199 state->basic.r25 = (long int) scp;
200
201 return scp;
202
203 /* The trampoline code follows. This is not actually executed as part of
204 this function, it is just convenient to write it that way. */
205
206 rpc_wait_trampoline:
207 /* This is the entry point when we have an RPC reply message to receive
208 before running the handler. The MACH_MSG_SEND bit has already been
209 cleared in the OPTION argument in our registers. For our convenience,
210 at ($28) points to the sc_regs[0] member of the sigcontext (saved v0
211 ($0)). */
212 asm volatile
213 (/* Retry the interrupted mach_msg system call. */
214 "lda $0, -25($31)\n" /* mach_msg_trap */
215 "call_pal %0\n" /* Magic system call instruction. */
216 /* When the sigcontext was saved, v0 was MACH_RCV_INTERRUPTED. But
217 now the message receive has completed and the original caller of
218 the RPC (i.e. the code running when the signal arrived) needs to
219 see the final return value of the message receive in v0. So
220 store the new v0 value into the sc_regs[0] member of the sigcontext
221 (whose address is in at to make this code simpler). */
222 "stq $0, 0($28)\n"
223 /* Since the argument registers needed to have the mach_msg_trap
224 arguments, we've stored the arguments to the handler function
225 in registers t8..t10 ($22..$24). */
226 "mov $22, $16\n"
227 "mov $23, $17\n"
228 "mov $24, $18\n"
229 : : "i" (op_chmk));
230
231 trampoline:
232 /* Entry point for running the handler normally. The arguments to the
233 handler function are already in the standard registers:
234
235 a0 SIGNO
236 a1 SIGCODE
237 a2 SCP
238
239 t12 also contains SCP; this value is callee-saved (and so should not get
240 clobbered by running the handler). We use this saved value to pass to
241 __sigreturn, so the handler can clobber the argument registers if it
242 likes. */
243 /* Call the handler function, saving return address in ra ($26). */
244 asm volatile ("jsr $26, ($26)");
245 /* Reset gp ($29) from the return address (here) in ra ($26). */
246 asm volatile ("ldgp $29, 0($26)");
247 asm volatile ("mov $25, $16"); /* Move saved SCP to argument register. */
248 /* Call __sigreturn (SCP); this cannot return. */
249 asm volatile ("jmp $31, ($27)");
250
251 /* NOTREACHED */
252 return NULL;
253}