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 | |
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>
-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 | ||||
-rw-r--r-- | include/asm-parisc/compat_ucontext.h | 3 | ||||
-rw-r--r-- | include/asm-parisc/rt_sigframe.h | 4 |
6 files changed, 232 insertions, 14 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, |
diff --git a/include/asm-parisc/compat_ucontext.h b/include/asm-parisc/compat_ucontext.h index a1228a3d2071..2f7292afde3c 100644 --- a/include/asm-parisc/compat_ucontext.h +++ b/include/asm-parisc/compat_ucontext.h | |||
@@ -1,8 +1,7 @@ | |||
1 | #ifndef _ASM_PARISC_COMPAT_UCONTEXT_H | 1 | #ifndef _ASM_PARISC_COMPAT_UCONTEXT_H |
2 | #define _ASM_PARISC_COMPAT_UCONTEXT_H | 2 | #define _ASM_PARISC_COMPAT_UCONTEXT_H |
3 | 3 | ||
4 | #include<linux/compat.h> | 4 | #include <linux/compat.h> |
5 | #include<asm/compat_signal.h> | ||
6 | 5 | ||
7 | /* 32-bit ucontext as seen from an 64-bit kernel */ | 6 | /* 32-bit ucontext as seen from an 64-bit kernel */ |
8 | struct compat_ucontext { | 7 | struct compat_ucontext { |
diff --git a/include/asm-parisc/rt_sigframe.h b/include/asm-parisc/rt_sigframe.h index 5623c032b64c..f0dd3b30f6c4 100644 --- a/include/asm-parisc/rt_sigframe.h +++ b/include/asm-parisc/rt_sigframe.h | |||
@@ -1,10 +1,6 @@ | |||
1 | #ifndef _ASM_PARISC_RT_SIGFRAME_H | 1 | #ifndef _ASM_PARISC_RT_SIGFRAME_H |
2 | #define _ASM_PARISC_RT_SIGFRAME_H | 2 | #define _ASM_PARISC_RT_SIGFRAME_H |
3 | 3 | ||
4 | #ifdef CONFIG_COMPAT | ||
5 | #include <asm/compat_rt_sigframe.h> | ||
6 | #endif | ||
7 | |||
8 | #define SIGRETURN_TRAMP 4 | 4 | #define SIGRETURN_TRAMP 4 |
9 | #define SIGRESTARTBLOCK_TRAMP 5 | 5 | #define SIGRESTARTBLOCK_TRAMP 5 |
10 | #define TRAMP_SIZE (SIGRETURN_TRAMP + SIGRESTARTBLOCK_TRAMP) | 6 | #define TRAMP_SIZE (SIGRETURN_TRAMP + SIGRESTARTBLOCK_TRAMP) |