diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/kernel/signal_o32.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/kernel/signal_o32.c')
-rw-r--r-- | arch/mips/kernel/signal_o32.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/arch/mips/kernel/signal_o32.c b/arch/mips/kernel/signal_o32.c new file mode 100644 index 000000000..299a7a28c --- /dev/null +++ b/arch/mips/kernel/signal_o32.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
7 | * Copyright (C) 1994 - 2000, 2006 Ralf Baechle | ||
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | ||
9 | * Copyright (C) 2016, Imagination Technologies Ltd. | ||
10 | */ | ||
11 | #include <linux/compiler.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/signal.h> | ||
14 | #include <linux/sched/signal.h> | ||
15 | #include <linux/uaccess.h> | ||
16 | |||
17 | #include <asm/abi.h> | ||
18 | #include <asm/compat-signal.h> | ||
19 | #include <asm/dsp.h> | ||
20 | #include <asm/sim.h> | ||
21 | #include <asm/unistd.h> | ||
22 | |||
23 | #include "signal-common.h" | ||
24 | |||
25 | /* | ||
26 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... | ||
27 | */ | ||
28 | #define __NR_O32_restart_syscall 4253 | ||
29 | |||
30 | struct sigframe32 { | ||
31 | u32 sf_ass[4]; /* argument save space for o32 */ | ||
32 | u32 sf_pad[2]; /* Was: signal trampoline */ | ||
33 | struct sigcontext32 sf_sc; | ||
34 | compat_sigset_t sf_mask; | ||
35 | }; | ||
36 | |||
37 | struct ucontext32 { | ||
38 | u32 uc_flags; | ||
39 | s32 uc_link; | ||
40 | compat_stack_t uc_stack; | ||
41 | struct sigcontext32 uc_mcontext; | ||
42 | compat_sigset_t uc_sigmask; /* mask last for extensibility */ | ||
43 | }; | ||
44 | |||
45 | struct rt_sigframe32 { | ||
46 | u32 rs_ass[4]; /* argument save space for o32 */ | ||
47 | u32 rs_pad[2]; /* Was: signal trampoline */ | ||
48 | compat_siginfo_t rs_info; | ||
49 | struct ucontext32 rs_uc; | ||
50 | }; | ||
51 | |||
52 | static int setup_sigcontext32(struct pt_regs *regs, | ||
53 | struct sigcontext32 __user *sc) | ||
54 | { | ||
55 | int err = 0; | ||
56 | int i; | ||
57 | |||
58 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | ||
59 | |||
60 | err |= __put_user(0, &sc->sc_regs[0]); | ||
61 | for (i = 1; i < 32; i++) | ||
62 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | ||
63 | |||
64 | err |= __put_user(regs->hi, &sc->sc_mdhi); | ||
65 | err |= __put_user(regs->lo, &sc->sc_mdlo); | ||
66 | if (cpu_has_dsp) { | ||
67 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
68 | err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
69 | err |= __put_user(mflo1(), &sc->sc_lo1); | ||
70 | err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
71 | err |= __put_user(mflo2(), &sc->sc_lo2); | ||
72 | err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
73 | err |= __put_user(mflo3(), &sc->sc_lo3); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Save FPU state to signal context. Signal handler | ||
78 | * will "inherit" current FPU state. | ||
79 | */ | ||
80 | err |= protected_save_fp_context(sc); | ||
81 | |||
82 | return err; | ||
83 | } | ||
84 | |||
85 | static int restore_sigcontext32(struct pt_regs *regs, | ||
86 | struct sigcontext32 __user *sc) | ||
87 | { | ||
88 | int err = 0; | ||
89 | s32 treg; | ||
90 | int i; | ||
91 | |||
92 | /* Always make any pending restarted system calls return -EINTR */ | ||
93 | current->restart_block.fn = do_no_restart_syscall; | ||
94 | |||
95 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | ||
96 | err |= __get_user(regs->hi, &sc->sc_mdhi); | ||
97 | err |= __get_user(regs->lo, &sc->sc_mdlo); | ||
98 | if (cpu_has_dsp) { | ||
99 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
100 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
101 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
102 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
103 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
104 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
105 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
106 | } | ||
107 | |||
108 | for (i = 1; i < 32; i++) | ||
109 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | ||
110 | |||
111 | return err ?: protected_restore_fp_context(sc); | ||
112 | } | ||
113 | |||
114 | static int setup_frame_32(void *sig_return, struct ksignal *ksig, | ||
115 | struct pt_regs *regs, sigset_t *set) | ||
116 | { | ||
117 | struct sigframe32 __user *frame; | ||
118 | int err = 0; | ||
119 | |||
120 | frame = get_sigframe(ksig, regs, sizeof(*frame)); | ||
121 | if (!access_ok(frame, sizeof (*frame))) | ||
122 | return -EFAULT; | ||
123 | |||
124 | err |= setup_sigcontext32(regs, &frame->sf_sc); | ||
125 | err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); | ||
126 | |||
127 | if (err) | ||
128 | return -EFAULT; | ||
129 | |||
130 | /* | ||
131 | * Arguments to signal handler: | ||
132 | * | ||
133 | * a0 = signal number | ||
134 | * a1 = 0 (should be cause) | ||
135 | * a2 = pointer to struct sigcontext | ||
136 | * | ||
137 | * $25 and c0_epc point to the signal handler, $29 points to the | ||
138 | * struct sigframe. | ||
139 | */ | ||
140 | regs->regs[ 4] = ksig->sig; | ||
141 | regs->regs[ 5] = 0; | ||
142 | regs->regs[ 6] = (unsigned long) &frame->sf_sc; | ||
143 | regs->regs[29] = (unsigned long) frame; | ||
144 | regs->regs[31] = (unsigned long) sig_return; | ||
145 | regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; | ||
146 | |||
147 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", | ||
148 | current->comm, current->pid, | ||
149 | frame, regs->cp0_epc, regs->regs[31]); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | asmlinkage void sys32_rt_sigreturn(void) | ||
155 | { | ||
156 | struct rt_sigframe32 __user *frame; | ||
157 | struct pt_regs *regs; | ||
158 | sigset_t set; | ||
159 | int sig; | ||
160 | |||
161 | regs = current_pt_regs(); | ||
162 | frame = (struct rt_sigframe32 __user *)regs->regs[29]; | ||
163 | if (!access_ok(frame, sizeof(*frame))) | ||
164 | goto badframe; | ||
165 | if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) | ||
166 | goto badframe; | ||
167 | |||
168 | set_current_blocked(&set); | ||
169 | |||
170 | sig = restore_sigcontext32(regs, &frame->rs_uc.uc_mcontext); | ||
171 | if (sig < 0) | ||
172 | goto badframe; | ||
173 | else if (sig) | ||
174 | force_sig(sig); | ||
175 | |||
176 | if (compat_restore_altstack(&frame->rs_uc.uc_stack)) | ||
177 | goto badframe; | ||
178 | |||
179 | /* | ||
180 | * Don't let your children do this ... | ||
181 | */ | ||
182 | __asm__ __volatile__( | ||
183 | "move\t$29, %0\n\t" | ||
184 | "j\tsyscall_exit" | ||
185 | : /* no outputs */ | ||
186 | : "r" (regs)); | ||
187 | /* Unreached */ | ||
188 | |||
189 | badframe: | ||
190 | force_sig(SIGSEGV); | ||
191 | } | ||
192 | |||
193 | static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, | ||
194 | struct pt_regs *regs, sigset_t *set) | ||
195 | { | ||
196 | struct rt_sigframe32 __user *frame; | ||
197 | int err = 0; | ||
198 | |||
199 | frame = get_sigframe(ksig, regs, sizeof(*frame)); | ||
200 | if (!access_ok(frame, sizeof (*frame))) | ||
201 | return -EFAULT; | ||
202 | |||
203 | /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ | ||
204 | err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); | ||
205 | |||
206 | /* Create the ucontext. */ | ||
207 | err |= __put_user(0, &frame->rs_uc.uc_flags); | ||
208 | err |= __put_user(0, &frame->rs_uc.uc_link); | ||
209 | err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); | ||
210 | err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); | ||
211 | err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); | ||
212 | |||
213 | if (err) | ||
214 | return -EFAULT; | ||
215 | |||
216 | /* | ||
217 | * Arguments to signal handler: | ||
218 | * | ||
219 | * a0 = signal number | ||
220 | * a1 = 0 (should be cause) | ||
221 | * a2 = pointer to ucontext | ||
222 | * | ||
223 | * $25 and c0_epc point to the signal handler, $29 points to | ||
224 | * the struct rt_sigframe32. | ||
225 | */ | ||
226 | regs->regs[ 4] = ksig->sig; | ||
227 | regs->regs[ 5] = (unsigned long) &frame->rs_info; | ||
228 | regs->regs[ 6] = (unsigned long) &frame->rs_uc; | ||
229 | regs->regs[29] = (unsigned long) frame; | ||
230 | regs->regs[31] = (unsigned long) sig_return; | ||
231 | regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; | ||
232 | |||
233 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", | ||
234 | current->comm, current->pid, | ||
235 | frame, regs->cp0_epc, regs->regs[31]); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * o32 compatibility on 64-bit kernels, without DSP ASE | ||
242 | */ | ||
243 | struct mips_abi mips_abi_32 = { | ||
244 | .setup_frame = setup_frame_32, | ||
245 | .setup_rt_frame = setup_rt_frame_32, | ||
246 | .restart = __NR_O32_restart_syscall, | ||
247 | |||
248 | .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), | ||
249 | .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), | ||
250 | .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), | ||
251 | |||
252 | .vdso = &vdso_image_o32, | ||
253 | }; | ||
254 | |||
255 | |||
256 | asmlinkage void sys32_sigreturn(void) | ||
257 | { | ||
258 | struct sigframe32 __user *frame; | ||
259 | struct pt_regs *regs; | ||
260 | sigset_t blocked; | ||
261 | int sig; | ||
262 | |||
263 | regs = current_pt_regs(); | ||
264 | frame = (struct sigframe32 __user *)regs->regs[29]; | ||
265 | if (!access_ok(frame, sizeof(*frame))) | ||
266 | goto badframe; | ||
267 | if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) | ||
268 | goto badframe; | ||
269 | |||
270 | set_current_blocked(&blocked); | ||
271 | |||
272 | sig = restore_sigcontext32(regs, &frame->sf_sc); | ||
273 | if (sig < 0) | ||
274 | goto badframe; | ||
275 | else if (sig) | ||
276 | force_sig(sig); | ||
277 | |||
278 | /* | ||
279 | * Don't let your children do this ... | ||
280 | */ | ||
281 | __asm__ __volatile__( | ||
282 | "move\t$29, %0\n\t" | ||
283 | "j\tsyscall_exit" | ||
284 | : /* no outputs */ | ||
285 | : "r" (regs)); | ||
286 | /* Unreached */ | ||
287 | |||
288 | badframe: | ||
289 | force_sig(SIGSEGV); | ||
290 | } | ||