diff options
| author | Kyle McMartin <kyle@parisc-linux.org> | 2006-01-15 14:10:29 -0500 |
|---|---|---|
| committer | Kyle McMartin <kyle@duet.int.mcmartin.ca> | 2006-01-22 20:57:42 -0500 |
| commit | f671c45df23005692daa200aba768c642fb14ef2 (patch) | |
| tree | fbc882669f06171cd1a8be2ad7b99f062a6e1e57 /arch | |
| parent | 16541c8745e28f62b3dcb6cb354b73c9c01ea178 (diff) | |
[PARISC] Arch-specific compat signals
Add enough arch-specific compat signals code to enable parisc64
to compile and boot out of the mainline tree. There are likely still
many dragons here, but this is a start to squashing the last
big difference between the mainline tree and the parisc-linux tree.
The remaining bugs can be squashed as they come up.
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/parisc/kernel/ptrace.c | 8 | ||||
| -rw-r--r-- | arch/parisc/kernel/signal.c | 2 | ||||
| -rw-r--r-- | arch/parisc/kernel/signal32.c | 102 | ||||
| -rw-r--r-- | arch/parisc/kernel/signal32.h | 127 |
4 files changed, 231 insertions, 8 deletions
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 27160e8bf15b..413292f1a4a3 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c | |||
| @@ -91,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 91 | int copied; | 91 | int copied; |
| 92 | 92 | ||
| 93 | #ifdef __LP64__ | 93 | #ifdef __LP64__ |
| 94 | if (is_compat_task(child)) { | 94 | if (personality(child->personality) == PER_LINUX32) { |
| 95 | unsigned int tmp; | 95 | unsigned int tmp; |
| 96 | 96 | ||
| 97 | addr &= 0xffffffffL; | 97 | addr &= 0xffffffffL; |
| @@ -123,7 +123,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 123 | case PTRACE_POKEDATA: | 123 | case PTRACE_POKEDATA: |
| 124 | ret = 0; | 124 | ret = 0; |
| 125 | #ifdef __LP64__ | 125 | #ifdef __LP64__ |
| 126 | if (is_compat_task(child)) { | 126 | if (personality(child->personality) == PER_LINUX32) { |
| 127 | unsigned int tmp = (unsigned int)data; | 127 | unsigned int tmp = (unsigned int)data; |
| 128 | DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n", | 128 | DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n", |
| 129 | request == PTRACE_POKETEXT ? "TEXT" : "DATA", | 129 | request == PTRACE_POKETEXT ? "TEXT" : "DATA", |
| @@ -146,7 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 146 | case PTRACE_PEEKUSR: { | 146 | case PTRACE_PEEKUSR: { |
| 147 | ret = -EIO; | 147 | ret = -EIO; |
| 148 | #ifdef __LP64__ | 148 | #ifdef __LP64__ |
| 149 | if (is_compat_task(child)) { | 149 | if (personality(child->personality) == PER_LINUX32) { |
| 150 | unsigned int tmp; | 150 | unsigned int tmp; |
| 151 | 151 | ||
| 152 | if (addr & (sizeof(int)-1)) | 152 | if (addr & (sizeof(int)-1)) |
| @@ -205,7 +205,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 205 | goto out_tsk; | 205 | goto out_tsk; |
| 206 | } | 206 | } |
| 207 | #ifdef __LP64__ | 207 | #ifdef __LP64__ |
| 208 | if (is_compat_task(child)) { | 208 | if (personality(child->personality) == PER_LINUX32) { |
| 209 | if (addr & (sizeof(int)-1)) | 209 | if (addr & (sizeof(int)-1)) |
| 210 | goto out_tsk; | 210 | goto out_tsk; |
| 211 | if ((addr = translate_usr_offset(addr)) < 0) | 211 | if ((addr = translate_usr_offset(addr)) < 0) |
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 3a25a7bd673e..05767e83cf2d 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
| @@ -317,7 +317,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 317 | 317 | ||
| 318 | if(personality(current->personality) == PER_LINUX32) { | 318 | if(personality(current->personality) == PER_LINUX32) { |
| 319 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); | 319 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); |
| 320 | err |= compat_copy_siginfo_to_user(&compat_frame->info, info); | 320 | err |= copy_siginfo_to_user32(&compat_frame->info, info); |
| 321 | DBG(1,"SETUP_RT_FRAME: 1\n"); | 321 | DBG(1,"SETUP_RT_FRAME: 1\n"); |
| 322 | compat_val = (compat_int_t)current->sas_ss_sp; | 322 | compat_val = (compat_int_t)current->sas_ss_sp; |
| 323 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); | 323 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); |
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 0792e20efef3..a6b4231cafa1 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include <linux/types.h> | 31 | #include <linux/types.h> |
| 32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
| 33 | 33 | ||
| 34 | #include <asm/compat_signal.h> | ||
| 35 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
| 36 | 35 | ||
| 37 | #include "signal32.h" | 36 | #include "signal32.h" |
| @@ -398,3 +397,104 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ | |||
| 398 | 397 | ||
| 399 | return err; | 398 | return err; |
| 400 | } | 399 | } |
| 400 | |||
| 401 | int | ||
| 402 | copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) | ||
| 403 | { | ||
| 404 | unsigned long tmp; | ||
| 405 | int err; | ||
| 406 | |||
| 407 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) | ||
| 408 | return -EFAULT; | ||
| 409 | |||
| 410 | err = __get_user(to->si_signo, &from->si_signo); | ||
| 411 | err |= __get_user(to->si_errno, &from->si_errno); | ||
| 412 | err |= __get_user(to->si_code, &from->si_code); | ||
| 413 | |||
| 414 | if (to->si_code < 0) | ||
| 415 | err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | ||
| 416 | else { | ||
| 417 | switch (to->si_code >> 16) { | ||
| 418 | case __SI_CHLD >> 16: | ||
| 419 | err |= __get_user(to->si_utime, &from->si_utime); | ||
| 420 | err |= __get_user(to->si_stime, &from->si_stime); | ||
| 421 | err |= __get_user(to->si_status, &from->si_status); | ||
| 422 | default: | ||
| 423 | err |= __get_user(to->si_pid, &from->si_pid); | ||
| 424 | err |= __get_user(to->si_uid, &from->si_uid); | ||
| 425 | break; | ||
| 426 | case __SI_FAULT >> 16: | ||
| 427 | err |= __get_user(tmp, &from->si_addr); | ||
| 428 | to->si_addr = (void __user *) tmp; | ||
| 429 | break; | ||
| 430 | case __SI_POLL >> 16: | ||
| 431 | err |= __get_user(to->si_band, &from->si_band); | ||
| 432 | err |= __get_user(to->si_fd, &from->si_fd); | ||
| 433 | break; | ||
| 434 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | ||
| 435 | case __SI_MESGQ >> 16: | ||
| 436 | err |= __get_user(to->si_pid, &from->si_pid); | ||
| 437 | err |= __get_user(to->si_uid, &from->si_uid); | ||
| 438 | err |= __get_user(to->si_int, &from->si_int); | ||
| 439 | break; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | return err; | ||
| 443 | } | ||
| 444 | |||
| 445 | int | ||
| 446 | copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) | ||
| 447 | { | ||
| 448 | unsigned int addr; | ||
| 449 | int err; | ||
| 450 | |||
| 451 | if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | ||
| 452 | return -EFAULT; | ||
| 453 | |||
| 454 | /* If you change siginfo_t structure, please be sure | ||
| 455 | this code is fixed accordingly. | ||
| 456 | It should never copy any pad contained in the structure | ||
| 457 | to avoid security leaks, but must copy the generic | ||
| 458 | 3 ints plus the relevant union member. | ||
| 459 | This routine must convert siginfo from 64bit to 32bit as well | ||
| 460 | at the same time. */ | ||
| 461 | err = __put_user(from->si_signo, &to->si_signo); | ||
| 462 | err |= __put_user(from->si_errno, &to->si_errno); | ||
| 463 | err |= __put_user((short)from->si_code, &to->si_code); | ||
| 464 | if (from->si_code < 0) | ||
| 465 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | ||
| 466 | else { | ||
| 467 | switch (from->si_code >> 16) { | ||
| 468 | case __SI_CHLD >> 16: | ||
| 469 | err |= __put_user(from->si_utime, &to->si_utime); | ||
| 470 | err |= __put_user(from->si_stime, &to->si_stime); | ||
| 471 | err |= __put_user(from->si_status, &to->si_status); | ||
| 472 | default: | ||
| 473 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 474 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 475 | break; | ||
| 476 | case __SI_FAULT >> 16: | ||
| 477 | /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ | ||
| 478 | err |= __put_user(from->_sifields._pad[0], &to->si_addr); | ||
| 479 | break; | ||
| 480 | case __SI_POLL >> 16: | ||
| 481 | err |= __put_user(from->si_band, &to->si_band); | ||
| 482 | err |= __put_user(from->si_fd, &to->si_fd); | ||
| 483 | break; | ||
| 484 | case __SI_TIMER >> 16: | ||
| 485 | err |= __put_user(from->si_tid, &to->si_tid); | ||
| 486 | err |= __put_user(from->si_overrun, &to->si_overrun); | ||
| 487 | addr = (unsigned long) from->si_ptr; | ||
| 488 | err |= __put_user(addr, &to->si_ptr); | ||
| 489 | break; | ||
| 490 | case __SI_RT >> 16: /* Not generated by the kernel as of now. */ | ||
| 491 | case __SI_MESGQ >> 16: | ||
| 492 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 493 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 494 | addr = (unsigned long) from->si_ptr; | ||
| 495 | err |= __put_user(addr, &to->si_ptr); | ||
| 496 | break; | ||
| 497 | } | ||
| 498 | } | ||
| 499 | return err; | ||
| 500 | } | ||
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index 4d1569e717cc..e39b38a67a87 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h | |||
| @@ -20,8 +20,34 @@ | |||
| 20 | #define _PARISC64_KERNEL_SIGNAL32_H | 20 | #define _PARISC64_KERNEL_SIGNAL32_H |
| 21 | 21 | ||
| 22 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
| 23 | #include <asm/compat_signal.h> | 23 | |
| 24 | #include <asm/compat_rt_sigframe.h> | 24 | typedef compat_uptr_t compat_sighandler_t; |
| 25 | |||
| 26 | typedef struct compat_sigaltstack { | ||
| 27 | compat_uptr_t ss_sp; | ||
| 28 | compat_int_t ss_flags; | ||
| 29 | compat_size_t ss_size; | ||
| 30 | } compat_stack_t; | ||
| 31 | |||
| 32 | /* Most things should be clean enough to redefine this at will, if care | ||
| 33 | is taken to make libc match. */ | ||
| 34 | |||
| 35 | struct compat_sigaction { | ||
| 36 | compat_sighandler_t sa_handler; | ||
| 37 | compat_uint_t sa_flags; | ||
| 38 | compat_sigset_t sa_mask; /* mask last for extensibility */ | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* 32-bit ucontext as seen from an 64-bit kernel */ | ||
| 42 | struct compat_ucontext { | ||
| 43 | compat_uint_t uc_flags; | ||
| 44 | compat_uptr_t uc_link; | ||
| 45 | compat_stack_t uc_stack; /* struct compat_sigaltstack (12 bytes)*/ | ||
| 46 | /* FIXME: Pad out to get uc_mcontext to start at an 8-byte aligned boundary */ | ||
| 47 | compat_uint_t pad[1]; | ||
| 48 | struct compat_sigcontext uc_mcontext; | ||
| 49 | compat_sigset_t uc_sigmask; /* mask last for extensibility */ | ||
| 50 | }; | ||
| 25 | 51 | ||
| 26 | /* ELF32 signal handling */ | 52 | /* ELF32 signal handling */ |
| 27 | 53 | ||
| @@ -29,6 +55,103 @@ struct k_sigaction32 { | |||
| 29 | struct compat_sigaction sa; | 55 | struct compat_sigaction sa; |
| 30 | }; | 56 | }; |
| 31 | 57 | ||
| 58 | typedef struct compat_siginfo { | ||
| 59 | int si_signo; | ||
| 60 | int si_errno; | ||
| 61 | int si_code; | ||
| 62 | |||
| 63 | union { | ||
| 64 | int _pad[((128/sizeof(int)) - 3)]; | ||
| 65 | |||
| 66 | /* kill() */ | ||
| 67 | struct { | ||
| 68 | unsigned int _pid; /* sender's pid */ | ||
| 69 | unsigned int _uid; /* sender's uid */ | ||
| 70 | } _kill; | ||
| 71 | |||
| 72 | /* POSIX.1b timers */ | ||
| 73 | struct { | ||
| 74 | compat_timer_t _tid; /* timer id */ | ||
| 75 | int _overrun; /* overrun count */ | ||
| 76 | char _pad[sizeof(unsigned int) - sizeof(int)]; | ||
| 77 | compat_sigval_t _sigval; /* same as below */ | ||
| 78 | int _sys_private; /* not to be passed to user */ | ||
| 79 | } _timer; | ||
| 80 | |||
| 81 | /* POSIX.1b signals */ | ||
| 82 | struct { | ||
| 83 | unsigned int _pid; /* sender's pid */ | ||
| 84 | unsigned int _uid; /* sender's uid */ | ||
| 85 | compat_sigval_t _sigval; | ||
| 86 | } _rt; | ||
| 87 | |||
| 88 | /* SIGCHLD */ | ||
| 89 | struct { | ||
| 90 | unsigned int _pid; /* which child */ | ||
| 91 | unsigned int _uid; /* sender's uid */ | ||
| 92 | int _status; /* exit code */ | ||
| 93 | compat_clock_t _utime; | ||
| 94 | compat_clock_t _stime; | ||
| 95 | } _sigchld; | ||
| 96 | |||
| 97 | /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ | ||
| 98 | struct { | ||
| 99 | unsigned int _addr; /* faulting insn/memory ref. */ | ||
| 100 | } _sigfault; | ||
| 101 | |||
| 102 | /* SIGPOLL */ | ||
| 103 | struct { | ||
| 104 | int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ | ||
| 105 | int _fd; | ||
| 106 | } _sigpoll; | ||
| 107 | } _sifields; | ||
| 108 | } compat_siginfo_t; | ||
| 109 | |||
| 110 | int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from); | ||
| 111 | int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from); | ||
| 112 | |||
| 113 | /* In a deft move of uber-hackery, we decide to carry the top half of all | ||
| 114 | * 64-bit registers in a non-portable, non-ABI, hidden structure. | ||
| 115 | * Userspace can read the hidden structure if it *wants* but is never | ||
| 116 | * guaranteed to be in the same place. Infact the uc_sigmask from the | ||
| 117 | * ucontext_t structure may push the hidden register file downards | ||
| 118 | */ | ||
| 119 | struct compat_regfile { | ||
| 120 | /* Upper half of all the 64-bit registers that were truncated | ||
| 121 | on a copy to a 32-bit userspace */ | ||
| 122 | compat_int_t rf_gr[32]; | ||
| 123 | compat_int_t rf_iasq[2]; | ||
| 124 | compat_int_t rf_iaoq[2]; | ||
| 125 | compat_int_t rf_sar; | ||
| 126 | }; | ||
| 127 | |||
| 128 | #define COMPAT_SIGRETURN_TRAMP 4 | ||
| 129 | #define COMPAT_SIGRESTARTBLOCK_TRAMP 5 | ||
| 130 | #define COMPAT_TRAMP_SIZE (COMPAT_SIGRETURN_TRAMP + \ | ||
| 131 | COMPAT_SIGRESTARTBLOCK_TRAMP) | ||
| 132 | |||
| 133 | struct compat_rt_sigframe { | ||
| 134 | /* XXX: Must match trampoline size in arch/parisc/kernel/signal.c | ||
| 135 | Secondary to that it must protect the ERESTART_RESTARTBLOCK | ||
| 136 | trampoline we left on the stack (we were bad and didn't | ||
| 137 | change sp so we could run really fast.) */ | ||
| 138 | compat_uint_t tramp[COMPAT_TRAMP_SIZE]; | ||
| 139 | compat_siginfo_t info; | ||
| 140 | struct compat_ucontext uc; | ||
| 141 | /* Hidden location of truncated registers, *must* be last. */ | ||
| 142 | struct compat_regfile regs; | ||
| 143 | }; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * The 32-bit ABI wants at least 48 bytes for a function call frame: | ||
| 147 | * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of | ||
| 148 | * which Linux/parisc uses is sp-20 for the saved return pointer...) | ||
| 149 | * Then, the stack pointer must be rounded to a cache line (64 bytes). | ||
| 150 | */ | ||
| 151 | #define SIGFRAME32 64 | ||
| 152 | #define FUNCTIONCALLFRAME32 48 | ||
| 153 | #define PARISC_RT_SIGFRAME_SIZE32 (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32) | ||
| 154 | |||
| 32 | void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); | 155 | void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); |
| 33 | void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); | 156 | void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); |
| 34 | int do_sigaltstack32 (const compat_stack_t __user *uss32, | 157 | int do_sigaltstack32 (const compat_stack_t __user *uss32, |
