Loading...
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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2003 Broadcom Corporation */ #include <linux/cache.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> #include <linux/wait.h> #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/compat.h> #include <linux/bitops.h> #include <asm/abi.h> #include <asm/asm.h> #include <asm/cacheflush.h> #include <asm/compat-signal.h> #include <asm/sim.h> #include <linux/uaccess.h> #include <asm/ucontext.h> #include <asm/fpu.h> #include <asm/cpu-features.h> #include "signal-common.h" /* * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... */ #define __NR_N32_restart_syscall 6214 extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); struct ucontextn32 { u32 uc_flags; s32 uc_link; compat_stack_t uc_stack; struct sigcontext uc_mcontext; compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ u32 rs_pad[2]; /* Was: signal trampoline */ struct compat_siginfo rs_info; struct ucontextn32 rs_uc; }; asmlinkage void sysn32_rt_sigreturn(void) { struct rt_sigframe_n32 __user *frame; struct pt_regs *regs; sigset_t set; int sig; regs = current_pt_regs(); frame = (struct rt_sigframe_n32 __user *)regs->regs[29]; if (!access_ok(frame, sizeof(*frame))) goto badframe; if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; set_current_blocked(&set); sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); if (sig < 0) goto badframe; else if (sig) force_sig(sig); if (compat_restore_altstack(&frame->rs_uc.uc_stack)) goto badframe; /* * Don't let your children do this ... */ __asm__ __volatile__( "move\t$29, %0\n\t" "j\tsyscall_exit" : /* no outputs */ : "r" (regs)); /* Unreached */ badframe: force_sig(SIGSEGV); } static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig, struct pt_regs *regs, sigset_t *set) { struct rt_sigframe_n32 __user *frame; int err = 0; frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(frame, sizeof (*frame))) return -EFAULT; /* Create siginfo. */ err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) return -EFAULT; /* * Arguments to signal handler: * * a0 = signal number * a1 = 0 (should be cause) * a2 = pointer to ucontext * * $25 and c0_epc point to the signal handler, $29 points to * the struct rt_sigframe. */ regs->regs[ 4] = ksig->sig; regs->regs[ 5] = (unsigned long) &frame->rs_info; regs->regs[ 6] = (unsigned long) &frame->rs_uc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) sig_return; regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); return 0; } struct mips_abi mips_abi_n32 = { .setup_rt_frame = setup_rt_frame_n32, .restart = __NR_N32_restart_syscall, .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), .vdso = &vdso_image_n32, }; |