Kaz Kojima
kkoji****@rr*****
2004年 11月 6日 (土) 21:47:20 JST
小島です。 LANDISK kernel の arch/sh/kernel/signal.c のパッチです。 -- --- ../HDLSRC42/kernel/latest/linux-2.4.21-iodata/arch/sh/kernel/signal.c 2003-10-24 22:24:13.000000000 +0900 +++ arch/sh/kernel/signal.c 2004-11-05 23:19:50.000000000 +0900 @@ -167,20 +167,22 @@ sys_sigaltstack(const stack_t *uss, stac * Do a signal return; undo the signal stack. */ +#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ +#define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ +#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ + struct sigframe { struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; - char retcode[4]; + u16 retcode[8]; }; struct rt_sigframe { - struct siginfo *pinfo; - void *puc; struct siginfo info; struct ucontext uc; - char retcode[4]; + u16 retcode[8]; }; #if defined(__SH4__) @@ -406,15 +408,16 @@ static void setup_frame(int sig, struct if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_sigreturn,r3 ; trapa #0x10 */ -#ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc310e300 | (__NR_sigreturn); -#else - unsigned long code = 0xe300c310 | (__NR_sigreturn << 16); -#endif - + /* Generate return code (system call to sigreturn) */ + err |= __put_user(MOVW(7), &frame->retcode[0]); + err |= __put_user(TRAP16, &frame->retcode[1]); + err |= __put_user(OR_R0_R0, &frame->retcode[2]); + err |= __put_user(OR_R0_R0, &frame->retcode[3]); + err |= __put_user(OR_R0_R0, &frame->retcode[4]); + err |= __put_user(OR_R0_R0, &frame->retcode[5]); + err |= __put_user(OR_R0_R0, &frame->retcode[6]); + err |= __put_user((__NR_sigreturn), &frame->retcode[7]); regs->pr = (unsigned long) frame->retcode; - err |= __put_user(code, (long *)(frame->retcode+0)); } if (err) @@ -423,7 +426,9 @@ static void setup_frame(int sig, struct /* Set up registers for signal handler */ regs->regs[15] = (unsigned long) frame; regs->regs[4] = signal; /* Arg for signal handler */ - regs->pc = (unsigned long) ka->sa.sa_handler; + regs->regs[5] = 0; + regs->regs[6] = (unsigned long) &frame->sc; + regs->pc = (unsigned long) ka->sa.sa_handler; set_fs(USER_DS); @@ -433,7 +438,9 @@ static void setup_frame(int sig, struct #endif flush_cache_sigtramp(regs->pr); - return; + if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) + flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); + return; give_sigsegv: if (sig == SIGSEGV) @@ -459,8 +466,6 @@ static void setup_rt_frame(int sig, stru ? current->exec_domain->signal_invmap[sig] : sig; - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ @@ -480,15 +485,16 @@ static void setup_rt_frame(int sig, stru if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_rt_sigreturn,r3 ; trapa #0x10 */ -#ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc310e300 | (__NR_rt_sigreturn); -#else - unsigned long code = 0xe300c310 | (__NR_rt_sigreturn << 16); -#endif - + /* Generate return code (system call to rt_sigreturn) */ + err |= __put_user(MOVW(7), &frame->retcode[0]); + err |= __put_user(TRAP16, &frame->retcode[1]); + err |= __put_user(OR_R0_R0, &frame->retcode[2]); + err |= __put_user(OR_R0_R0, &frame->retcode[3]); + err |= __put_user(OR_R0_R0, &frame->retcode[4]); + err |= __put_user(OR_R0_R0, &frame->retcode[5]); + err |= __put_user(OR_R0_R0, &frame->retcode[6]); + err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]); regs->pr = (unsigned long) frame->retcode; - err |= __put_user(code, (long *)(frame->retcode+0)); } if (err) @@ -497,6 +503,8 @@ static void setup_rt_frame(int sig, stru /* Set up registers for signal handler */ regs->regs[15] = (unsigned long) frame; regs->regs[4] = signal; /* Arg for signal handler */ + regs->regs[5] = (unsigned long)&frame->info; /* Arg2 (siginfo) */ + regs->regs[6] = (unsigned long)&frame->uc; /* Arg3 (context) */ regs->pc = (unsigned long) ka->sa.sa_handler; set_fs(USER_DS); @@ -507,7 +515,9 @@ static void setup_rt_frame(int sig, stru #endif flush_cache_sigtramp(regs->pr); - return; + if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) + flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); + return; give_sigsegv: if (sig == SIGSEGV)