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

MIPS: Move signal trampolines off of the stack.

This is a follow on to the vdso patch.

Since all processes now have signal trampolines permanently mapped, we
can use those instead of putting the trampoline on the stack and
invalidating the corresponding icache across all CPUs. We also get rid
of a bunch of ICACHE_REFILLS_WORKAROUND_WAR code.

[Ralf: GDB 7.1 which has the necessary modifications to allow backtracing
over signal frames will supposedly be released tomorrow. The old signal
frame format obsoleted by this patch exists in two variations, for sane
processors and for those requiring ICACHE_REFILLS_WORKAROUND_WAR. So
there was never a GDB which did support backtracing over signal frames
on all MIPS systems. This convinved me this series should be applied and
pushed upstream as soon as possible.]

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/974/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

David Daney and committed by
Ralf Baechle
d814c28c c52d0d30

+43 -135
+4 -2
arch/mips/include/asm/abi.h
··· 13 13 #include <asm/siginfo.h> 14 14 15 15 struct mips_abi { 16 - int (* const setup_frame)(struct k_sigaction * ka, 16 + int (* const setup_frame)(void *sig_return, struct k_sigaction *ka, 17 17 struct pt_regs *regs, int signr, 18 18 sigset_t *set); 19 - int (* const setup_rt_frame)(struct k_sigaction * ka, 19 + const unsigned long signal_return_offset; 20 + int (* const setup_rt_frame)(void *sig_return, struct k_sigaction *ka, 20 21 struct pt_regs *regs, int signr, 21 22 sigset_t *set, siginfo_t *info); 23 + const unsigned long rt_signal_return_offset; 22 24 const unsigned long restart; 23 25 }; 24 26
-5
arch/mips/kernel/signal-common.h
··· 26 26 */ 27 27 extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 28 28 size_t frame_size); 29 - /* 30 - * install trampoline code to get back from the sig handler 31 - */ 32 - extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); 33 - 34 29 /* Check and clear pending FPU exceptions in saved CSR */ 35 30 extern int fpcsr_pending(unsigned int __user *fpcsr); 36 31
+19 -67
arch/mips/kernel/signal.c
··· 32 32 #include <asm/ucontext.h> 33 33 #include <asm/cpu-features.h> 34 34 #include <asm/war.h> 35 + #include <asm/vdso.h> 35 36 36 37 #include "signal-common.h" 37 38 ··· 45 44 extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); 46 45 extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); 47 46 48 - /* 49 - * Horribly complicated - with the bloody RM9000 workarounds enabled 50 - * the signal trampolines is moving to the end of the structure so we can 51 - * increase the alignment without breaking software compatibility. 52 - */ 53 - #if ICACHE_REFILLS_WORKAROUND_WAR == 0 54 - 55 47 struct sigframe { 56 48 u32 sf_ass[4]; /* argument save space for o32 */ 57 - u32 sf_code[2]; /* signal trampoline */ 49 + u32 sf_pad[2]; /* Was: signal trampoline */ 58 50 struct sigcontext sf_sc; 59 51 sigset_t sf_mask; 60 52 }; 61 53 62 54 struct rt_sigframe { 63 55 u32 rs_ass[4]; /* argument save space for o32 */ 64 - u32 rs_code[2]; /* signal trampoline */ 56 + u32 rs_pad[2]; /* Was: signal trampoline */ 65 57 struct siginfo rs_info; 66 58 struct ucontext rs_uc; 67 59 }; 68 - 69 - #else 70 - 71 - struct sigframe { 72 - u32 sf_ass[4]; /* argument save space for o32 */ 73 - u32 sf_pad[2]; 74 - struct sigcontext sf_sc; /* hw context */ 75 - sigset_t sf_mask; 76 - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ 77 - }; 78 - 79 - struct rt_sigframe { 80 - u32 rs_ass[4]; /* argument save space for o32 */ 81 - u32 rs_pad[2]; 82 - struct siginfo rs_info; 83 - struct ucontext rs_uc; 84 - u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ 85 - }; 86 - 87 - #endif 88 60 89 61 /* 90 62 * Helper routines ··· 238 264 sp = current->sas_ss_sp + current->sas_ss_size; 239 265 240 266 return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); 241 - } 242 - 243 - int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) 244 - { 245 - int err; 246 - 247 - /* 248 - * Set up the return code ... 249 - * 250 - * li v0, __NR__foo_sigreturn 251 - * syscall 252 - */ 253 - 254 - err = __put_user(0x24020000 + syscall, tramp + 0); 255 - err |= __put_user(0x0000000c , tramp + 1); 256 - if (ICACHE_REFILLS_WORKAROUND_WAR) { 257 - err |= __put_user(0, tramp + 2); 258 - err |= __put_user(0, tramp + 3); 259 - err |= __put_user(0, tramp + 4); 260 - err |= __put_user(0, tramp + 5); 261 - err |= __put_user(0, tramp + 6); 262 - err |= __put_user(0, tramp + 7); 263 - } 264 - flush_cache_sigtramp((unsigned long) tramp); 265 - 266 - return err; 267 267 } 268 268 269 269 /* ··· 432 484 } 433 485 434 486 #ifdef CONFIG_TRAD_SIGNALS 435 - static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, 436 - int signr, sigset_t *set) 487 + static int setup_frame(void *sig_return, struct k_sigaction *ka, 488 + struct pt_regs *regs, int signr, sigset_t *set) 437 489 { 438 490 struct sigframe __user *frame; 439 491 int err = 0; ··· 441 493 frame = get_sigframe(ka, regs, sizeof(*frame)); 442 494 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 443 495 goto give_sigsegv; 444 - 445 - err |= install_sigtramp(frame->sf_code, __NR_sigreturn); 446 496 447 497 err |= setup_sigcontext(regs, &frame->sf_sc); 448 498 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); ··· 461 515 regs->regs[ 5] = 0; 462 516 regs->regs[ 6] = (unsigned long) &frame->sf_sc; 463 517 regs->regs[29] = (unsigned long) frame; 464 - regs->regs[31] = (unsigned long) frame->sf_code; 518 + regs->regs[31] = (unsigned long) sig_return; 465 519 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 466 520 467 521 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", ··· 475 529 } 476 530 #endif 477 531 478 - static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, 479 - int signr, sigset_t *set, siginfo_t *info) 532 + static int setup_rt_frame(void *sig_return, struct k_sigaction *ka, 533 + struct pt_regs *regs, int signr, sigset_t *set, 534 + siginfo_t *info) 480 535 { 481 536 struct rt_sigframe __user *frame; 482 537 int err = 0; ··· 485 538 frame = get_sigframe(ka, regs, sizeof(*frame)); 486 539 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 487 540 goto give_sigsegv; 488 - 489 - err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); 490 541 491 542 /* Create siginfo. */ 492 543 err |= copy_siginfo_to_user(&frame->rs_info, info); ··· 518 573 regs->regs[ 5] = (unsigned long) &frame->rs_info; 519 574 regs->regs[ 6] = (unsigned long) &frame->rs_uc; 520 575 regs->regs[29] = (unsigned long) frame; 521 - regs->regs[31] = (unsigned long) frame->rs_code; 576 + regs->regs[31] = (unsigned long) sig_return; 522 577 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 523 578 524 579 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", ··· 535 590 struct mips_abi mips_abi = { 536 591 #ifdef CONFIG_TRAD_SIGNALS 537 592 .setup_frame = setup_frame, 593 + .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline), 538 594 #endif 539 595 .setup_rt_frame = setup_rt_frame, 596 + .rt_signal_return_offset = 597 + offsetof(struct mips_vdso, rt_signal_trampoline), 540 598 .restart = __NR_restart_syscall 541 599 }; 542 600 ··· 547 599 struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) 548 600 { 549 601 int ret; 602 + struct mips_abi *abi = current->thread.abi; 603 + void *vdso = current->mm->context.vdso; 550 604 551 605 switch(regs->regs[0]) { 552 606 case ERESTART_RESTARTBLOCK: ··· 569 619 regs->regs[0] = 0; /* Don't deal with this again. */ 570 620 571 621 if (sig_uses_siginfo(ka)) 572 - ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); 622 + ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, 623 + ka, regs, sig, oldset, info); 573 624 else 574 - ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); 625 + ret = abi->setup_frame(vdso + abi->signal_return_offset, 626 + ka, regs, sig, oldset); 575 627 576 628 spin_lock_irq(&current->sighand->siglock); 577 629 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+14 -41
arch/mips/kernel/signal32.c
··· 32 32 #include <asm/system.h> 33 33 #include <asm/fpu.h> 34 34 #include <asm/war.h> 35 + #include <asm/vdso.h> 35 36 36 37 #include "signal-common.h" 37 38 ··· 48 47 /* 49 48 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 50 49 */ 51 - #define __NR_O32_sigreturn 4119 52 - #define __NR_O32_rt_sigreturn 4193 53 50 #define __NR_O32_restart_syscall 4253 54 51 55 52 /* 32-bit compatibility types */ ··· 76 77 compat_sigset_t uc_sigmask; /* mask last for extensibility */ 77 78 }; 78 79 79 - /* 80 - * Horribly complicated - with the bloody RM9000 workarounds enabled 81 - * the signal trampolines is moving to the end of the structure so we can 82 - * increase the alignment without breaking software compatibility. 83 - */ 84 - #if ICACHE_REFILLS_WORKAROUND_WAR == 0 85 - 86 80 struct sigframe32 { 87 81 u32 sf_ass[4]; /* argument save space for o32 */ 88 - u32 sf_code[2]; /* signal trampoline */ 82 + u32 sf_pad[2]; /* Was: signal trampoline */ 89 83 struct sigcontext32 sf_sc; 90 84 compat_sigset_t sf_mask; 91 85 }; 92 86 93 87 struct rt_sigframe32 { 94 88 u32 rs_ass[4]; /* argument save space for o32 */ 95 - u32 rs_code[2]; /* signal trampoline */ 89 + u32 rs_pad[2]; /* Was: signal trampoline */ 96 90 compat_siginfo_t rs_info; 97 91 struct ucontext32 rs_uc; 98 92 }; 99 - 100 - #else /* ICACHE_REFILLS_WORKAROUND_WAR */ 101 - 102 - struct sigframe32 { 103 - u32 sf_ass[4]; /* argument save space for o32 */ 104 - u32 sf_pad[2]; 105 - struct sigcontext32 sf_sc; /* hw context */ 106 - compat_sigset_t sf_mask; 107 - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ 108 - }; 109 - 110 - struct rt_sigframe32 { 111 - u32 rs_ass[4]; /* argument save space for o32 */ 112 - u32 rs_pad[2]; 113 - compat_siginfo_t rs_info; 114 - struct ucontext32 rs_uc; 115 - u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ 116 - }; 117 - 118 - #endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ 119 93 120 94 /* 121 95 * sigcontext handlers ··· 570 598 force_sig(SIGSEGV, current); 571 599 } 572 600 573 - static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 574 - int signr, sigset_t *set) 601 + static int setup_frame_32(void *sig_return, struct k_sigaction *ka, 602 + struct pt_regs *regs, int signr, sigset_t *set) 575 603 { 576 604 struct sigframe32 __user *frame; 577 605 int err = 0; ··· 579 607 frame = get_sigframe(ka, regs, sizeof(*frame)); 580 608 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 581 609 goto give_sigsegv; 582 - 583 - err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn); 584 610 585 611 err |= setup_sigcontext32(regs, &frame->sf_sc); 586 612 err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); ··· 600 630 regs->regs[ 5] = 0; 601 631 regs->regs[ 6] = (unsigned long) &frame->sf_sc; 602 632 regs->regs[29] = (unsigned long) frame; 603 - regs->regs[31] = (unsigned long) frame->sf_code; 633 + regs->regs[31] = (unsigned long) sig_return; 604 634 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 605 635 606 636 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", ··· 614 644 return -EFAULT; 615 645 } 616 646 617 - static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 618 - int signr, sigset_t *set, siginfo_t *info) 647 + static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, 648 + struct pt_regs *regs, int signr, sigset_t *set, 649 + siginfo_t *info) 619 650 { 620 651 struct rt_sigframe32 __user *frame; 621 652 int err = 0; ··· 625 654 frame = get_sigframe(ka, regs, sizeof(*frame)); 626 655 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 627 656 goto give_sigsegv; 628 - 629 - err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn); 630 657 631 658 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ 632 659 err |= copy_siginfo_to_user32(&frame->rs_info, info); ··· 659 690 regs->regs[ 5] = (unsigned long) &frame->rs_info; 660 691 regs->regs[ 6] = (unsigned long) &frame->rs_uc; 661 692 regs->regs[29] = (unsigned long) frame; 662 - regs->regs[31] = (unsigned long) frame->rs_code; 693 + regs->regs[31] = (unsigned long) sig_return; 663 694 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 664 695 665 696 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", ··· 678 709 */ 679 710 struct mips_abi mips_abi_32 = { 680 711 .setup_frame = setup_frame_32, 712 + .signal_return_offset = 713 + offsetof(struct mips_vdso, o32_signal_trampoline), 681 714 .setup_rt_frame = setup_rt_frame_32, 715 + .rt_signal_return_offset = 716 + offsetof(struct mips_vdso, o32_rt_signal_trampoline), 682 717 .restart = __NR_O32_restart_syscall 683 718 }; 684 719
+6 -20
arch/mips/kernel/signal_n32.c
··· 39 39 #include <asm/fpu.h> 40 40 #include <asm/cpu-features.h> 41 41 #include <asm/war.h> 42 + #include <asm/vdso.h> 42 43 43 44 #include "signal-common.h" 44 45 45 46 /* 46 47 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... 47 48 */ 48 - #define __NR_N32_rt_sigreturn 6211 49 49 #define __NR_N32_restart_syscall 6214 50 50 51 51 extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); ··· 67 67 compat_sigset_t uc_sigmask; /* mask last for extensibility */ 68 68 }; 69 69 70 - #if ICACHE_REFILLS_WORKAROUND_WAR == 0 71 - 72 70 struct rt_sigframe_n32 { 73 71 u32 rs_ass[4]; /* argument save space for o32 */ 74 - u32 rs_code[2]; /* signal trampoline */ 72 + u32 rs_pad[2]; /* Was: signal trampoline */ 75 73 struct compat_siginfo rs_info; 76 74 struct ucontextn32 rs_uc; 77 75 }; 78 - 79 - #else /* ICACHE_REFILLS_WORKAROUND_WAR */ 80 - 81 - struct rt_sigframe_n32 { 82 - u32 rs_ass[4]; /* argument save space for o32 */ 83 - u32 rs_pad[2]; 84 - struct compat_siginfo rs_info; 85 - struct ucontextn32 rs_uc; 86 - u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ 87 - }; 88 - 89 - #endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ 90 76 91 77 extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); 92 78 ··· 159 173 force_sig(SIGSEGV, current); 160 174 } 161 175 162 - static int setup_rt_frame_n32(struct k_sigaction * ka, 176 + static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka, 163 177 struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) 164 178 { 165 179 struct rt_sigframe_n32 __user *frame; ··· 169 183 frame = get_sigframe(ka, regs, sizeof(*frame)); 170 184 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 171 185 goto give_sigsegv; 172 - 173 - install_sigtramp(frame->rs_code, __NR_N32_rt_sigreturn); 174 186 175 187 /* Create siginfo. */ 176 188 err |= copy_siginfo_to_user32(&frame->rs_info, info); ··· 203 219 regs->regs[ 5] = (unsigned long) &frame->rs_info; 204 220 regs->regs[ 6] = (unsigned long) &frame->rs_uc; 205 221 regs->regs[29] = (unsigned long) frame; 206 - regs->regs[31] = (unsigned long) frame->rs_code; 222 + regs->regs[31] = (unsigned long) sig_return; 207 223 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 208 224 209 225 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", ··· 219 235 220 236 struct mips_abi mips_abi_n32 = { 221 237 .setup_rt_frame = setup_rt_frame_n32, 238 + .rt_signal_return_offset = 239 + offsetof(struct mips_vdso, n32_rt_signal_trampoline), 222 240 .restart = __NR_N32_restart_syscall 223 241 };