Hello All, this is an update of the earlier signal handling code improvements patch in order to handle the PLAT_TRAMPOLINE_STUFF_LINE stuff as well. In addition to the earlier fixes it extends the use of PLAT_TRAMPOLINE_STUFF_LINE to cover N32 ABI, and uses __clear_user instead of __builtin_memset. Thiemo Index: arch/mips/kernel/signal.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/signal.c,v retrieving revision 1.81 diff -u -p -r1.81 signal.c --- arch/mips/kernel/signal.c 29 Nov 2004 13:21:07 -0000 1.81 +++ arch/mips/kernel/signal.c 30 Nov 2004 05:39:51 -0000 @@ -29,12 +29,15 @@ #include <asm/sim.h> #include <asm/uaccess.h> #include <asm/ucontext.h> +#include <asm/cpu-features.h> + +#include "signal64.h" #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); +static int do_signal(sigset_t *oldset, struct pt_regs *regs); /* * Atomically swap in the new signal mask, and wait for a signal. @@ -152,51 +155,6 @@ asmlinkage int sys_sigaltstack(nabi_no_r return do_sigaltstack(uss, uoss, usp); } -asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) -{ - int err = 0; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - err |= __get_user(regs->cp0_epc, &sc->sc_pc); - err |= __get_user(regs->hi, &sc->sc_mdhi); - err |= __get_user(regs->lo, &sc->sc_mdlo); - -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - - err |= __get_user(current->used_math, &sc->sc_used_math); - - preempt_disable(); - - if (current->used_math) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); - } - - preempt_enable(); - - return err; -} - #if PLAT_TRAMPOLINE_STUFF_LINE #define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE))) #else @@ -220,7 +178,9 @@ struct rt_sigframe { }; #ifdef CONFIG_TRAD_SIGNALS -asmlinkage void sys_sigreturn(struct pt_regs regs) +save_static_function(sys_sigreturn); +__attribute_used__ noinline static void +_sys_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe *frame; sigset_t blocked; @@ -257,7 +217,9 @@ badframe: } #endif -asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sys_rt_sigreturn); +__attribute_used__ noinline static void +_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe *frame; sigset_t set; @@ -298,85 +260,6 @@ badframe: force_sig(SIGSEGV, current); } -inline int setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) -{ - int err = 0; - - err |= __put_user(regs->cp0_epc, &sc->sc_pc); - err |= __put_user(regs->cp0_status, &sc->sc_status); - -#define save_gp_reg(i) do { \ - err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg - - err |= __put_user(regs->hi, &sc->sc_mdhi); - err |= __put_user(regs->lo, &sc->sc_mdlo); - err |= __put_user(regs->cp0_cause, &sc->sc_cause); - err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); - - err |= __put_user(current->used_math, &sc->sc_used_math); - - if (!current->used_math) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context(sc); - - preempt_enable(); - -out: - return err; -} - -/* - * Determine which stack to use.. - */ -static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp, almask; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - if (PLAT_TRAMPOLINE_STUFF_LINE) - almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1); - else - almask = ALMASK; - - return (void *)((sp - frame_size) & almask); -} - #ifdef CONFIG_TRAD_SIGNALS static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) @@ -395,8 +278,7 @@ static void inline setup_frame(struct k_ * syscall */ if (PLAT_TRAMPOLINE_STUFF_LINE) - __builtin_memset(frame->sf_code, '0', - PLAT_TRAMPOLINE_STUFF_LINE); + __clear_user(frame->sf_code, PLAT_TRAMPOLINE_STUFF_LINE); err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0); err |= __put_user(0x0000000c , frame->sf_code + 1); flush_cache_sigtramp((unsigned long) frame->sf_code); @@ -452,8 +334,7 @@ static void inline setup_rt_frame(struct * syscall */ if (PLAT_TRAMPOLINE_STUFF_LINE) - __builtin_memset(frame->rs_code, '0', - PLAT_TRAMPOLINE_STUFF_LINE); + __clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE); err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0); err |= __put_user(0x0000000c , frame->rs_code + 1); flush_cache_sigtramp((unsigned long) frame->rs_code); @@ -557,7 +438,7 @@ static inline void handle_signal(unsigne extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs); -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +static int do_signal(sigset_t *oldset, struct pt_regs *regs) { struct k_sigaction ka; siginfo_t info; Index: arch/mips/kernel/signal32.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/signal32.c,v retrieving revision 1.18 diff -u -p -r1.18 signal32.c --- arch/mips/kernel/signal32.c 11 Nov 2004 14:09:09 -0000 1.18 +++ arch/mips/kernel/signal32.c 30 Nov 2004 05:39:51 -0000 @@ -106,7 +106,7 @@ typedef struct siginfo32 { #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs); +extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); /* 32-bit compatibility types */ @@ -192,6 +192,7 @@ static inline int get_sigset(sigset_t *k /* * Atomically swap in the new signal mask, and wait for a signal. */ + save_static_function(sys32_sigsuspend); __attribute_used__ noinline static int _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) @@ -333,8 +334,7 @@ asmlinkage int sys32_sigaltstack(nabi_no return ret; } -static asmlinkage int restore_sigcontext32(struct pt_regs *regs, - struct sigcontext32 *sc) +static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) { int err = 0; @@ -440,7 +440,9 @@ static int copy_siginfo_to_user32(siginf return err; } -asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sys32_sigreturn); +__attribute_used__ noinline static void +_sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe *frame; sigset_t blocked; @@ -476,7 +478,9 @@ badframe: force_sig(SIGSEGV, current); } -asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sys32_rt_sigreturn); +__attribute_used__ noinline static void +_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe32 *frame; sigset_t set; @@ -759,7 +763,7 @@ static inline void handle_signal(unsigne } } -asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs) +int do_signal32(sigset_t *oldset, struct pt_regs *regs) { struct k_sigaction ka; siginfo_t info; Index: arch/mips/kernel/signal_n32.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/signal_n32.c,v retrieving revision 1.8 diff -u -p -r1.8 signal_n32.c --- arch/mips/kernel/signal_n32.c 25 Oct 2004 20:44:17 -0000 1.8 +++ arch/mips/kernel/signal_n32.c 30 Nov 2004 05:39:51 -0000 @@ -35,6 +35,9 @@ #include <asm/ucontext.h> #include <asm/system.h> #include <asm/fpu.h> +#include <asm/cpu-features.h> + +#include "signal64.h" /* * Including <asm/unistd.h would give use the 64-bit syscall numbers ... @@ -59,17 +62,22 @@ struct ucontextn32 { sigset_t uc_sigmask; /* mask last for extensibility */ }; +#if PLAT_TRAMPOLINE_STUFF_LINE +#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE))) +#else +#define __tramp +#endif + struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ - u32 rs_code[2]; /* signal trampoline */ - struct siginfo rs_info; + u32 rs_code[2] __tramp; /* signal trampoline */ + struct siginfo rs_info __tramp; struct ucontextn32 rs_uc; }; -extern asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc); -extern int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc); - -asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +save_static_function(sysn32_rt_sigreturn); +__attribute_used__ noinline static void +_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe_n32 *frame; sigset_t set; @@ -118,31 +126,6 @@ badframe: force_sig(SIGSEGV, current); } -/* - * Determine which stack to use.. - */ -static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void *)((sp - frame_size) & ALMASK); -} - void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) { @@ -160,8 +143,10 @@ void setup_rt_frame_n32(struct k_sigacti * li v0, __NR_rt_sigreturn * syscall */ + if (PLAT_TRAMPOLINE_STUFF_LINE) + __clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE); err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0); - err |= __put_user(0x0000000c , frame->rs_code + 1); + err |= __put_user(0x0000000c , frame->rs_code + 1); flush_cache_sigtramp((unsigned long) frame->rs_code); /* Create siginfo. */ --- /dev/null 2004-08-24 19:23:08.000000000 +0200 +++ arch/mips/kernel/signal64.h 2004-11-30 06:29:37.000000000 +0100 @@ -0,0 +1,125 @@ +extern inline int +setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int err = 0; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + err |= __put_user(regs->cp0_status, &sc->sc_status); + +#define save_gp_reg(i) do { \ + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ +} while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); +#undef save_gp_reg + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + err |= __put_user(regs->cp0_cause, &sc->sc_cause); + err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + + err |= __put_user(current->used_math, &sc->sc_used_math); + + if (!current->used_math) + goto out; + + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + +out: + return err; +} + +extern inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int err = 0; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + +#define restore_gp_reg(i) do { \ + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ +} while(0) + restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); + restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); + restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); +#undef restore_gp_reg + + err |= __get_user(current->used_math, &sc->sc_used_math); + + preempt_disable(); + + if (current->used_math) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); + + return err; +} + +/* + * Determine which stack to use.. + */ +extern inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long sp, almask; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; + + if (PLAT_TRAMPOLINE_STUFF_LINE) + almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1); + else + almask = ALMASK; + + return (void *)((sp - frame_size) & almask); +}