Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Hexagon: Add signal functions

Signed-off-by: Richard Kuo <rkuo@codeaurora.org>
Signed-off-by: Linas Vepstas <linas@codeaurora.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Richard Kuo and committed by
Linus Torvalds
cd5b61d6 98fb1036

+569
+33
arch/hexagon/include/asm/sigcontext.h
··· 1 + /* 2 + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program; if not, write to the Free Software 15 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 16 + * 02110-1301, USA. 17 + */ 18 + 19 + #ifndef _ASM_SIGCONTEXT_H 20 + #define _ASM_SIGCONTEXT_H 21 + 22 + #include <asm/user.h> 23 + 24 + /* 25 + * Signal context structure - contains all info to do with the state 26 + * before the signal handler was invoked. Note: only add new entries 27 + * to the end of the structure. 28 + */ 29 + struct sigcontext { 30 + struct user_regs_struct sc_regs; 31 + } __aligned(8); 32 + 33 + #endif
+26
arch/hexagon/include/asm/signal.h
··· 1 + /* 2 + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program; if not, write to the Free Software 15 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 16 + * 02110-1301, USA. 17 + */ 18 + 19 + #ifndef _ASM_SIGNAL_H 20 + #define _ASM_SIGNAL_H 21 + 22 + extern unsigned long __rt_sigtramp_template[2]; 23 + 24 + #include <asm-generic/signal.h> 25 + 26 + #endif
+30
arch/hexagon/include/asm/vdso.h
··· 1 + /* 2 + * vDSO implementation for Hexagon 3 + * 4 + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 and 8 + * only version 2 as published by the Free Software Foundation. 9 + * 10 + * This program 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 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 + * 02110-1301, USA. 19 + */ 20 + 21 + #ifndef __ASM_VDSO_H 22 + #define __ASM_VDSO_H 23 + 24 + #include <linux/types.h> 25 + 26 + struct hexagon_vdso { 27 + u32 rt_signal_trampoline[2]; 28 + }; 29 + 30 + #endif /* __ASM_VDSO_H */
+345
arch/hexagon/kernel/signal.c
··· 1 + /* 2 + * Signal support for Hexagon processor 3 + * 4 + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 and 8 + * only version 2 as published by the Free Software Foundation. 9 + * 10 + * This program 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 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 + * 02110-1301, USA. 19 + */ 20 + 21 + #include <linux/linkage.h> 22 + #include <linux/syscalls.h> 23 + #include <linux/freezer.h> 24 + #include <linux/tracehook.h> 25 + #include <asm/registers.h> 26 + #include <asm/thread_info.h> 27 + #include <asm/unistd.h> 28 + #include <asm/uaccess.h> 29 + #include <asm/ucontext.h> 30 + #include <asm/cacheflush.h> 31 + #include <asm/signal.h> 32 + #include <asm/vdso.h> 33 + 34 + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 35 + 36 + struct rt_sigframe { 37 + unsigned long tramp[2]; 38 + struct siginfo info; 39 + struct ucontext uc; 40 + }; 41 + 42 + static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 43 + size_t frame_size) 44 + { 45 + unsigned long sp = regs->r29; 46 + 47 + /* Switch to signal stack if appropriate */ 48 + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) 49 + sp = current->sas_ss_sp + current->sas_ss_size; 50 + 51 + return (void __user *)((sp - frame_size) & ~(sizeof(long long) - 1)); 52 + } 53 + 54 + static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) 55 + { 56 + unsigned long tmp; 57 + int err = 0; 58 + 59 + err |= copy_to_user(&sc->sc_regs.r0, &regs->r00, 60 + 32*sizeof(unsigned long)); 61 + 62 + err |= __put_user(regs->sa0, &sc->sc_regs.sa0); 63 + err |= __put_user(regs->lc0, &sc->sc_regs.lc0); 64 + err |= __put_user(regs->sa1, &sc->sc_regs.sa1); 65 + err |= __put_user(regs->lc1, &sc->sc_regs.lc1); 66 + err |= __put_user(regs->m0, &sc->sc_regs.m0); 67 + err |= __put_user(regs->m1, &sc->sc_regs.m1); 68 + err |= __put_user(regs->usr, &sc->sc_regs.usr); 69 + err |= __put_user(regs->preds, &sc->sc_regs.p3_0); 70 + err |= __put_user(regs->gp, &sc->sc_regs.gp); 71 + err |= __put_user(regs->ugp, &sc->sc_regs.ugp); 72 + 73 + tmp = pt_elr(regs); err |= __put_user(tmp, &sc->sc_regs.pc); 74 + tmp = pt_cause(regs); err |= __put_user(tmp, &sc->sc_regs.cause); 75 + tmp = pt_badva(regs); err |= __put_user(tmp, &sc->sc_regs.badva); 76 + 77 + return err; 78 + } 79 + 80 + static int restore_sigcontext(struct pt_regs *regs, 81 + struct sigcontext __user *sc) 82 + { 83 + unsigned long tmp; 84 + int err = 0; 85 + 86 + err |= copy_from_user(&regs->r00, &sc->sc_regs.r0, 87 + 32 * sizeof(unsigned long)); 88 + 89 + err |= __get_user(regs->sa0, &sc->sc_regs.sa0); 90 + err |= __get_user(regs->lc0, &sc->sc_regs.lc0); 91 + err |= __get_user(regs->sa1, &sc->sc_regs.sa1); 92 + err |= __get_user(regs->lc1, &sc->sc_regs.lc1); 93 + err |= __get_user(regs->m0, &sc->sc_regs.m0); 94 + err |= __get_user(regs->m1, &sc->sc_regs.m1); 95 + err |= __get_user(regs->usr, &sc->sc_regs.usr); 96 + err |= __get_user(regs->preds, &sc->sc_regs.p3_0); 97 + err |= __get_user(regs->gp, &sc->sc_regs.gp); 98 + err |= __get_user(regs->ugp, &sc->sc_regs.ugp); 99 + 100 + err |= __get_user(tmp, &sc->sc_regs.pc); pt_set_elr(regs, tmp); 101 + 102 + return err; 103 + } 104 + 105 + /* 106 + * Setup signal stack frame with siginfo structure 107 + */ 108 + static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, 109 + sigset_t *set, struct pt_regs *regs) 110 + { 111 + int err = 0; 112 + struct rt_sigframe __user *frame; 113 + struct hexagon_vdso *vdso = current->mm->context.vdso; 114 + 115 + frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe)); 116 + 117 + if (!access_ok(VERIFY_WRITE, frame, sizeof(struct rt_sigframe))) 118 + goto sigsegv; 119 + 120 + if (copy_siginfo_to_user(&frame->info, info)) 121 + goto sigsegv; 122 + 123 + /* The on-stack signal trampoline is no longer executed; 124 + * however, the libgcc signal frame unwinding code checks for 125 + * the presence of these two numeric magic values. 126 + */ 127 + err |= __put_user(0x7800d166, &frame->tramp[0]); 128 + err |= __put_user(0x5400c004, &frame->tramp[1]); 129 + err |= setup_sigcontext(regs, &frame->uc.uc_mcontext); 130 + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 131 + if (err) 132 + goto sigsegv; 133 + 134 + /* Load r0/r1 pair with signumber/siginfo pointer... */ 135 + regs->r0100 = ((unsigned long long)((unsigned long)&frame->info) << 32) 136 + | (unsigned long long)signr; 137 + regs->r02 = (unsigned long) &frame->uc; 138 + regs->r31 = (unsigned long) vdso->rt_signal_trampoline; 139 + pt_psp(regs) = (unsigned long) frame; 140 + pt_set_elr(regs, (unsigned long)ka->sa.sa_handler); 141 + 142 + return 0; 143 + 144 + sigsegv: 145 + force_sigsegv(signr, current); 146 + return -EFAULT; 147 + } 148 + 149 + /* 150 + * Setup invocation of signal handler 151 + */ 152 + static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, 153 + sigset_t *oldset, struct pt_regs *regs) 154 + { 155 + int rc; 156 + 157 + /* 158 + * If we're handling a signal that aborted a system call, 159 + * set up the error return value before adding the signal 160 + * frame to the stack. 161 + */ 162 + 163 + if (regs->syscall_nr >= 0) { 164 + switch (regs->r00) { 165 + case -ERESTART_RESTARTBLOCK: 166 + case -ERESTARTNOHAND: 167 + regs->r00 = -EINTR; 168 + break; 169 + case -ERESTARTSYS: 170 + if (!(ka->sa.sa_flags & SA_RESTART)) { 171 + regs->r00 = -EINTR; 172 + break; 173 + } 174 + /* Fall through */ 175 + case -ERESTARTNOINTR: 176 + regs->r06 = regs->syscall_nr; 177 + pt_set_elr(regs, pt_elr(regs) - 4); 178 + regs->r00 = regs->restart_r0; 179 + break; 180 + default: 181 + break; 182 + } 183 + } 184 + 185 + /* 186 + * Set up the stack frame; not doing the SA_SIGINFO thing. We 187 + * only set up the rt_frame flavor. 188 + */ 189 + rc = setup_rt_frame(sig, ka, info, oldset, regs); 190 + 191 + /* If there was an error on setup, no signal was delivered. */ 192 + if (rc) 193 + return rc; 194 + 195 + spin_lock_irq(&current->sighand->siglock); 196 + sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask); 197 + if (!(ka->sa.sa_flags & SA_NODEFER)) 198 + sigaddset(&current->blocked, sig); 199 + recalc_sigpending(); 200 + spin_unlock_irq(&current->sighand->siglock); 201 + 202 + return 0; 203 + } 204 + 205 + /* 206 + * Called from return-from-event code. 207 + */ 208 + static void do_signal(struct pt_regs *regs) 209 + { 210 + struct k_sigaction sigact; 211 + siginfo_t info; 212 + int signo; 213 + 214 + if (!user_mode(regs)) 215 + return; 216 + 217 + if (try_to_freeze()) 218 + goto no_signal; 219 + 220 + signo = get_signal_to_deliver(&info, &sigact, regs, NULL); 221 + 222 + if (signo > 0) { 223 + sigset_t *oldset; 224 + 225 + if (test_thread_flag(TIF_RESTORE_SIGMASK)) 226 + oldset = &current->saved_sigmask; 227 + else 228 + oldset = &current->blocked; 229 + 230 + if (handle_signal(signo, &info, &sigact, oldset, regs) == 0) { 231 + /* 232 + * Successful delivery case. The saved sigmask is 233 + * stored in the signal frame, and will be restored 234 + * by sigreturn. We can clear the TIF flag. 235 + */ 236 + clear_thread_flag(TIF_RESTORE_SIGMASK); 237 + 238 + tracehook_signal_handler(signo, &info, &sigact, regs, 239 + test_thread_flag(TIF_SINGLESTEP)); 240 + } 241 + return; 242 + } 243 + 244 + no_signal: 245 + /* 246 + * If we came from a system call, handle the restart. 247 + */ 248 + if (regs->syscall_nr >= 0) { 249 + switch (regs->r00) { 250 + case -ERESTARTNOHAND: 251 + case -ERESTARTSYS: 252 + case -ERESTARTNOINTR: 253 + regs->r06 = regs->syscall_nr; 254 + break; 255 + case -ERESTART_RESTARTBLOCK: 256 + regs->r06 = __NR_restart_syscall; 257 + break; 258 + default: 259 + goto no_restart; 260 + } 261 + pt_set_elr(regs, pt_elr(regs) - 4); 262 + regs->r00 = regs->restart_r0; 263 + } 264 + 265 + no_restart: 266 + /* If there's no signal to deliver, put the saved sigmask back */ 267 + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 268 + clear_thread_flag(TIF_RESTORE_SIGMASK); 269 + sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL); 270 + } 271 + } 272 + 273 + void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) 274 + { 275 + if (thread_info_flags & _TIF_SIGPENDING) 276 + do_signal(regs); 277 + 278 + if (thread_info_flags & _TIF_NOTIFY_RESUME) { 279 + clear_thread_flag(TIF_NOTIFY_RESUME); 280 + if (current->replacement_session_keyring) 281 + key_replace_session_keyring(); 282 + } 283 + } 284 + 285 + /* 286 + * Architecture-specific wrappers for signal-related system calls 287 + */ 288 + asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) 289 + { 290 + struct pt_regs *regs = current_thread_info()->regs; 291 + 292 + return do_sigaltstack(uss, uoss, regs->r29); 293 + } 294 + 295 + asmlinkage int sys_rt_sigreturn(void) 296 + { 297 + struct pt_regs *regs = current_thread_info()->regs; 298 + struct rt_sigframe __user *frame; 299 + sigset_t blocked; 300 + 301 + frame = (struct rt_sigframe __user *)pt_psp(regs); 302 + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 303 + goto badframe; 304 + if (__copy_from_user(&blocked, &frame->uc.uc_sigmask, sizeof(blocked))) 305 + goto badframe; 306 + 307 + sigdelsetmask(&blocked, ~_BLOCKABLE); 308 + spin_lock_irq(&current->sighand->siglock); 309 + current->blocked = blocked; 310 + recalc_sigpending(); 311 + spin_unlock_irq(&current->sighand->siglock); 312 + 313 + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) 314 + goto badframe; 315 + 316 + /* Restore the user's stack as well */ 317 + pt_psp(regs) = regs->r29; 318 + 319 + /* 320 + * Leave a trace in the stack frame that this was a sigreturn. 321 + * If the system call is to replay, we've already restored the 322 + * number in the GPR slot and it will be regenerated on the 323 + * new system call trap entry. Note that if restore_sigcontext() 324 + * did something other than a bulk copy of the pt_regs struct, 325 + * we could avoid this assignment by simply not overwriting 326 + * regs->syscall_nr. 327 + */ 328 + regs->syscall_nr = __NR_rt_sigreturn; 329 + 330 + /* 331 + * If we were meticulous, we'd only call this if we knew that 332 + * we were actually going to use an alternate stack, and we'd 333 + * consider any error to be fatal. What we do here, in common 334 + * with many other architectures, is call it blindly and only 335 + * consider the -EFAULT return case to be proof of a problem. 336 + */ 337 + if (do_sigaltstack(&frame->uc.uc_stack, NULL, pt_psp(regs)) == -EFAULT) 338 + goto badframe; 339 + 340 + return 0; 341 + 342 + badframe: 343 + force_sig(SIGSEGV, current); 344 + return 0; 345 + }
+35
arch/hexagon/kernel/trampoline.S
··· 1 + /* 2 + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program; if not, write to the Free Software 15 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 16 + * 02110-1301, USA. 17 + */ 18 + 19 + /* 20 + * Trampoline sequences to be copied onto user stack. 21 + * This consumes a little more space than hand-assembling 22 + * immediate constants for use in C, but is more portable 23 + * to future tweaks to the Hexagon instruction set. 24 + */ 25 + 26 + #include <asm/unistd.h> 27 + 28 + /* Sig trampolines - call sys_sigreturn or sys_rt_sigreturn as appropriate */ 29 + 30 + /* plain sigreturn is gone. */ 31 + 32 + .globl __rt_sigtramp_template 33 + __rt_sigtramp_template: 34 + r6 = #__NR_rt_sigreturn; 35 + trap0(#1);
+100
arch/hexagon/kernel/vdso.c
··· 1 + /* 2 + * vDSO implementation for Hexagon 3 + * 4 + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 and 8 + * only version 2 as published by the Free Software Foundation. 9 + * 10 + * This program 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 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 + * 02110-1301, USA. 19 + */ 20 + 21 + #include <linux/err.h> 22 + #include <linux/mm.h> 23 + #include <linux/vmalloc.h> 24 + 25 + #include <asm/vdso.h> 26 + 27 + static struct page *vdso_page; 28 + 29 + /* Create a vDSO page holding the signal trampoline. 30 + * We want this for a non-executable stack. 31 + */ 32 + static int __init vdso_init(void) 33 + { 34 + struct hexagon_vdso *vdso; 35 + 36 + vdso_page = alloc_page(GFP_KERNEL); 37 + if (!vdso_page) 38 + panic("Cannot allocate vdso"); 39 + 40 + vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); 41 + if (!vdso) 42 + panic("Cannot map vdso"); 43 + clear_page(vdso); 44 + 45 + /* Install the signal trampoline; currently looks like this: 46 + * r6 = #__NR_rt_sigreturn; 47 + * trap0(#1); 48 + */ 49 + vdso->rt_signal_trampoline[0] = __rt_sigtramp_template[0]; 50 + vdso->rt_signal_trampoline[1] = __rt_sigtramp_template[1]; 51 + 52 + vunmap(vdso); 53 + 54 + return 0; 55 + } 56 + arch_initcall(vdso_init); 57 + 58 + /* 59 + * Called from binfmt_elf. Create a VMA for the vDSO page. 60 + */ 61 + int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 62 + { 63 + int ret; 64 + unsigned long vdso_base; 65 + struct mm_struct *mm = current->mm; 66 + 67 + down_write(&mm->mmap_sem); 68 + 69 + /* Try to get it loaded right near ld.so/glibc. */ 70 + vdso_base = STACK_TOP; 71 + 72 + vdso_base = get_unmapped_area(NULL, vdso_base, PAGE_SIZE, 0, 0); 73 + if (IS_ERR_VALUE(vdso_base)) { 74 + ret = vdso_base; 75 + goto up_fail; 76 + } 77 + 78 + /* MAYWRITE to allow gdb to COW and set breakpoints. */ 79 + ret = install_special_mapping(mm, vdso_base, PAGE_SIZE, 80 + VM_READ|VM_EXEC| 81 + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| 82 + VM_ALWAYSDUMP, 83 + &vdso_page); 84 + 85 + if (ret) 86 + goto up_fail; 87 + 88 + mm->context.vdso = (void *)vdso_base; 89 + 90 + up_fail: 91 + up_write(&mm->mmap_sem); 92 + return ret; 93 + } 94 + 95 + const char *arch_vma_name(struct vm_area_struct *vma) 96 + { 97 + if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) 98 + return "[vdso]"; 99 + return NULL; 100 + }