1 |
1275 |
phoenix |
/*
|
2 |
|
|
* Copyright (C) 2003 Broadcom Corporation
|
3 |
|
|
*
|
4 |
|
|
* This program is free software; you can redistribute it and/or
|
5 |
|
|
* modify it under the terms of the GNU General Public License
|
6 |
|
|
* as published by the Free Software Foundation; either version 2
|
7 |
|
|
* of the License, or (at your option) any later version.
|
8 |
|
|
*
|
9 |
|
|
* This program is distributed in the hope that it will be useful,
|
10 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12 |
|
|
* GNU General Public License for more details.
|
13 |
|
|
*
|
14 |
|
|
* You should have received a copy of the GNU General Public License
|
15 |
|
|
* along with this program; if not, write to the Free Software
|
16 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
17 |
|
|
*/
|
18 |
|
|
|
19 |
|
|
#include <linux/config.h>
|
20 |
|
|
#include <linux/sched.h>
|
21 |
|
|
#include <linux/mm.h>
|
22 |
|
|
#include <linux/smp.h>
|
23 |
|
|
#include <linux/smp_lock.h>
|
24 |
|
|
#include <linux/kernel.h>
|
25 |
|
|
#include <linux/signal.h>
|
26 |
|
|
#include <linux/errno.h>
|
27 |
|
|
#include <linux/wait.h>
|
28 |
|
|
#include <linux/ptrace.h>
|
29 |
|
|
#include <linux/unistd.h>
|
30 |
|
|
|
31 |
|
|
#include <asm/asm.h>
|
32 |
|
|
#include <asm/bitops.h>
|
33 |
|
|
#include <asm/pgalloc.h>
|
34 |
|
|
#include <asm/stackframe.h>
|
35 |
|
|
#include <asm/uaccess.h>
|
36 |
|
|
#include <asm/ucontext.h>
|
37 |
|
|
#include <asm/system.h>
|
38 |
|
|
#include <asm/fpu.h>
|
39 |
|
|
|
40 |
|
|
/*
|
41 |
|
|
* Including <asm/unistd.h would give use the 64-bit syscall numbers ...
|
42 |
|
|
*/
|
43 |
|
|
#define __NR_N32_rt_sigreturn 6211
|
44 |
|
|
#define __NR_N32_restart_syscall 6214
|
45 |
|
|
|
46 |
|
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
47 |
|
|
|
48 |
|
|
/* IRIX compatible stack_t */
|
49 |
|
|
typedef struct sigaltstack32 {
|
50 |
|
|
s32 ss_sp;
|
51 |
|
|
__kernel_size_t32 ss_size;
|
52 |
|
|
int ss_flags;
|
53 |
|
|
} stack32_t;
|
54 |
|
|
|
55 |
|
|
struct ucontextn32 {
|
56 |
|
|
u32 uc_flags;
|
57 |
|
|
s32 uc_link;
|
58 |
|
|
stack32_t uc_stack;
|
59 |
|
|
struct sigcontext uc_mcontext;
|
60 |
|
|
sigset_t uc_sigmask; /* mask last for extensibility */
|
61 |
|
|
};
|
62 |
|
|
|
63 |
|
|
struct rt_sigframe_n32 {
|
64 |
|
|
u32 rs_ass[4]; /* argument save space for o32 */
|
65 |
|
|
u32 rs_code[2]; /* signal trampoline */
|
66 |
|
|
struct siginfo rs_info;
|
67 |
|
|
struct ucontextn32 rs_uc;
|
68 |
|
|
};
|
69 |
|
|
|
70 |
|
|
extern asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
|
71 |
|
|
extern int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
|
72 |
|
|
|
73 |
|
|
asmlinkage void sysn32_rt_sigreturn(abi64_no_regargs, struct pt_regs regs)
|
74 |
|
|
{
|
75 |
|
|
struct rt_sigframe_n32 *frame;
|
76 |
|
|
sigset_t set;
|
77 |
|
|
stack_t st;
|
78 |
|
|
s32 sp;
|
79 |
|
|
|
80 |
|
|
frame = (struct rt_sigframe_n32 *) regs.regs[29];
|
81 |
|
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
82 |
|
|
goto badframe;
|
83 |
|
|
if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
|
84 |
|
|
goto badframe;
|
85 |
|
|
|
86 |
|
|
sigdelsetmask(&set, ~_BLOCKABLE);
|
87 |
|
|
spin_lock_irq(¤t->sigmask_lock);
|
88 |
|
|
current->blocked = set;
|
89 |
|
|
recalc_sigpending(current);
|
90 |
|
|
spin_unlock_irq(¤t->sigmask_lock);
|
91 |
|
|
|
92 |
|
|
if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext))
|
93 |
|
|
goto badframe;
|
94 |
|
|
|
95 |
|
|
/* The ucontext contains a stack32_t, so we must convert! */
|
96 |
|
|
if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
|
97 |
|
|
goto badframe;
|
98 |
|
|
st.ss_size = (long) sp;
|
99 |
|
|
if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
|
100 |
|
|
goto badframe;
|
101 |
|
|
if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
|
102 |
|
|
goto badframe;
|
103 |
|
|
|
104 |
|
|
/* It is more difficult to avoid calling this function than to
|
105 |
|
|
call it and ignore errors. */
|
106 |
|
|
do_sigaltstack(&st, NULL, regs.regs[29]);
|
107 |
|
|
|
108 |
|
|
/*
|
109 |
|
|
* Don't let your children do this ...
|
110 |
|
|
*/
|
111 |
|
|
__asm__ __volatile__(
|
112 |
|
|
"move\t$29, %0\n\t"
|
113 |
|
|
"j\tret_from_sys_call"
|
114 |
|
|
:/* no outputs */
|
115 |
|
|
:"r" (®s));
|
116 |
|
|
/* Unreached */
|
117 |
|
|
|
118 |
|
|
badframe:
|
119 |
|
|
force_sig(SIGSEGV, current);
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
/*
|
123 |
|
|
* Determine which stack to use..
|
124 |
|
|
*/
|
125 |
|
|
static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
126 |
|
|
size_t frame_size)
|
127 |
|
|
{
|
128 |
|
|
unsigned long sp;
|
129 |
|
|
|
130 |
|
|
/* Default to using normal stack */
|
131 |
|
|
sp = regs->regs[29];
|
132 |
|
|
|
133 |
|
|
/*
|
134 |
|
|
* FPU emulator may have it's own trampoline active just
|
135 |
|
|
* above the user stack, 16-bytes before the next lowest
|
136 |
|
|
* 16 byte boundary. Try to avoid trashing it.
|
137 |
|
|
*/
|
138 |
|
|
sp -= 32;
|
139 |
|
|
|
140 |
|
|
/* This is the X/Open sanctioned signal stack switching. */
|
141 |
|
|
if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
|
142 |
|
|
sp = current->sas_ss_sp + current->sas_ss_size;
|
143 |
|
|
|
144 |
|
|
return (void *)((sp - frame_size) & ALMASK);
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
void setup_rt_frame_n32(struct k_sigaction * ka,
|
148 |
|
|
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
|
149 |
|
|
{
|
150 |
|
|
struct rt_sigframe_n32 *frame;
|
151 |
|
|
int err = 0;
|
152 |
|
|
s32 sp;
|
153 |
|
|
|
154 |
|
|
frame = get_sigframe(ka, regs, sizeof(*frame));
|
155 |
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
156 |
|
|
goto give_sigsegv;
|
157 |
|
|
|
158 |
|
|
/*
|
159 |
|
|
* Set up the return code ...
|
160 |
|
|
*
|
161 |
|
|
* li v0, __NR_rt_sigreturn
|
162 |
|
|
* syscall
|
163 |
|
|
*/
|
164 |
|
|
err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0);
|
165 |
|
|
err |= __put_user(0x0000000c , frame->rs_code + 1);
|
166 |
|
|
flush_cache_sigtramp((unsigned long) frame->rs_code);
|
167 |
|
|
|
168 |
|
|
/* Create siginfo. */
|
169 |
|
|
err |= copy_siginfo_to_user(&frame->rs_info, info);
|
170 |
|
|
|
171 |
|
|
/* Create the ucontext. */
|
172 |
|
|
err |= __put_user(0, &frame->rs_uc.uc_flags);
|
173 |
|
|
err |= __put_user(0, &frame->rs_uc.uc_link);
|
174 |
|
|
sp = (int) (long) current->sas_ss_sp;
|
175 |
|
|
err |= __put_user(sp,
|
176 |
|
|
&frame->rs_uc.uc_stack.ss_sp);
|
177 |
|
|
err |= __put_user(sas_ss_flags(regs->regs[29]),
|
178 |
|
|
&frame->rs_uc.uc_stack.ss_flags);
|
179 |
|
|
err |= __put_user(current->sas_ss_size,
|
180 |
|
|
&frame->rs_uc.uc_stack.ss_size);
|
181 |
|
|
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
|
182 |
|
|
err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
|
183 |
|
|
|
184 |
|
|
if (err)
|
185 |
|
|
goto give_sigsegv;
|
186 |
|
|
|
187 |
|
|
/*
|
188 |
|
|
* Arguments to signal handler:
|
189 |
|
|
*
|
190 |
|
|
* a0 = signal number
|
191 |
|
|
* a1 = 0 (should be cause)
|
192 |
|
|
* a2 = pointer to ucontext
|
193 |
|
|
*
|
194 |
|
|
* $25 and c0_epc point to the signal handler, $29 points to
|
195 |
|
|
* the struct rt_sigframe.
|
196 |
|
|
*/
|
197 |
|
|
regs->regs[ 4] = signr;
|
198 |
|
|
regs->regs[ 5] = (unsigned long) &frame->rs_info;
|
199 |
|
|
regs->regs[ 6] = (unsigned long) &frame->rs_uc;
|
200 |
|
|
regs->regs[29] = (unsigned long) frame;
|
201 |
|
|
regs->regs[31] = (unsigned long) frame->rs_code;
|
202 |
|
|
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
|
203 |
|
|
|
204 |
|
|
#if DEBUG_SIG
|
205 |
|
|
printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
|
206 |
|
|
current->comm, current->pid,
|
207 |
|
|
frame, regs->cp0_epc, regs->regs[31]);
|
208 |
|
|
#endif
|
209 |
|
|
return;
|
210 |
|
|
|
211 |
|
|
give_sigsegv:
|
212 |
|
|
if (signr == SIGSEGV)
|
213 |
|
|
ka->sa.sa_handler = SIG_DFL;
|
214 |
|
|
force_sig(SIGSEGV, current);
|
215 |
|
|
}
|