Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
81e7009e
Commit
81e7009e
authored
Oct 18, 2005
by
Stephen Rothwell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
powerpc: merge ppc signal.c and ppc64 signal32.c
Signed-off-by:
Stephen Rothwell
<
sfr@canb.auug.org.au
>
parent
55d36339
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
635 additions
and
1135 deletions
+635
-1135
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/Makefile
+1
-1
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_32.c
+624
-353
arch/ppc/kernel/Makefile
arch/ppc/kernel/Makefile
+2
-2
arch/ppc/kernel/signal.c
arch/ppc/kernel/signal.c
+0
-771
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/Makefile
+1
-1
include/asm-ppc64/ppc32.h
include/asm-ppc64/ppc32.h
+7
-7
No files found.
arch/powerpc/kernel/Makefile
View file @
81e7009e
...
@@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC
...
@@ -10,7 +10,7 @@ CFLAGS_prom_init.o += -fPIC
CFLAGS_btext.o
+=
-fPIC
CFLAGS_btext.o
+=
-fPIC
endif
endif
obj-y
:=
semaphore.o cputable.o ptrace.o
obj-y
:=
semaphore.o cputable.o ptrace.o
signal_32.o
obj-$(CONFIG_PPC64)
+=
binfmt_elf32.o sys_ppc32.o
obj-$(CONFIG_PPC64)
+=
binfmt_elf32.o sys_ppc32.o
obj-$(CONFIG_ALTIVEC)
+=
vecemu.o vector.o
obj-$(CONFIG_ALTIVEC)
+=
vecemu.o vector.o
obj-$(CONFIG_POWER4)
+=
idle_power4.o
obj-$(CONFIG_POWER4)
+=
idle_power4.o
...
...
arch/p
pc64/kernel/signal
32.c
→
arch/p
owerpc/kernel/signal_
32.c
View file @
81e7009e
/*
/*
*
signal32.c: Support 32bit signal syscalls.
*
Signal handling for 32bit PPC and 32bit tasks on 64bit PPC
*
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
* Copyright (C) 2001 IBM
* Copyright (C) 2001 IBM
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*
*
* These routines maintain argument size conversion between 32bit and 64bit
* Derived from "arch/i386/kernel/signal.c"
* environment.
* Copyright (C) 1991, 1992 Linus Torvalds
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
*
*
* This program is free software; you can redistribute it and/or
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* modify it under the terms of the GNU General Public License
...
@@ -21,36 +24,329 @@
...
@@ -21,36 +24,329 @@
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/signal.h>
#include <linux/syscalls.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/elf.h>
#include <linux/elf.h>
#ifdef CONFIG_PPC64
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
#include <linux/ptrace.h>
#include <asm/ppc32.h>
#else
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/suspend.h>
#endif
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#ifdef CONFIG_PPC64
#include <asm/ppc32.h>
#include <asm/ppcdebug.h>
#include <asm/ppcdebug.h>
#include <asm/unistd.h>
#include <asm/unistd.h>
#include <asm/cacheflush.h>
#include <asm/vdso.h>
#include <asm/vdso.h>
#else
#include <asm/ucontext.h>
#include <asm/pgtable.h>
#endif
#
define DEBUG_SIG 0
#
undef DEBUG_SIG
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
#define GP_REGS_SIZE32 min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
#ifdef CONFIG_PPC64
#define do_signal do_signal32
#define sys_sigsuspend sys32_sigsuspend
#define sys_rt_sigsuspend sys32_rt_sigsuspend
#define sys_rt_sigreturn sys32_rt_sigreturn
#define sys_sigaction sys32_sigaction
#define sys_swapcontext sys32_swapcontext
#define sys_sigreturn sys32_sigreturn
#define old_sigaction old_sigaction32
#define sigcontext sigcontext32
#define mcontext mcontext32
#define ucontext ucontext32
/*
* Returning 0 means we return to userspace via
* ret_from_except and thus restore all user
* registers from *regs. This is what we need
* to do when a signal has been delivered.
*/
#define sigreturn_exit(regs) return 0
#define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
#undef __SIGNAL_FRAMESIZE
#define __SIGNAL_FRAMESIZE __SIGNAL_FRAMESIZE32
#undef ELF_NVRREG
#define ELF_NVRREG ELF_NVRREG32
/*
* Functions for flipping sigsets (thanks to brain dead generic
* implementation that makes things simple for little endian only)
*/
static
inline
int
put_sigset_t
(
compat_sigset_t
__user
*
uset
,
sigset_t
*
set
)
{
compat_sigset_t
cset
;
switch
(
_NSIG_WORDS
)
{
case
4
:
cset
.
sig
[
5
]
=
set
->
sig
[
3
]
&
0xffffffffull
;
cset
.
sig
[
7
]
=
set
->
sig
[
3
]
>>
32
;
case
3
:
cset
.
sig
[
4
]
=
set
->
sig
[
2
]
&
0xffffffffull
;
cset
.
sig
[
5
]
=
set
->
sig
[
2
]
>>
32
;
case
2
:
cset
.
sig
[
2
]
=
set
->
sig
[
1
]
&
0xffffffffull
;
cset
.
sig
[
3
]
=
set
->
sig
[
1
]
>>
32
;
case
1
:
cset
.
sig
[
0
]
=
set
->
sig
[
0
]
&
0xffffffffull
;
cset
.
sig
[
1
]
=
set
->
sig
[
0
]
>>
32
;
}
return
copy_to_user
(
uset
,
&
cset
,
sizeof
(
*
uset
));
}
static
inline
int
get_sigset_t
(
sigset_t
*
set
,
compat_sigset_t
__user
*
uset
)
{
compat_sigset_t
s32
;
if
(
copy_from_user
(
&
s32
,
uset
,
sizeof
(
*
uset
)))
return
-
EFAULT
;
/*
* Swap the 2 words of the 64-bit sigset_t (they are stored
* in the "wrong" endian in 32-bit user storage).
*/
switch
(
_NSIG_WORDS
)
{
case
4
:
set
->
sig
[
3
]
=
s32
.
sig
[
6
]
|
(((
long
)
s32
.
sig
[
7
])
<<
32
);
case
3
:
set
->
sig
[
2
]
=
s32
.
sig
[
4
]
|
(((
long
)
s32
.
sig
[
5
])
<<
32
);
case
2
:
set
->
sig
[
1
]
=
s32
.
sig
[
2
]
|
(((
long
)
s32
.
sig
[
3
])
<<
32
);
case
1
:
set
->
sig
[
0
]
=
s32
.
sig
[
0
]
|
(((
long
)
s32
.
sig
[
1
])
<<
32
);
}
return
0
;
}
static
inline
int
get_old_sigaction
(
struct
k_sigaction
*
new_ka
,
struct
old_sigaction
__user
*
act
)
{
compat_old_sigset_t
mask
;
compat_uptr_t
handler
,
restorer
;
if
(
get_user
(
handler
,
&
act
->
sa_handler
)
||
__get_user
(
restorer
,
&
act
->
sa_restorer
)
||
__get_user
(
new_ka
->
sa
.
sa_flags
,
&
act
->
sa_flags
)
||
__get_user
(
mask
,
&
act
->
sa_mask
))
return
-
EFAULT
;
new_ka
->
sa
.
sa_handler
=
compat_ptr
(
handler
);
new_ka
->
sa
.
sa_restorer
=
compat_ptr
(
restorer
);
siginitset
(
&
new_ka
->
sa
.
sa_mask
,
mask
);
return
0
;
}
static
inline
compat_uptr_t
to_user_ptr
(
void
*
kp
)
{
return
(
compat_uptr_t
)(
u64
)
kp
;
}
#define from_user_ptr(p) compat_ptr(p)
static
inline
int
save_general_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
frame
)
{
elf_greg_t64
*
gregs
=
(
elf_greg_t64
*
)
regs
;
int
i
;
for
(
i
=
0
;
i
<=
PT_RESULT
;
i
++
)
if
(
__put_user
((
unsigned
int
)
gregs
[
i
],
&
frame
->
mc_gregs
[
i
]))
return
-
EFAULT
;
return
0
;
}
static
inline
int
restore_general_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
sr
)
{
elf_greg_t64
*
gregs
=
(
elf_greg_t64
*
)
regs
;
int
i
;
for
(
i
=
0
;
i
<=
PT_RESULT
;
i
++
)
{
if
((
i
==
PT_MSR
)
||
(
i
==
PT_SOFTE
))
continue
;
if
(
__get_user
(
gregs
[
i
],
&
sr
->
mc_gregs
[
i
]))
return
-
EFAULT
;
}
return
0
;
}
#else
/* CONFIG_PPC64 */
extern
void
sigreturn_exit
(
struct
pt_regs
*
);
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
static
inline
int
put_sigset_t
(
sigset_t
__user
*
uset
,
sigset_t
*
set
)
{
return
copy_to_user
(
uset
,
set
,
sizeof
(
*
uset
));
}
static
inline
int
get_sigset_t
(
sigset_t
*
set
,
sigset_t
__user
*
uset
)
{
return
copy_from_user
(
set
,
uset
,
sizeof
(
*
uset
));
}
static
inline
int
get_old_sigaction
(
struct
k_sigaction
*
new_ka
,
struct
old_sigaction
__user
*
act
)
{
old_sigset_t
mask
;
if
(
!
access_ok
(
VERIFY_READ
,
act
,
sizeof
(
*
act
))
||
__get_user
(
new_ka
->
sa
.
sa_handler
,
&
act
->
sa_handler
)
||
__get_user
(
new_ka
->
sa
.
sa_restorer
,
&
act
->
sa_restorer
))
return
-
EFAULT
;
__get_user
(
new_ka
->
sa
.
sa_flags
,
&
act
->
sa_flags
);
__get_user
(
mask
,
&
act
->
sa_mask
);
siginitset
(
&
new_ka
->
sa
.
sa_mask
,
mask
);
return
0
;
}
#define to_user_ptr(p) (p)
#define from_user_ptr(p) (p)
static
inline
int
save_general_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
frame
)
{
return
__copy_to_user
(
&
frame
->
mc_gregs
,
regs
,
GP_REGS_SIZE
);
}
static
inline
int
restore_general_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
sr
)
{
/* copy up to but not including MSR */
if
(
__copy_from_user
(
regs
,
&
sr
->
mc_gregs
,
PT_MSR
*
sizeof
(
elf_greg_t
)))
return
-
EFAULT
;
/* copy from orig_r3 (the word after the MSR) up to the end */
if
(
__copy_from_user
(
&
regs
->
orig_gpr3
,
&
sr
->
mc_gregs
[
PT_ORIG_R3
],
GP_REGS_SIZE
-
PT_ORIG_R3
*
sizeof
(
elf_greg_t
)))
return
-
EFAULT
;
return
0
;
}
#endif
/* CONFIG_PPC64 */
int
do_signal
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
);
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
long
sys_sigsuspend
(
old_sigset_t
mask
,
int
p2
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
;
mask
&=
_BLOCKABLE
;
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
siginitset
(
&
current
->
blocked
,
mask
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal
(
&
saveset
,
regs
))
sigreturn_exit
(
regs
);
}
}
long
sys_rt_sigsuspend
(
#ifdef CONFIG_PPC64
compat_sigset_t
__user
*
unewset
,
#else
sigset_t
__user
*
unewset
,
#endif
size_t
sigsetsize
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
,
newset
;
/* XXX: Don't preclude handling different sized sigset_t's. */
if
(
sigsetsize
!=
sizeof
(
sigset_t
))
return
-
EINVAL
;
if
(
get_sigset_t
(
&
newset
,
unewset
))
return
-
EFAULT
;
sigdelsetmask
(
&
newset
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
current
->
blocked
=
newset
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal
(
&
saveset
,
regs
))
sigreturn_exit
(
regs
);
}
}
#ifdef CONFIG_PPC32
long
sys_sigaltstack
(
const
stack_t
__user
*
uss
,
stack_t
__user
*
uoss
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
return
do_sigaltstack
(
uss
,
uoss
,
regs
->
gpr
[
1
]);
}
#endif
long
sys_sigaction
(
int
sig
,
struct
old_sigaction
__user
*
act
,
struct
old_sigaction
__user
*
oact
)
{
struct
k_sigaction
new_ka
,
old_ka
;
int
ret
;
#ifdef CONFIG_PPC64
if
(
sig
<
0
)
sig
=
-
sig
;
#endif
if
(
act
)
{
if
(
get_old_sigaction
(
&
new_ka
,
act
))
return
-
EFAULT
;
}
ret
=
do_sigaction
(
sig
,
act
?
&
new_ka
:
NULL
,
oact
?
&
old_ka
:
NULL
);
if
(
!
ret
&&
oact
)
{
if
(
!
access_ok
(
VERIFY_WRITE
,
oact
,
sizeof
(
*
oact
))
||
__put_user
(
to_user_ptr
(
old_ka
.
sa
.
sa_handler
),
&
oact
->
sa_handler
)
||
__put_user
(
to_user_ptr
(
old_ka
.
sa
.
sa_restorer
),
&
oact
->
sa_restorer
)
||
__put_user
(
old_ka
.
sa
.
sa_flags
,
&
oact
->
sa_flags
)
||
__put_user
(
old_ka
.
sa
.
sa_mask
.
sig
[
0
],
&
oact
->
sa_mask
))
return
-
EFAULT
;
}
return
ret
;
}
/*
/*
* When we have signals to deliver, we set up on the
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* user stack, going down from the original stack pointer:
* a sigregs
32
struct
* a sigregs struct
* a sigcontext
32
struct
* a sigcontext struct
* a gap of __SIGNAL_FRAMESIZE
32
bytes
* a gap of __SIGNAL_FRAMESIZE bytes
*
*
* Each of these things must be a multiple of 16 bytes in size.
* Each of these things must be a multiple of 16 bytes in size.
*
*
*/
*/
struct
sigregs
32
{
struct
sigregs
{
struct
mcontext
32
mctx
;
/* all the register values */
struct
mcontext
mctx
;
/* all the register values */
/*
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
* regs and 18 fp regs below sp before decrementing it.
...
@@ -64,17 +360,21 @@ struct sigregs32 {
...
@@ -64,17 +360,21 @@ struct sigregs32 {
/*
/*
* When we have rt signals to deliver, we set up on the
* When we have rt signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* user stack, going down from the original stack pointer:
* one rt_sigframe
32
struct (siginfo + ucontext + ABI gap)
* one rt_sigframe struct (siginfo + ucontext + ABI gap)
* a gap of __SIGNAL_FRAMESIZE
32
+16 bytes
* a gap of __SIGNAL_FRAMESIZE+16 bytes
* (the +16 is to get the siginfo and ucontext
32
in the same
* (the +16 is to get the siginfo and ucontext in the same
* positions as in older kernels).
* positions as in older kernels).
*
*
* Each of these things must be a multiple of 16 bytes in size.
* Each of these things must be a multiple of 16 bytes in size.
*
*
*/
*/
struct
rt_sigframe32
{
struct
rt_sigframe
{
#ifdef CONFIG_PPC64
compat_siginfo_t
info
;
compat_siginfo_t
info
;
struct
ucontext32
uc
;
#else
struct
siginfo
info
;
#endif
struct
ucontext
uc
;
/*
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
* regs and 18 fp regs below sp before decrementing it.
...
@@ -82,66 +382,24 @@ struct rt_sigframe32 {
...
@@ -82,66 +382,24 @@ struct rt_sigframe32 {
int
abigap
[
56
];
int
abigap
[
56
];
};
};
/*
* Common utility functions used by signal and context support
*
*/
/*
* Restore the user process's signal mask
* (implemented in signal.c)
*/
extern
void
restore_sigmask
(
sigset_t
*
set
);
/*
* Functions for flipping sigsets (thanks to brain dead generic
* implementation that makes things simple for little endian only
*/
static
inline
void
compat_from_sigset
(
compat_sigset_t
*
compat
,
sigset_t
*
set
)
{
switch
(
_NSIG_WORDS
)
{
case
4
:
compat
->
sig
[
5
]
=
set
->
sig
[
3
]
&
0xffffffffull
;
compat
->
sig
[
7
]
=
set
->
sig
[
3
]
>>
32
;
case
3
:
compat
->
sig
[
4
]
=
set
->
sig
[
2
]
&
0xffffffffull
;
compat
->
sig
[
5
]
=
set
->
sig
[
2
]
>>
32
;
case
2
:
compat
->
sig
[
2
]
=
set
->
sig
[
1
]
&
0xffffffffull
;
compat
->
sig
[
3
]
=
set
->
sig
[
1
]
>>
32
;
case
1
:
compat
->
sig
[
0
]
=
set
->
sig
[
0
]
&
0xffffffffull
;
compat
->
sig
[
1
]
=
set
->
sig
[
0
]
>>
32
;
}
}
static
inline
void
sigset_from_compat
(
sigset_t
*
set
,
compat_sigset_t
*
compat
)
{
switch
(
_NSIG_WORDS
)
{
case
4
:
set
->
sig
[
3
]
=
compat
->
sig
[
6
]
|
(((
long
)
compat
->
sig
[
7
])
<<
32
);
case
3
:
set
->
sig
[
2
]
=
compat
->
sig
[
4
]
|
(((
long
)
compat
->
sig
[
5
])
<<
32
);
case
2
:
set
->
sig
[
1
]
=
compat
->
sig
[
2
]
|
(((
long
)
compat
->
sig
[
3
])
<<
32
);
case
1
:
set
->
sig
[
0
]
=
compat
->
sig
[
0
]
|
(((
long
)
compat
->
sig
[
1
])
<<
32
);
}
}
/*
/*
* Save the current user registers on the user stack.
* Save the current user registers on the user stack.
* We only save the altivec registers if the process has used
* We only save the altivec
/spe
registers if the process has used
* altivec instructions at some point.
* altivec
/spe
instructions at some point.
*/
*/
static
int
save_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext32
__user
*
frame
,
int
sigret
)
static
int
save_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
frame
,
int
sigret
)
{
{
elf_greg_t64
*
gregs
=
(
elf_greg_t64
*
)
regs
;
#ifdef CONFIG_PPC32
int
i
,
err
=
0
;
CHECK_FULL_REGS
(
regs
)
;
#endif
/* Make sure floating point registers are stored in regs */
/* Make sure floating point registers are stored in regs */
flush_fp_to_thread
(
current
);
flush_fp_to_thread
(
current
);
/* save general and floating-point registers */
/* save general and floating-point registers */
for
(
i
=
0
;
i
<=
PT_RESULT
;
i
++
)
if
(
save_general_regs
(
regs
,
frame
)
||
err
|=
__put_user
((
unsigned
int
)
gregs
[
i
],
&
frame
->
mc_gregs
[
i
]);
__copy_to_user
(
&
frame
->
mc_fregs
,
current
->
thread
.
fpr
,
err
|=
__copy_to_user
(
&
frame
->
mc_fregs
,
current
->
thread
.
fpr
,
ELF_NFPREG
*
sizeof
(
double
)))
ELF_NFPREG
*
sizeof
(
double
));
if
(
err
)
return
1
;
return
1
;
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
...
@@ -151,7 +409,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
...
@@ -151,7 +409,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
if
(
current
->
thread
.
used_vr
)
{
if
(
current
->
thread
.
used_vr
)
{
flush_altivec_to_thread
(
current
);
flush_altivec_to_thread
(
current
);
if
(
__copy_to_user
(
&
frame
->
mc_vregs
,
current
->
thread
.
vr
,
if
(
__copy_to_user
(
&
frame
->
mc_vregs
,
current
->
thread
.
vr
,
ELF_NVRREG
32
*
sizeof
(
vector128
)))
ELF_NVRREG
*
sizeof
(
vector128
)))
return
1
;
return
1
;
/* set MSR_VEC in the saved MSR value to indicate that
/* set MSR_VEC in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
frame->mc_vregs contains valid data */
...
@@ -169,6 +427,25 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
...
@@ -169,6 +427,25 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
return
1
;
return
1
;
#endif
/* CONFIG_ALTIVEC */
#endif
/* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
/* save spe registers */
if
(
current
->
thread
.
used_spe
)
{
flush_spe_to_thread
(
current
);
if
(
__copy_to_user
(
&
frame
->
mc_vregs
,
current
->
thread
.
evr
,
ELF_NEVRREG
*
sizeof
(
u32
)))
return
1
;
/* set MSR_SPE in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
if
(
__put_user
(
regs
->
msr
|
MSR_SPE
,
&
frame
->
mc_gregs
[
PT_MSR
]))
return
1
;
}
/* else assert((regs->msr & MSR_SPE) == 0) */
/* We always copy to/from spefscr */
if
(
__put_user
(
current
->
thread
.
spefscr
,
(
u32
__user
*
)
&
frame
->
mc_vregs
+
ELF_NEVRREG
))
return
1
;
#endif
/* CONFIG_SPE */
if
(
sigret
)
{
if
(
sigret
)
{
/* Set up the sigreturn trampoline: li r0,sigret; sc */
/* Set up the sigreturn trampoline: li r0,sigret; sc */
if
(
__put_user
(
0x38000000UL
+
sigret
,
&
frame
->
tramp
[
0
])
if
(
__put_user
(
0x38000000UL
+
sigret
,
&
frame
->
tramp
[
0
])
...
@@ -186,13 +463,11 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
...
@@ -186,13 +463,11 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame,
* (except for MSR).
* (except for MSR).
*/
*/
static
long
restore_user_regs
(
struct
pt_regs
*
regs
,
static
long
restore_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
32
__user
*
sr
,
int
sig
)
struct
mcontext
__user
*
sr
,
int
sig
)
{
{
elf_greg_t64
*
gregs
=
(
elf_greg_t64
*
)
regs
;
long
err
;
int
i
;
long
err
=
0
;
unsigned
int
save_r2
=
0
;
unsigned
int
save_r2
=
0
;
#if
def CONFIG_ALTIVEC
#if
defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
unsigned
long
msr
;
unsigned
long
msr
;
#endif
#endif
...
@@ -202,11 +477,7 @@ static long restore_user_regs(struct pt_regs *regs,
...
@@ -202,11 +477,7 @@ static long restore_user_regs(struct pt_regs *regs,
*/
*/
if
(
!
sig
)
if
(
!
sig
)
save_r2
=
(
unsigned
int
)
regs
->
gpr
[
2
];
save_r2
=
(
unsigned
int
)
regs
->
gpr
[
2
];
for
(
i
=
0
;
i
<=
PT_RESULT
;
i
++
)
{
err
=
restore_general_regs
(
regs
,
sr
);
if
((
i
==
PT_MSR
)
||
(
i
==
PT_SOFTE
))
continue
;
err
|=
__get_user
(
gregs
[
i
],
&
sr
->
mc_gregs
[
i
]);
}
if
(
!
sig
)
if
(
!
sig
)
regs
->
gpr
[
2
]
=
(
unsigned
long
)
save_r2
;
regs
->
gpr
[
2
]
=
(
unsigned
long
)
save_r2
;
if
(
err
)
if
(
err
)
...
@@ -229,135 +500,51 @@ static long restore_user_regs(struct pt_regs *regs,
...
@@ -229,135 +500,51 @@ static long restore_user_regs(struct pt_regs *regs,
sizeof
(
sr
->
mc_vregs
)))
sizeof
(
sr
->
mc_vregs
)))
return
1
;
return
1
;
}
else
if
(
current
->
thread
.
used_vr
)
}
else
if
(
current
->
thread
.
used_vr
)
memset
(
current
->
thread
.
vr
,
0
,
ELF_NVRREG
32
*
sizeof
(
vector128
));
memset
(
current
->
thread
.
vr
,
0
,
ELF_NVRREG
*
sizeof
(
vector128
));
/* Always get VRSAVE back */
/* Always get VRSAVE back */
if
(
__get_user
(
current
->
thread
.
vrsave
,
(
u32
__user
*
)
&
sr
->
mc_vregs
[
32
]))
if
(
__get_user
(
current
->
thread
.
vrsave
,
(
u32
__user
*
)
&
sr
->
mc_vregs
[
32
]))
return
1
;
return
1
;
#endif
/* CONFIG_ALTIVEC */
#endif
/* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
/* force the process to reload the spe registers from
current->thread when it next does spe instructions */
regs
->
msr
&=
~
MSR_SPE
;
if
(
!
__get_user
(
msr
,
&
sr
->
mc_gregs
[
PT_MSR
])
&&
(
msr
&
MSR_SPE
)
!=
0
)
{
/* restore spe registers from the stack */
if
(
__copy_from_user
(
current
->
thread
.
evr
,
&
sr
->
mc_vregs
,
ELF_NEVRREG
*
sizeof
(
u32
)))
return
1
;
}
else
if
(
current
->
thread
.
used_spe
)
memset
(
current
->
thread
.
evr
,
0
,
ELF_NEVRREG
*
sizeof
(
u32
));
/* Always get SPEFSCR back */
if
(
__get_user
(
current
->
thread
.
spefscr
,
(
u32
__user
*
)
&
sr
->
mc_vregs
+
ELF_NEVRREG
))
return
1
;
#endif
/* CONFIG_SPE */
#ifndef CONFIG_SMP
#ifndef CONFIG_SMP
preempt_disable
();
preempt_disable
();
if
(
last_task_used_math
==
current
)
if
(
last_task_used_math
==
current
)
last_task_used_math
=
NULL
;
last_task_used_math
=
NULL
;
if
(
last_task_used_altivec
==
current
)
if
(
last_task_used_altivec
==
current
)
last_task_used_altivec
=
NULL
;
last_task_used_altivec
=
NULL
;
#ifdef CONFIG_SPE
if
(
last_task_used_spe
==
current
)
last_task_used_spe
=
NULL
;
#endif
preempt_enable
();
preempt_enable
();
#endif
#endif
return
0
;
return
0
;
}
}
#ifdef CONFIG_PPC64
/*
* Start of nonRT signal support
*
* sigset_t is 32 bits for non-rt signals
*
* System Calls
* sigaction sys32_sigaction
* sigreturn sys32_sigreturn
*
* Note sigsuspend has no special 32 bit routine - uses the 64 bit routine
*
* Other routines
* setup_frame32
*/
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
long
sys32_sigsuspend
(
old_sigset_t
mask
,
int
p2
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
;
mask
&=
_BLOCKABLE
;
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
siginitset
(
&
current
->
blocked
,
mask
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal32
(
&
saveset
,
regs
))
/*
* Returning 0 means we return to userspace via
* ret_from_except and thus restore all user
* registers from *regs. This is what we need
* to do when a signal has been delivered.
*/
return
0
;
}
}
long
sys32_sigaction
(
int
sig
,
struct
old_sigaction32
__user
*
act
,
struct
old_sigaction32
__user
*
oact
)
{
struct
k_sigaction
new_ka
,
old_ka
;
int
ret
;
if
(
sig
<
0
)
sig
=
-
sig
;
if
(
act
)
{
compat_old_sigset_t
mask
;
compat_uptr_t
handler
,
restorer
;
if
(
get_user
(
handler
,
&
act
->
sa_handler
)
||
__get_user
(
restorer
,
&
act
->
sa_restorer
)
||
__get_user
(
new_ka
.
sa
.
sa_flags
,
&
act
->
sa_flags
)
||
__get_user
(
mask
,
&
act
->
sa_mask
))
return
-
EFAULT
;
new_ka
.
sa
.
sa_handler
=
compat_ptr
(
handler
);
new_ka
.
sa
.
sa_restorer
=
compat_ptr
(
restorer
);
siginitset
(
&
new_ka
.
sa
.
sa_mask
,
mask
);
}
ret
=
do_sigaction
(
sig
,
act
?
&
new_ka
:
NULL
,
oact
?
&
old_ka
:
NULL
);
if
(
!
ret
&&
oact
)
{
if
(
put_user
((
long
)
old_ka
.
sa
.
sa_handler
,
&
oact
->
sa_handler
)
||
__put_user
((
long
)
old_ka
.
sa
.
sa_restorer
,
&
oact
->
sa_restorer
)
||
__put_user
(
old_ka
.
sa
.
sa_flags
,
&
oact
->
sa_flags
)
||
__put_user
(
old_ka
.
sa
.
sa_mask
.
sig
[
0
],
&
oact
->
sa_mask
))
return
-
EFAULT
;
}
return
ret
;
}
/*
* Start of RT signal support
*
* sigset_t is 64 bits for rt signals
*
* System Calls
* sigaction sys32_rt_sigaction
* sigpending sys32_rt_sigpending
* sigprocmask sys32_rt_sigprocmask
* sigreturn sys32_rt_sigreturn
* sigqueueinfo sys32_rt_sigqueueinfo
* sigsuspend sys32_rt_sigsuspend
*
* Other routines
* setup_rt_frame32
* copy_siginfo_to_user32
* siginfo32to64
*/
long
sys32_rt_sigaction
(
int
sig
,
const
struct
sigaction32
__user
*
act
,
long
sys32_rt_sigaction
(
int
sig
,
const
struct
sigaction32
__user
*
act
,
struct
sigaction32
__user
*
oact
,
size_t
sigsetsize
)
struct
sigaction32
__user
*
oact
,
size_t
sigsetsize
)
{
{
struct
k_sigaction
new_ka
,
old_ka
;
struct
k_sigaction
new_ka
,
old_ka
;
int
ret
;
int
ret
;
compat_sigset_t
set32
;
/* XXX: Don't preclude handling different sized sigset_t's. */
/* XXX: Don't preclude handling different sized sigset_t's. */
if
(
sigsetsize
!=
sizeof
(
compat_sigset_t
))
if
(
sigsetsize
!=
sizeof
(
compat_sigset_t
))
...
@@ -368,9 +555,7 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
...
@@ -368,9 +555,7 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
ret
=
get_user
(
handler
,
&
act
->
sa_handler
);
ret
=
get_user
(
handler
,
&
act
->
sa_handler
);
new_ka
.
sa
.
sa_handler
=
compat_ptr
(
handler
);
new_ka
.
sa
.
sa_handler
=
compat_ptr
(
handler
);
ret
|=
__copy_from_user
(
&
set32
,
&
act
->
sa_mask
,
ret
|=
get_sigset_t
(
&
new_ka
.
sa
.
sa_mask
,
&
act
->
sa_mask
);
sizeof
(
compat_sigset_t
));
sigset_from_compat
(
&
new_ka
.
sa
.
sa_mask
,
&
set32
);
ret
|=
__get_user
(
new_ka
.
sa
.
sa_flags
,
&
act
->
sa_flags
);
ret
|=
__get_user
(
new_ka
.
sa
.
sa_flags
,
&
act
->
sa_flags
);
if
(
ret
)
if
(
ret
)
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -378,10 +563,8 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
...
@@ -378,10 +563,8 @@ long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
ret
=
do_sigaction
(
sig
,
act
?
&
new_ka
:
NULL
,
oact
?
&
old_ka
:
NULL
);
ret
=
do_sigaction
(
sig
,
act
?
&
new_ka
:
NULL
,
oact
?
&
old_ka
:
NULL
);
if
(
!
ret
&&
oact
)
{
if
(
!
ret
&&
oact
)
{
compat_from_sigset
(
&
set32
,
&
old_ka
.
sa
.
sa_mask
);
ret
=
put_user
((
long
)
old_ka
.
sa
.
sa_handler
,
&
oact
->
sa_handler
);
ret
=
put_user
((
long
)
old_ka
.
sa
.
sa_handler
,
&
oact
->
sa_handler
);
ret
|=
__copy_to_user
(
&
oact
->
sa_mask
,
&
set32
,
ret
|=
put_sigset_t
(
&
oact
->
sa_mask
,
&
old_ka
.
sa
.
sa_mask
);
sizeof
(
compat_sigset_t
));
ret
|=
__put_user
(
old_ka
.
sa
.
sa_flags
,
&
oact
->
sa_flags
);
ret
|=
__put_user
(
old_ka
.
sa
.
sa_flags
,
&
oact
->
sa_flags
);
}
}
return
ret
;
return
ret
;
...
@@ -399,14 +582,12 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
...
@@ -399,14 +582,12 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
{
{
sigset_t
s
;
sigset_t
s
;
sigset_t
__user
*
up
;
sigset_t
__user
*
up
;
compat_sigset_t
s32
;
int
ret
;
int
ret
;
mm_segment_t
old_fs
=
get_fs
();
mm_segment_t
old_fs
=
get_fs
();
if
(
set
)
{
if
(
set
)
{
if
(
copy_from_user
(
&
s32
,
set
,
sizeof
(
compat_sigset_t
)
))
if
(
get_sigset_t
(
&
s
,
set
))
return
-
EFAULT
;
return
-
EFAULT
;
sigset_from_compat
(
&
s
,
&
s32
);
}
}
set_fs
(
KERNEL_DS
);
set_fs
(
KERNEL_DS
);
...
@@ -418,8 +599,7 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
...
@@ -418,8 +599,7 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
if
(
oset
)
{
if
(
oset
)
{
compat_from_sigset
(
&
s32
,
&
s
);
if
(
put_sigset_t
(
oset
,
&
s
))
if
(
copy_to_user
(
oset
,
&
s32
,
sizeof
(
compat_sigset_t
)))
return
-
EFAULT
;
return
-
EFAULT
;
}
}
return
0
;
return
0
;
...
@@ -428,7 +608,6 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
...
@@ -428,7 +608,6 @@ long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
long
sys32_rt_sigpending
(
compat_sigset_t
__user
*
set
,
compat_size_t
sigsetsize
)
long
sys32_rt_sigpending
(
compat_sigset_t
__user
*
set
,
compat_size_t
sigsetsize
)
{
{
sigset_t
s
;
sigset_t
s
;
compat_sigset_t
s32
;
int
ret
;
int
ret
;
mm_segment_t
old_fs
=
get_fs
();
mm_segment_t
old_fs
=
get_fs
();
...
@@ -437,8 +616,7 @@ long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
...
@@ -437,8 +616,7 @@ long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
ret
=
sys_rt_sigpending
((
sigset_t
__user
*
)
&
s
,
sigsetsize
);
ret
=
sys_rt_sigpending
((
sigset_t
__user
*
)
&
s
,
sigsetsize
);
set_fs
(
old_fs
);
set_fs
(
old_fs
);
if
(
!
ret
)
{
if
(
!
ret
)
{
compat_from_sigset
(
&
s32
,
&
s
);
if
(
put_sigset_t
(
set
,
&
s
))
if
(
copy_to_user
(
set
,
&
s32
,
sizeof
(
compat_sigset_t
)))
return
-
EFAULT
;
return
-
EFAULT
;
}
}
return
ret
;
return
ret
;
...
@@ -500,6 +678,8 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
...
@@ -500,6 +678,8 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
return
err
;
return
err
;
}
}
#define copy_siginfo_to_user copy_siginfo_to_user32
/*
/*
* Note: it is necessary to treat pid and sig as unsigned ints, with the
* Note: it is necessary to treat pid and sig as unsigned ints, with the
* corresponding cast to a signed int to insure that the proper conversion
* corresponding cast to a signed int to insure that the proper conversion
...
@@ -522,50 +702,6 @@ long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo)
...
@@ -522,50 +702,6 @@ long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo)
set_fs
(
old_fs
);
set_fs
(
old_fs
);
return
ret
;
return
ret
;
}
}
int
sys32_rt_sigsuspend
(
compat_sigset_t
__user
*
unewset
,
size_t
sigsetsize
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
,
newset
;
compat_sigset_t
s32
;
/* XXX: Don't preclude handling different sized sigset_t's. */
if
(
sigsetsize
!=
sizeof
(
sigset_t
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
s32
,
unewset
,
sizeof
(
s32
)))
return
-
EFAULT
;
/*
* Swap the 2 words of the 64-bit sigset_t (they are stored
* in the "wrong" endian in 32-bit user storage).
*/
sigset_from_compat
(
&
newset
,
&
s32
);
sigdelsetmask
(
&
newset
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
current
->
blocked
=
newset
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal32
(
&
saveset
,
regs
))
/*
* Returning 0 means we return to userspace via
* ret_from_except and thus restore all user
* registers from *regs. This is what we need
* to do when a signal has been delivered.
*/
return
0
;
}
}
/*
/*
* Start Alternate signal stack support
* Start Alternate signal stack support
*
*
...
@@ -615,76 +751,95 @@ int sys32_sigaltstack(u32 __new, u32 __old, int r5,
...
@@ -615,76 +751,95 @@ int sys32_sigaltstack(u32 __new, u32 __old, int r5,
return
-
EFAULT
;
return
-
EFAULT
;
return
ret
;
return
ret
;
}
}
#endif
/* CONFIG_PPC64 */
/*
* Restore the user process's signal mask
*/
#ifdef CONFIG_PPC64
extern
void
restore_sigmask
(
sigset_t
*
set
);
#else
/* CONFIG_PPC64 */
static
void
restore_sigmask
(
sigset_t
*
set
)
{
sigdelsetmask
(
set
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
current
->
blocked
=
*
set
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
}
#endif
/*
/*
* Set up a signal frame for a "real-time" signal handler
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
* (one which gets siginfo).
*/
*/
static
int
handle_rt_signal
32
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
static
int
handle_rt_signal
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
struct
pt_regs
*
regs
,
unsigned
long
newsp
)
struct
pt_regs
*
regs
,
unsigned
long
newsp
)
{
{
struct
rt_sigframe
32
__user
*
rt_sf
;
struct
rt_sigframe
__user
*
rt_sf
;
struct
mcontext
32
__user
*
frame
;
struct
mcontext
__user
*
frame
;
unsigned
long
origsp
=
newsp
;
unsigned
long
origsp
=
newsp
;
compat_sigset_t
c_oldset
;
/* Set up Signal Frame */
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
/* Put a Real Time Context onto stack */
newsp
-=
sizeof
(
*
rt_sf
);
newsp
-=
sizeof
(
*
rt_sf
);
rt_sf
=
(
struct
rt_sigframe
32
__user
*
)
newsp
;
rt_sf
=
(
struct
rt_sigframe
__user
*
)
newsp
;
/* create a stack frame for the caller of the handler */
/* create a stack frame for the caller of the handler */
newsp
-=
__SIGNAL_FRAMESIZE
32
+
16
;
newsp
-=
__SIGNAL_FRAMESIZE
+
16
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
goto
badframe
;
compat_from_sigset
(
&
c_oldset
,
oldset
);
/* Put the siginfo & fill in most of the ucontext */
/* Put the siginfo & fill in most of the ucontext */
if
(
copy_siginfo_to_user
32
(
&
rt_sf
->
info
,
info
)
if
(
copy_siginfo_to_user
(
&
rt_sf
->
info
,
info
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_flags
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_flags
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_link
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_link
)
||
__put_user
(
current
->
sas_ss_sp
,
&
rt_sf
->
uc
.
uc_stack
.
ss_sp
)
||
__put_user
(
current
->
sas_ss_sp
,
&
rt_sf
->
uc
.
uc_stack
.
ss_sp
)
||
__put_user
(
sas_ss_flags
(
regs
->
gpr
[
1
]),
||
__put_user
(
sas_ss_flags
(
regs
->
gpr
[
1
]),
&
rt_sf
->
uc
.
uc_stack
.
ss_flags
)
&
rt_sf
->
uc
.
uc_stack
.
ss_flags
)
||
__put_user
(
current
->
sas_ss_size
,
&
rt_sf
->
uc
.
uc_stack
.
ss_size
)
||
__put_user
(
current
->
sas_ss_size
,
&
rt_sf
->
uc
.
uc_stack
.
ss_size
)
||
__put_user
((
u32
)(
u64
)
&
rt_sf
->
uc
.
uc_mcontext
,
&
rt_sf
->
uc
.
uc_regs
)
||
__put_user
(
to_user_ptr
(
&
rt_sf
->
uc
.
uc_mcontext
),
||
__copy_to_user
(
&
rt_sf
->
uc
.
uc_sigmask
,
&
c_oldset
,
sizeof
(
c_oldset
)))
&
rt_sf
->
uc
.
uc_regs
)
||
put_sigset_t
(
&
rt_sf
->
uc
.
uc_sigmask
,
oldset
))
goto
badframe
;
goto
badframe
;
/* Save user registers on the stack */
/* Save user registers on the stack */
frame
=
&
rt_sf
->
uc
.
uc_mcontext
;
frame
=
&
rt_sf
->
uc
.
uc_mcontext
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
u32
__user
*
)
newsp
))
#ifdef CONFIG_PPC64
goto
badframe
;
if
(
vdso32_rt_sigtramp
&&
current
->
thread
.
vdso_base
)
{
if
(
vdso32_rt_sigtramp
&&
current
->
thread
.
vdso_base
)
{
if
(
save_user_regs
(
regs
,
frame
,
0
))
if
(
save_user_regs
(
regs
,
frame
,
0
))
goto
badframe
;
goto
badframe
;
regs
->
link
=
current
->
thread
.
vdso_base
+
vdso32_rt_sigtramp
;
regs
->
link
=
current
->
thread
.
vdso_base
+
vdso32_rt_sigtramp
;
}
else
{
}
else
#endif
{
if
(
save_user_regs
(
regs
,
frame
,
__NR_rt_sigreturn
))
if
(
save_user_regs
(
regs
,
frame
,
__NR_rt_sigreturn
))
goto
badframe
;
goto
badframe
;
regs
->
link
=
(
unsigned
long
)
frame
->
tramp
;
regs
->
link
=
(
unsigned
long
)
frame
->
tramp
;
}
}
regs
->
gpr
[
1
]
=
(
unsigned
long
)
newsp
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
__user
*
)
newsp
))
goto
badframe
;
regs
->
gpr
[
1
]
=
newsp
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
&
rt_sf
->
info
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
&
rt_sf
->
info
;
regs
->
gpr
[
5
]
=
(
unsigned
long
)
&
rt_sf
->
uc
;
regs
->
gpr
[
5
]
=
(
unsigned
long
)
&
rt_sf
->
uc
;
regs
->
gpr
[
6
]
=
(
unsigned
long
)
rt_sf
;
regs
->
gpr
[
6
]
=
(
unsigned
long
)
rt_sf
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
link
=
(
unsigned
long
)
frame
->
tramp
;
regs
->
trap
=
0
;
regs
->
trap
=
0
;
#ifdef CONFIG_PPC64
regs
->
result
=
0
;
regs
->
result
=
0
;
if
(
test_thread_flag
(
TIF_SINGLESTEP
))
if
(
test_thread_flag
(
TIF_SINGLESTEP
))
ptrace_notify
(
SIGTRAP
);
ptrace_notify
(
SIGTRAP
);
#endif
return
1
;
return
1
;
badframe:
badframe:
#if DEBUG_SIG
#if
def
DEBUG_SIG
printk
(
"badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx
\n
"
,
printk
(
"badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx
\n
"
,
regs
,
frame
,
newsp
);
regs
,
frame
,
newsp
);
#endif
#endif
...
@@ -692,46 +847,50 @@ badframe:
...
@@ -692,46 +847,50 @@ badframe:
return
0
;
return
0
;
}
}
static
long
do_setcontext32
(
struct
ucontext32
__user
*
ucp
,
struct
pt_regs
*
regs
,
int
sig
)
static
int
do_setcontext
(
struct
ucontext
__user
*
ucp
,
struct
pt_regs
*
regs
,
int
sig
)
{
{
compat_sigset_t
c_set
;
sigset_t
set
;
sigset_t
set
;
u32
mcp
;
struct
mcontext
__user
*
mcp
;
if
(
__copy_from_user
(
&
c_set
,
&
ucp
->
uc_sigmask
,
sizeof
(
c_set
))
if
(
get_sigset_t
(
&
set
,
&
ucp
->
uc_sigmask
))
||
__get_user
(
mcp
,
&
ucp
->
uc_regs
))
return
-
EFAULT
;
return
-
EFAULT
;
sigset_from_compat
(
&
set
,
&
c_set
);
#ifdef CONFIG_PPC64
{
u32
cmcp
;
if
(
__get_user
(
cmcp
,
&
ucp
->
uc_regs
))
return
-
EFAULT
;
mcp
=
(
struct
mcontext
__user
*
)(
u64
)
cmcp
;
}
#else
if
(
__get_user
(
mcp
,
&
ucp
->
uc_regs
))
return
-
EFAULT
;
#endif
restore_sigmask
(
&
set
);
restore_sigmask
(
&
set
);
if
(
restore_user_regs
(
regs
,
(
struct
mcontext32
__user
*
)(
u64
)
mcp
,
sig
))
if
(
restore_user_regs
(
regs
,
mcp
,
sig
))
return
-
EFAULT
;
return
-
EFAULT
;
return
0
;
return
0
;
}
}
/*
long
sys_swapcontext
(
struct
ucontext
__user
*
old_ctx
,
* Handle {get,set,swap}_context operations for 32 bits processes
struct
ucontext
__user
*
new_ctx
,
*/
long
sys32_swapcontext
(
struct
ucontext32
__user
*
old_ctx
,
struct
ucontext32
__user
*
new_ctx
,
int
ctx_size
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
int
ctx_size
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
{
unsigned
char
tmp
;
unsigned
char
tmp
;
compat_sigset_t
c_set
;
/* Context size is for future use. Right now, we only make sure
/* Context size is for future use. Right now, we only make sure
* we are passed something we understand
* we are passed something we understand
*/
*/
if
(
ctx_size
<
sizeof
(
struct
ucontext
32
))
if
(
ctx_size
<
sizeof
(
struct
ucontext
))
return
-
EINVAL
;
return
-
EINVAL
;
if
(
old_ctx
!=
NULL
)
{
if
(
old_ctx
!=
NULL
)
{
compat_from_sigset
(
&
c_set
,
&
current
->
blocked
);
if
(
!
access_ok
(
VERIFY_WRITE
,
old_ctx
,
sizeof
(
*
old_ctx
))
if
(
!
access_ok
(
VERIFY_WRITE
,
old_ctx
,
sizeof
(
*
old_ctx
))
||
save_user_regs
(
regs
,
&
old_ctx
->
uc_mcontext
,
0
)
||
save_user_regs
(
regs
,
&
old_ctx
->
uc_mcontext
,
0
)
||
__copy_to_user
(
&
old_ctx
->
uc_sigmask
,
&
c_set
,
sizeof
(
c_set
))
||
put_sigset_t
(
&
old_ctx
->
uc_sigmask
,
&
current
->
blocked
)
||
__put_user
((
u32
)(
u64
)
&
old_ctx
->
uc_mcontext
,
&
old_ctx
->
uc_regs
))
||
__put_user
(
to_user_ptr
(
&
old_ctx
->
uc_mcontext
),
&
old_ctx
->
uc_regs
))
return
-
EFAULT
;
return
-
EFAULT
;
}
}
if
(
new_ctx
==
NULL
)
if
(
new_ctx
==
NULL
)
...
@@ -752,27 +911,26 @@ long sys32_swapcontext(struct ucontext32 __user *old_ctx,
...
@@ -752,27 +911,26 @@ long sys32_swapcontext(struct ucontext32 __user *old_ctx,
* or if another thread unmaps the region containing the context.
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
* We kill the task with a SIGSEGV in this situation.
*/
*/
if
(
do_setcontext
32
(
new_ctx
,
regs
,
0
))
if
(
do_setcontext
(
new_ctx
,
regs
,
0
))
do_exit
(
SIGSEGV
);
do_exit
(
SIGSEGV
);
sigreturn_exit
(
regs
);
/* doesn't actually return back to here */
return
0
;
return
0
;
}
}
long
sys
32
_rt_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
long
sys_rt_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
struct
pt_regs
*
regs
)
{
{
struct
rt_sigframe32
__user
*
rt_sf
;
struct
rt_sigframe
__user
*
rt_sf
;
int
ret
;
/* Always make any pending restarted system calls return -EINTR */
/* Always make any pending restarted system calls return -EINTR */
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
rt_sf
=
(
struct
rt_sigframe
32
__user
*
)
rt_sf
=
(
struct
rt_sigframe
__user
*
)
(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
32
+
16
);
(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
+
16
);
if
(
!
access_ok
(
VERIFY_READ
,
rt_sf
,
sizeof
(
*
rt_sf
)))
if
(
!
access_ok
(
VERIFY_READ
,
rt_sf
,
sizeof
(
*
rt_sf
)))
goto
bad
;
goto
bad
;
if
(
do_setcontext
32
(
&
rt_sf
->
uc
,
regs
,
1
))
if
(
do_setcontext
(
&
rt_sf
->
uc
,
regs
,
1
))
goto
bad
;
goto
bad
;
/*
/*
...
@@ -781,62 +939,165 @@ long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
...
@@ -781,62 +939,165 @@ long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
* signal return. But other architectures do this and we have
* signal return. But other architectures do this and we have
* always done it up until now so it is probably better not to
* always done it up until now so it is probably better not to
* change it. -- paulus
* change it. -- paulus
*/
#ifdef CONFIG_PPC64
/*
* We use the sys32_ version that does the 32/64 bits conversion
* We use the sys32_ version that does the 32/64 bits conversion
* and takes userland pointer directly. What about error checking ?
* and takes userland pointer directly. What about error checking ?
* nobody does any...
* nobody does any...
*/
*/
sys32_sigaltstack
((
u32
)(
u64
)
&
rt_sf
->
uc
.
uc_stack
,
0
,
0
,
0
,
0
,
0
,
regs
);
sys32_sigaltstack
((
u32
)(
u64
)
&
rt_sf
->
uc
.
uc_stack
,
0
,
0
,
0
,
0
,
0
,
regs
);
return
(
int
)
regs
->
result
;
ret
=
regs
->
result
;
#else
do_sigaltstack
(
&
rt_sf
->
uc
.
uc_stack
,
NULL
,
regs
->
gpr
[
1
]);
return
ret
;
sigreturn_exit
(
regs
);
/* doesn't return here */
return
0
;
#endif
bad:
bad:
force_sig
(
SIGSEGV
,
current
);
force_sig
(
SIGSEGV
,
current
);
return
0
;
return
0
;
}
}
#ifdef CONFIG_PPC32
int
sys_debug_setcontext
(
struct
ucontext
__user
*
ctx
,
int
ndbg
,
struct
sig_dbg_op
__user
*
dbg
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
struct
sig_dbg_op
op
;
int
i
;
unsigned
long
new_msr
=
regs
->
msr
;
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
unsigned
long
new_dbcr0
=
current
->
thread
.
dbcr0
;
#endif
for
(
i
=
0
;
i
<
ndbg
;
i
++
)
{
if
(
__copy_from_user
(
&
op
,
dbg
,
sizeof
(
op
)))
return
-
EFAULT
;
switch
(
op
.
dbg_type
)
{
case
SIG_DBG_SINGLE_STEPPING
:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
if
(
op
.
dbg_value
)
{
new_msr
|=
MSR_DE
;
new_dbcr0
|=
(
DBCR0_IDM
|
DBCR0_IC
);
}
else
{
new_msr
&=
~
MSR_DE
;
new_dbcr0
&=
~
(
DBCR0_IDM
|
DBCR0_IC
);
}
#else
if
(
op
.
dbg_value
)
new_msr
|=
MSR_SE
;
else
new_msr
&=
~
MSR_SE
;
#endif
break
;
case
SIG_DBG_BRANCH_TRACING
:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
return
-
EINVAL
;
#else
if
(
op
.
dbg_value
)
new_msr
|=
MSR_BE
;
else
new_msr
&=
~
MSR_BE
;
#endif
break
;
default:
return
-
EINVAL
;
}
}
/* We wait until here to actually install the values in the
registers so if we fail in the above loop, it will not
affect the contents of these registers. After this point,
failure is a problem, anyway, and it's very unlikely unless
the user is really doing something wrong. */
regs
->
msr
=
new_msr
;
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
current
->
thread
.
dbcr0
=
new_dbcr0
;
#endif
/*
* If we get a fault copying the context into the kernel's
* image of the user's registers, we can't just return -EFAULT
* because the user's registers will be corrupted. For instance
* the NIP value may have been updated but not some of the
* other registers. Given that we have done the access_ok
* and successfully read the first and last bytes of the region
* above, this should only happen in an out-of-memory situation
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
*/
if
(
do_setcontext
(
ctx
,
regs
,
1
))
{
force_sig
(
SIGSEGV
,
current
);
goto
out
;
}
/*
* It's not clear whether or why it is desirable to save the
* sigaltstack setting on signal delivery and restore it on
* signal return. But other architectures do this and we have
* always done it up until now so it is probably better not to
* change it. -- paulus
*/
do_sigaltstack
(
&
ctx
->
uc_stack
,
NULL
,
regs
->
gpr
[
1
]);
sigreturn_exit
(
regs
);
/* doesn't actually return back to here */
out:
return
0
;
}
#endif
/*
/*
* OK, we're invoking a handler
* OK, we're invoking a handler
*/
*/
static
int
handle_signal
32
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
static
int
handle_signal
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
struct
pt_regs
*
regs
,
struct
pt_regs
*
regs
,
unsigned
long
newsp
)
unsigned
long
newsp
)
{
{
struct
sigcontext
32
__user
*
sc
;
struct
sigcontext
__user
*
sc
;
struct
sigregs
32
__user
*
frame
;
struct
sigregs
__user
*
frame
;
unsigned
long
origsp
=
newsp
;
unsigned
long
origsp
=
newsp
;
/* Set up Signal Frame */
/* Set up Signal Frame */
newsp
-=
sizeof
(
struct
sigregs
32
);
newsp
-=
sizeof
(
struct
sigregs
);
frame
=
(
struct
sigregs
32
__user
*
)
newsp
;
frame
=
(
struct
sigregs
__user
*
)
newsp
;
/* Put a sigcontext on the stack */
/* Put a sigcontext on the stack */
newsp
-=
sizeof
(
*
sc
);
newsp
-=
sizeof
(
*
sc
);
sc
=
(
struct
sigcontext
32
__user
*
)
newsp
;
sc
=
(
struct
sigcontext
__user
*
)
newsp
;
/* create a stack frame for the caller of the handler */
/* create a stack frame for the caller of the handler */
newsp
-=
__SIGNAL_FRAMESIZE
32
;
newsp
-=
__SIGNAL_FRAMESIZE
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
goto
badframe
;
#if _NSIG != 64
#if _NSIG != 64
#error "Please adjust handle_signal
32
()"
#error "Please adjust handle_signal()"
#endif
#endif
if
(
__put_user
(
(
u32
)(
u64
)
ka
->
sa
.
sa_handler
,
&
sc
->
handler
)
if
(
__put_user
(
to_user_ptr
(
ka
->
sa
.
sa_handler
)
,
&
sc
->
handler
)
||
__put_user
(
oldset
->
sig
[
0
],
&
sc
->
oldmask
)
||
__put_user
(
oldset
->
sig
[
0
],
&
sc
->
oldmask
)
#ifdef CONFIG_PPC64
||
__put_user
((
oldset
->
sig
[
0
]
>>
32
),
&
sc
->
_unused
[
3
])
||
__put_user
((
oldset
->
sig
[
0
]
>>
32
),
&
sc
->
_unused
[
3
])
||
__put_user
((
u32
)(
u64
)
frame
,
&
sc
->
regs
)
#else
||
__put_user
(
oldset
->
sig
[
1
],
&
sc
->
_unused
[
3
])
#endif
||
__put_user
(
to_user_ptr
(
frame
),
&
sc
->
regs
)
||
__put_user
(
sig
,
&
sc
->
signal
))
||
__put_user
(
sig
,
&
sc
->
signal
))
goto
badframe
;
goto
badframe
;
#ifdef CONFIG_PPC64
if
(
vdso32_sigtramp
&&
current
->
thread
.
vdso_base
)
{
if
(
vdso32_sigtramp
&&
current
->
thread
.
vdso_base
)
{
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
0
))
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
0
))
goto
badframe
;
goto
badframe
;
regs
->
link
=
current
->
thread
.
vdso_base
+
vdso32_sigtramp
;
regs
->
link
=
current
->
thread
.
vdso_base
+
vdso32_sigtramp
;
}
else
{
}
else
#endif
{
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
__NR_sigreturn
))
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
__NR_sigreturn
))
goto
badframe
;
goto
badframe
;
regs
->
link
=
(
unsigned
long
)
frame
->
mctx
.
tramp
;
regs
->
link
=
(
unsigned
long
)
frame
->
mctx
.
tramp
;
...
@@ -844,22 +1105,24 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka,
...
@@ -844,22 +1105,24 @@ static int handle_signal32(unsigned long sig, struct k_sigaction *ka,
if
(
put_user
(
regs
->
gpr
[
1
],
(
u32
__user
*
)
newsp
))
if
(
put_user
(
regs
->
gpr
[
1
],
(
u32
__user
*
)
newsp
))
goto
badframe
;
goto
badframe
;
regs
->
gpr
[
1
]
=
(
unsigned
long
)
newsp
;
regs
->
gpr
[
1
]
=
newsp
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
sc
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
sc
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
trap
=
0
;
regs
->
trap
=
0
;
#ifdef CONFIG_PPC64
regs
->
result
=
0
;
regs
->
result
=
0
;
if
(
test_thread_flag
(
TIF_SINGLESTEP
))
if
(
test_thread_flag
(
TIF_SINGLESTEP
))
ptrace_notify
(
SIGTRAP
);
ptrace_notify
(
SIGTRAP
);
#endif
return
1
;
return
1
;
badframe:
badframe:
#if DEBUG_SIG
#if
def
DEBUG_SIG
printk
(
"badframe in handle_signal, regs=%p frame=%
x newsp=%
x
\n
"
,
printk
(
"badframe in handle_signal, regs=%p frame=%
p newsp=%l
x
\n
"
,
regs
,
frame
,
*
newsp
p
);
regs
,
frame
,
news
p
);
#endif
#endif
force_sigsegv
(
sig
,
current
);
force_sigsegv
(
sig
,
current
);
return
0
;
return
0
;
...
@@ -868,65 +1131,69 @@ badframe:
...
@@ -868,65 +1131,69 @@ badframe:
/*
/*
* Do a signal return; undo the signal stack.
* Do a signal return; undo the signal stack.
*/
*/
long
sys
32
_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
long
sys_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
struct
pt_regs
*
regs
)
{
{
struct
sigcontext
32
__user
*
sc
;
struct
sigcontext
__user
*
sc
;
struct
sigcontext
32
sigctx
;
struct
sigcontext
sigctx
;
struct
mcontext
32
__user
*
sr
;
struct
mcontext
__user
*
sr
;
sigset_t
set
;
sigset_t
set
;
int
ret
;
/* Always make any pending restarted system calls return -EINTR */
/* Always make any pending restarted system calls return -EINTR */
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
sc
=
(
struct
sigcontext
32
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE32
);
sc
=
(
struct
sigcontext
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
);
if
(
copy_from_user
(
&
sigctx
,
sc
,
sizeof
(
sigctx
)))
if
(
copy_from_user
(
&
sigctx
,
sc
,
sizeof
(
sigctx
)))
goto
badframe
;
goto
badframe
;
#ifdef CONFIG_PPC64
/*
/*
* Note that PPC32 puts the upper 32 bits of the sigmask in the
* Note that PPC32 puts the upper 32 bits of the sigmask in the
* unused part of the signal stackframe
* unused part of the signal stackframe
*/
*/
set
.
sig
[
0
]
=
sigctx
.
oldmask
+
((
long
)(
sigctx
.
_unused
[
3
])
<<
32
);
set
.
sig
[
0
]
=
sigctx
.
oldmask
+
((
long
)(
sigctx
.
_unused
[
3
])
<<
32
);
#else
set
.
sig
[
0
]
=
sigctx
.
oldmask
;
set
.
sig
[
1
]
=
sigctx
.
_unused
[
3
];
#endif
restore_sigmask
(
&
set
);
restore_sigmask
(
&
set
);
sr
=
(
struct
mcontext
32
__user
*
)(
u64
)
sigctx
.
regs
;
sr
=
(
struct
mcontext
__user
*
)
from_user_ptr
(
sigctx
.
regs
)
;
if
(
!
access_ok
(
VERIFY_READ
,
sr
,
sizeof
(
*
sr
))
if
(
!
access_ok
(
VERIFY_READ
,
sr
,
sizeof
(
*
sr
))
||
restore_user_regs
(
regs
,
sr
,
1
))
||
restore_user_regs
(
regs
,
sr
,
1
))
goto
badframe
;
goto
badframe
;
ret
=
regs
->
result
;
#ifdef CONFIG_PPC64
return
ret
;
return
(
int
)
regs
->
result
;
#else
sigreturn_exit
(
regs
);
/* doesn't return */
return
0
;
#endif
badframe:
badframe:
force_sig
(
SIGSEGV
,
current
);
force_sig
(
SIGSEGV
,
current
);
return
0
;
return
0
;
}
}
/*
* Start of do_signal32 routine
*
* This routine gets control when a pending signal needs to be processed
* in the 32 bit target thread -
*
* It handles both rt and non-rt signals
*/
/*
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
* mistake.
*/
*/
int
do_signal
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
)
int
do_signal32
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
)
{
{
siginfo_t
info
;
siginfo_t
info
;
struct
k_sigaction
ka
;
unsigned
int
frame
,
newsp
;
unsigned
int
frame
,
newsp
;
int
signr
,
ret
;
int
signr
,
ret
;
struct
k_sigaction
ka
;
#ifdef CONFIG_PPC32
if
(
try_to_freeze
())
{
signr
=
0
;
if
(
!
signal_pending
(
current
))
goto
no_signal
;
}
#endif
if
(
!
oldset
)
if
(
!
oldset
)
oldset
=
&
current
->
blocked
;
oldset
=
&
current
->
blocked
;
...
@@ -934,7 +1201,9 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
...
@@ -934,7 +1201,9 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
newsp
=
frame
=
0
;
newsp
=
frame
=
0
;
signr
=
get_signal_to_deliver
(
&
info
,
&
ka
,
regs
,
NULL
);
signr
=
get_signal_to_deliver
(
&
info
,
&
ka
,
regs
,
NULL
);
#ifdef CONFIG_PPC32
no_signal:
#endif
if
(
TRAP
(
regs
)
==
0x0C00
/* System Call! */
if
(
TRAP
(
regs
)
==
0x0C00
/* System Call! */
&&
regs
->
ccr
&
0x10000000
/* error signalled */
&&
regs
->
ccr
&
0x10000000
/* error signalled */
&&
((
ret
=
regs
->
gpr
[
3
])
==
ERESTARTSYS
&&
((
ret
=
regs
->
gpr
[
3
])
==
ERESTARTSYS
...
@@ -964,12 +1233,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
...
@@ -964,12 +1233,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
return
0
;
/* no signals delivered */
return
0
;
/* no signals delivered */
if
((
ka
.
sa
.
sa_flags
&
SA_ONSTACK
)
&&
current
->
sas_ss_size
if
((
ka
.
sa
.
sa_flags
&
SA_ONSTACK
)
&&
current
->
sas_ss_size
&&
(
!
on_sig_stack
(
regs
->
gpr
[
1
])
))
&&
!
on_sig_stack
(
regs
->
gpr
[
1
]
))
newsp
=
(
current
->
sas_ss_sp
+
current
->
sas_ss_size
)
;
newsp
=
current
->
sas_ss_sp
+
current
->
sas_ss_size
;
else
else
newsp
=
regs
->
gpr
[
1
];
newsp
=
regs
->
gpr
[
1
];
newsp
&=
~
0xfUL
;
newsp
&=
~
0xfUL
;
#ifdef CONFIG_PPC64
/*
/*
* Reenable the DABR before delivering the signal to
* Reenable the DABR before delivering the signal to
* user space. The DABR will have been cleared if it
* user space. The DABR will have been cleared if it
...
@@ -977,12 +1247,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
...
@@ -977,12 +1247,13 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
*/
*/
if
(
current
->
thread
.
dabr
)
if
(
current
->
thread
.
dabr
)
set_dabr
(
current
->
thread
.
dabr
);
set_dabr
(
current
->
thread
.
dabr
);
#endif
/* Whee! Actually deliver the signal. */
/* Whee! Actually deliver the signal. */
if
(
ka
.
sa
.
sa_flags
&
SA_SIGINFO
)
if
(
ka
.
sa
.
sa_flags
&
SA_SIGINFO
)
ret
=
handle_rt_signal
32
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
ret
=
handle_rt_signal
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
else
else
ret
=
handle_signal
32
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
ret
=
handle_signal
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
if
(
ret
)
{
if
(
ret
)
{
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
...
...
arch/ppc/kernel/Makefile
View file @
81e7009e
...
@@ -13,7 +13,7 @@ extra-$(CONFIG_POWER4) += idle_power4.o
...
@@ -13,7 +13,7 @@ extra-$(CONFIG_POWER4) += idle_power4.o
extra-y
+=
vmlinux.lds
extra-y
+=
vmlinux.lds
obj-y
:=
entry.o traps.o irq.o idle.o time.o misc.o
\
obj-y
:=
entry.o traps.o irq.o idle.o time.o misc.o
\
process.o
signal.o
align.o
\
process.o align.o
\
syscalls.o setup.o
\
syscalls.o setup.o
\
ppc_htab.o perfmon.o
ppc_htab.o perfmon.o
obj-$(CONFIG_6xx)
+=
l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_6xx)
+=
l2cr.o cpu_setup_6xx.o
...
@@ -38,7 +38,7 @@ endif
...
@@ -38,7 +38,7 @@ endif
else
else
obj-y
:=
irq.o idle.o time.o
\
obj-y
:=
irq.o idle.o time.o
\
signal.o
align.o perfmon.o
align.o perfmon.o
obj-$(CONFIG_6xx)
+=
l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_6xx)
+=
l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_SOFTWARE_SUSPEND)
+=
swsusp.o
obj-$(CONFIG_SOFTWARE_SUSPEND)
+=
swsusp.o
obj-$(CONFIG_MODULES)
+=
module.o
obj-$(CONFIG_MODULES)
+=
module.o
...
...
arch/ppc/kernel/signal.c
deleted
100644 → 0
View file @
55d36339
/*
* arch/ppc/kernel/signal.c
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Derived from "arch/i386/kernel/signal.c"
* Copyright (C) 1991, 1992 Linus Torvalds
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/elf.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/suspend.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
#undef DEBUG_SIG
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern
void
sigreturn_exit
(
struct
pt_regs
*
);
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
int
do_signal
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
);
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
int
sys_sigsuspend
(
old_sigset_t
mask
,
int
p2
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
;
mask
&=
_BLOCKABLE
;
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
siginitset
(
&
current
->
blocked
,
mask
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal
(
&
saveset
,
regs
))
sigreturn_exit
(
regs
);
}
}
int
sys_rt_sigsuspend
(
sigset_t
__user
*
unewset
,
size_t
sigsetsize
,
int
p3
,
int
p4
,
int
p6
,
int
p7
,
struct
pt_regs
*
regs
)
{
sigset_t
saveset
,
newset
;
/* XXX: Don't preclude handling different sized sigset_t's. */
if
(
sigsetsize
!=
sizeof
(
sigset_t
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
newset
,
unewset
,
sizeof
(
newset
)))
return
-
EFAULT
;
sigdelsetmask
(
&
newset
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
saveset
=
current
->
blocked
;
current
->
blocked
=
newset
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
if
(
do_signal
(
&
saveset
,
regs
))
sigreturn_exit
(
regs
);
}
}
int
sys_sigaltstack
(
const
stack_t
__user
*
uss
,
stack_t
__user
*
uoss
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
return
do_sigaltstack
(
uss
,
uoss
,
regs
->
gpr
[
1
]);
}
int
sys_sigaction
(
int
sig
,
const
struct
old_sigaction
__user
*
act
,
struct
old_sigaction
__user
*
oact
)
{
struct
k_sigaction
new_ka
,
old_ka
;
int
ret
;
if
(
act
)
{
old_sigset_t
mask
;
if
(
!
access_ok
(
VERIFY_READ
,
act
,
sizeof
(
*
act
))
||
__get_user
(
new_ka
.
sa
.
sa_handler
,
&
act
->
sa_handler
)
||
__get_user
(
new_ka
.
sa
.
sa_restorer
,
&
act
->
sa_restorer
))
return
-
EFAULT
;
__get_user
(
new_ka
.
sa
.
sa_flags
,
&
act
->
sa_flags
);
__get_user
(
mask
,
&
act
->
sa_mask
);
siginitset
(
&
new_ka
.
sa
.
sa_mask
,
mask
);
}
ret
=
do_sigaction
(
sig
,
(
act
?
&
new_ka
:
NULL
),
(
oact
?
&
old_ka
:
NULL
));
if
(
!
ret
&&
oact
)
{
if
(
!
access_ok
(
VERIFY_WRITE
,
oact
,
sizeof
(
*
oact
))
||
__put_user
(
old_ka
.
sa
.
sa_handler
,
&
oact
->
sa_handler
)
||
__put_user
(
old_ka
.
sa
.
sa_restorer
,
&
oact
->
sa_restorer
))
return
-
EFAULT
;
__put_user
(
old_ka
.
sa
.
sa_flags
,
&
oact
->
sa_flags
);
__put_user
(
old_ka
.
sa
.
sa_mask
.
sig
[
0
],
&
oact
->
sa_mask
);
}
return
ret
;
}
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* a sigregs struct
* a sigcontext struct
* a gap of __SIGNAL_FRAMESIZE bytes
*
* Each of these things must be a multiple of 16 bytes in size.
*
*/
struct
sigregs
{
struct
mcontext
mctx
;
/* all the register values */
/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
and 18 fp regs below sp before decrementing it. */
int
abigap
[
56
];
};
/* We use the mc_pad field for the signal return trampoline. */
#define tramp mc_pad
/*
* When we have rt signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* one rt_sigframe struct (siginfo + ucontext + ABI gap)
* a gap of __SIGNAL_FRAMESIZE+16 bytes
* (the +16 is to get the siginfo and ucontext in the same
* positions as in older kernels).
*
* Each of these things must be a multiple of 16 bytes in size.
*
*/
struct
rt_sigframe
{
struct
siginfo
info
;
struct
ucontext
uc
;
/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
and 18 fp regs below sp before decrementing it. */
int
abigap
[
56
];
};
/*
* Save the current user registers on the user stack.
* We only save the altivec/spe registers if the process has used
* altivec/spe instructions at some point.
*/
static
int
save_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
frame
,
int
sigret
)
{
/* save general and floating-point registers */
CHECK_FULL_REGS
(
regs
);
preempt_disable
();
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
#ifdef CONFIG_ALTIVEC
if
(
current
->
thread
.
used_vr
&&
(
regs
->
msr
&
MSR_VEC
))
giveup_altivec
(
current
);
#endif
/* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
if
(
current
->
thread
.
used_spe
&&
(
regs
->
msr
&
MSR_SPE
))
giveup_spe
(
current
);
#endif
/* CONFIG_ALTIVEC */
preempt_enable
();
if
(
__copy_to_user
(
&
frame
->
mc_gregs
,
regs
,
GP_REGS_SIZE
)
||
__copy_to_user
(
&
frame
->
mc_fregs
,
current
->
thread
.
fpr
,
ELF_NFPREG
*
sizeof
(
double
)))
return
1
;
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
#ifdef CONFIG_ALTIVEC
/* save altivec registers */
if
(
current
->
thread
.
used_vr
)
{
if
(
__copy_to_user
(
&
frame
->
mc_vregs
,
current
->
thread
.
vr
,
ELF_NVRREG
*
sizeof
(
vector128
)))
return
1
;
/* set MSR_VEC in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
if
(
__put_user
(
regs
->
msr
|
MSR_VEC
,
&
frame
->
mc_gregs
[
PT_MSR
]))
return
1
;
}
/* else assert((regs->msr & MSR_VEC) == 0) */
/* We always copy to/from vrsave, it's 0 if we don't have or don't
* use altivec. Since VSCR only contains 32 bits saved in the least
* significant bits of a vector, we "cheat" and stuff VRSAVE in the
* most significant bits of that same vector. --BenH
*/
if
(
__put_user
(
current
->
thread
.
vrsave
,
(
u32
__user
*
)
&
frame
->
mc_vregs
[
32
]))
return
1
;
#endif
/* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
/* save spe registers */
if
(
current
->
thread
.
used_spe
)
{
if
(
__copy_to_user
(
&
frame
->
mc_vregs
,
current
->
thread
.
evr
,
ELF_NEVRREG
*
sizeof
(
u32
)))
return
1
;
/* set MSR_SPE in the saved MSR value to indicate that
frame->mc_vregs contains valid data */
if
(
__put_user
(
regs
->
msr
|
MSR_SPE
,
&
frame
->
mc_gregs
[
PT_MSR
]))
return
1
;
}
/* else assert((regs->msr & MSR_SPE) == 0) */
/* We always copy to/from spefscr */
if
(
__put_user
(
current
->
thread
.
spefscr
,
(
u32
*
)
&
frame
->
mc_vregs
+
ELF_NEVRREG
))
return
1
;
#endif
/* CONFIG_SPE */
if
(
sigret
)
{
/* Set up the sigreturn trampoline: li r0,sigret; sc */
if
(
__put_user
(
0x38000000UL
+
sigret
,
&
frame
->
tramp
[
0
])
||
__put_user
(
0x44000002UL
,
&
frame
->
tramp
[
1
]))
return
1
;
flush_icache_range
((
unsigned
long
)
&
frame
->
tramp
[
0
],
(
unsigned
long
)
&
frame
->
tramp
[
2
]);
}
return
0
;
}
/*
* Restore the current user register values from the user stack,
* (except for MSR).
*/
static
int
restore_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
__user
*
sr
,
int
sig
)
{
unsigned
long
save_r2
=
0
;
#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
unsigned
long
msr
;
#endif
/* backup/restore the TLS as we don't want it to be modified */
if
(
!
sig
)
save_r2
=
regs
->
gpr
[
2
];
/* copy up to but not including MSR */
if
(
__copy_from_user
(
regs
,
&
sr
->
mc_gregs
,
PT_MSR
*
sizeof
(
elf_greg_t
)))
return
1
;
/* copy from orig_r3 (the word after the MSR) up to the end */
if
(
__copy_from_user
(
&
regs
->
orig_gpr3
,
&
sr
->
mc_gregs
[
PT_ORIG_R3
],
GP_REGS_SIZE
-
PT_ORIG_R3
*
sizeof
(
elf_greg_t
)))
return
1
;
if
(
!
sig
)
regs
->
gpr
[
2
]
=
save_r2
;
/* force the process to reload the FP registers from
current->thread when it next does FP instructions */
regs
->
msr
&=
~
(
MSR_FP
|
MSR_FE0
|
MSR_FE1
);
if
(
__copy_from_user
(
current
->
thread
.
fpr
,
&
sr
->
mc_fregs
,
sizeof
(
sr
->
mc_fregs
)))
return
1
;
#ifdef CONFIG_ALTIVEC
/* force the process to reload the altivec registers from
current->thread when it next does altivec instructions */
regs
->
msr
&=
~
MSR_VEC
;
if
(
!
__get_user
(
msr
,
&
sr
->
mc_gregs
[
PT_MSR
])
&&
(
msr
&
MSR_VEC
)
!=
0
)
{
/* restore altivec registers from the stack */
if
(
__copy_from_user
(
current
->
thread
.
vr
,
&
sr
->
mc_vregs
,
sizeof
(
sr
->
mc_vregs
)))
return
1
;
}
else
if
(
current
->
thread
.
used_vr
)
memset
(
&
current
->
thread
.
vr
,
0
,
ELF_NVRREG
*
sizeof
(
vector128
));
/* Always get VRSAVE back */
if
(
__get_user
(
current
->
thread
.
vrsave
,
(
u32
__user
*
)
&
sr
->
mc_vregs
[
32
]))
return
1
;
#endif
/* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
/* force the process to reload the spe registers from
current->thread when it next does spe instructions */
regs
->
msr
&=
~
MSR_SPE
;
if
(
!
__get_user
(
msr
,
&
sr
->
mc_gregs
[
PT_MSR
])
&&
(
msr
&
MSR_SPE
)
!=
0
)
{
/* restore spe registers from the stack */
if
(
__copy_from_user
(
current
->
thread
.
evr
,
&
sr
->
mc_vregs
,
ELF_NEVRREG
*
sizeof
(
u32
)))
return
1
;
}
else
if
(
current
->
thread
.
used_spe
)
memset
(
&
current
->
thread
.
evr
,
0
,
ELF_NEVRREG
*
sizeof
(
u32
));
/* Always get SPEFSCR back */
if
(
__get_user
(
current
->
thread
.
spefscr
,
(
u32
*
)
&
sr
->
mc_vregs
+
ELF_NEVRREG
))
return
1
;
#endif
/* CONFIG_SPE */
#ifndef CONFIG_SMP
preempt_disable
();
if
(
last_task_used_math
==
current
)
last_task_used_math
=
NULL
;
if
(
last_task_used_altivec
==
current
)
last_task_used_altivec
=
NULL
;
if
(
last_task_used_spe
==
current
)
last_task_used_spe
=
NULL
;
preempt_enable
();
#endif
return
0
;
}
/*
* Restore the user process's signal mask
*/
static
void
restore_sigmask
(
sigset_t
*
set
)
{
sigdelsetmask
(
set
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
current
->
blocked
=
*
set
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
}
/*
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
*/
static
void
handle_rt_signal
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
struct
pt_regs
*
regs
,
unsigned
long
newsp
)
{
struct
rt_sigframe
__user
*
rt_sf
;
struct
mcontext
__user
*
frame
;
unsigned
long
origsp
=
newsp
;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
newsp
-=
sizeof
(
*
rt_sf
);
rt_sf
=
(
struct
rt_sigframe
__user
*
)
newsp
;
/* create a stack frame for the caller of the handler */
newsp
-=
__SIGNAL_FRAMESIZE
+
16
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
/* Put the siginfo & fill in most of the ucontext */
if
(
copy_siginfo_to_user
(
&
rt_sf
->
info
,
info
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_flags
)
||
__put_user
(
0
,
&
rt_sf
->
uc
.
uc_link
)
||
__put_user
(
current
->
sas_ss_sp
,
&
rt_sf
->
uc
.
uc_stack
.
ss_sp
)
||
__put_user
(
sas_ss_flags
(
regs
->
gpr
[
1
]),
&
rt_sf
->
uc
.
uc_stack
.
ss_flags
)
||
__put_user
(
current
->
sas_ss_size
,
&
rt_sf
->
uc
.
uc_stack
.
ss_size
)
||
__put_user
(
&
rt_sf
->
uc
.
uc_mcontext
,
&
rt_sf
->
uc
.
uc_regs
)
||
__copy_to_user
(
&
rt_sf
->
uc
.
uc_sigmask
,
oldset
,
sizeof
(
*
oldset
)))
goto
badframe
;
/* Save user registers on the stack */
frame
=
&
rt_sf
->
uc
.
uc_mcontext
;
if
(
save_user_regs
(
regs
,
frame
,
__NR_rt_sigreturn
))
goto
badframe
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
__user
*
)
newsp
))
goto
badframe
;
regs
->
gpr
[
1
]
=
newsp
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
&
rt_sf
->
info
;
regs
->
gpr
[
5
]
=
(
unsigned
long
)
&
rt_sf
->
uc
;
regs
->
gpr
[
6
]
=
(
unsigned
long
)
rt_sf
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
link
=
(
unsigned
long
)
frame
->
tramp
;
regs
->
trap
=
0
;
return
;
badframe:
#ifdef DEBUG_SIG
printk
(
"badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx
\n
"
,
regs
,
frame
,
newsp
);
#endif
force_sigsegv
(
sig
,
current
);
}
static
int
do_setcontext
(
struct
ucontext
__user
*
ucp
,
struct
pt_regs
*
regs
,
int
sig
)
{
sigset_t
set
;
struct
mcontext
__user
*
mcp
;
if
(
__copy_from_user
(
&
set
,
&
ucp
->
uc_sigmask
,
sizeof
(
set
))
||
__get_user
(
mcp
,
&
ucp
->
uc_regs
))
return
-
EFAULT
;
restore_sigmask
(
&
set
);
if
(
restore_user_regs
(
regs
,
mcp
,
sig
))
return
-
EFAULT
;
return
0
;
}
int
sys_swapcontext
(
struct
ucontext
__user
*
old_ctx
,
struct
ucontext
__user
*
new_ctx
,
int
ctx_size
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
unsigned
char
tmp
;
/* Context size is for future use. Right now, we only make sure
* we are passed something we understand
*/
if
(
ctx_size
<
sizeof
(
struct
ucontext
))
return
-
EINVAL
;
if
(
old_ctx
!=
NULL
)
{
if
(
!
access_ok
(
VERIFY_WRITE
,
old_ctx
,
sizeof
(
*
old_ctx
))
||
save_user_regs
(
regs
,
&
old_ctx
->
uc_mcontext
,
0
)
||
__copy_to_user
(
&
old_ctx
->
uc_sigmask
,
&
current
->
blocked
,
sizeof
(
sigset_t
))
||
__put_user
(
&
old_ctx
->
uc_mcontext
,
&
old_ctx
->
uc_regs
))
return
-
EFAULT
;
}
if
(
new_ctx
==
NULL
)
return
0
;
if
(
!
access_ok
(
VERIFY_READ
,
new_ctx
,
sizeof
(
*
new_ctx
))
||
__get_user
(
tmp
,
(
u8
__user
*
)
new_ctx
)
||
__get_user
(
tmp
,
(
u8
__user
*
)
(
new_ctx
+
1
)
-
1
))
return
-
EFAULT
;
/*
* If we get a fault copying the context into the kernel's
* image of the user's registers, we can't just return -EFAULT
* because the user's registers will be corrupted. For instance
* the NIP value may have been updated but not some of the
* other registers. Given that we have done the access_ok
* and successfully read the first and last bytes of the region
* above, this should only happen in an out-of-memory situation
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
*/
if
(
do_setcontext
(
new_ctx
,
regs
,
0
))
do_exit
(
SIGSEGV
);
sigreturn_exit
(
regs
);
/* doesn't actually return back to here */
return
0
;
}
int
sys_rt_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
struct
rt_sigframe
__user
*
rt_sf
;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
rt_sf
=
(
struct
rt_sigframe
__user
*
)
(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
+
16
);
if
(
!
access_ok
(
VERIFY_READ
,
rt_sf
,
sizeof
(
struct
rt_sigframe
)))
goto
bad
;
if
(
do_setcontext
(
&
rt_sf
->
uc
,
regs
,
1
))
goto
bad
;
/*
* It's not clear whether or why it is desirable to save the
* sigaltstack setting on signal delivery and restore it on
* signal return. But other architectures do this and we have
* always done it up until now so it is probably better not to
* change it. -- paulus
*/
do_sigaltstack
(
&
rt_sf
->
uc
.
uc_stack
,
NULL
,
regs
->
gpr
[
1
]);
sigreturn_exit
(
regs
);
/* doesn't return here */
return
0
;
bad:
force_sig
(
SIGSEGV
,
current
);
return
0
;
}
int
sys_debug_setcontext
(
struct
ucontext
__user
*
ctx
,
int
ndbg
,
struct
sig_dbg_op
__user
*
dbg
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
struct
sig_dbg_op
op
;
int
i
;
unsigned
long
new_msr
=
regs
->
msr
;
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
unsigned
long
new_dbcr0
=
current
->
thread
.
dbcr0
;
#endif
for
(
i
=
0
;
i
<
ndbg
;
i
++
)
{
if
(
__copy_from_user
(
&
op
,
dbg
,
sizeof
(
op
)))
return
-
EFAULT
;
switch
(
op
.
dbg_type
)
{
case
SIG_DBG_SINGLE_STEPPING
:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
if
(
op
.
dbg_value
)
{
new_msr
|=
MSR_DE
;
new_dbcr0
|=
(
DBCR0_IDM
|
DBCR0_IC
);
}
else
{
new_msr
&=
~
MSR_DE
;
new_dbcr0
&=
~
(
DBCR0_IDM
|
DBCR0_IC
);
}
#else
if
(
op
.
dbg_value
)
new_msr
|=
MSR_SE
;
else
new_msr
&=
~
MSR_SE
;
#endif
break
;
case
SIG_DBG_BRANCH_TRACING
:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
return
-
EINVAL
;
#else
if
(
op
.
dbg_value
)
new_msr
|=
MSR_BE
;
else
new_msr
&=
~
MSR_BE
;
#endif
break
;
default:
return
-
EINVAL
;
}
}
/* We wait until here to actually install the values in the
registers so if we fail in the above loop, it will not
affect the contents of these registers. After this point,
failure is a problem, anyway, and it's very unlikely unless
the user is really doing something wrong. */
regs
->
msr
=
new_msr
;
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
current
->
thread
.
dbcr0
=
new_dbcr0
;
#endif
/*
* If we get a fault copying the context into the kernel's
* image of the user's registers, we can't just return -EFAULT
* because the user's registers will be corrupted. For instance
* the NIP value may have been updated but not some of the
* other registers. Given that we have done the access_ok
* and successfully read the first and last bytes of the region
* above, this should only happen in an out-of-memory situation
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
*/
if
(
do_setcontext
(
ctx
,
regs
,
1
))
{
force_sig
(
SIGSEGV
,
current
);
goto
out
;
}
/*
* It's not clear whether or why it is desirable to save the
* sigaltstack setting on signal delivery and restore it on
* signal return. But other architectures do this and we have
* always done it up until now so it is probably better not to
* change it. -- paulus
*/
do_sigaltstack
(
&
ctx
->
uc_stack
,
NULL
,
regs
->
gpr
[
1
]);
sigreturn_exit
(
regs
);
/* doesn't actually return back to here */
out:
return
0
;
}
/*
* OK, we're invoking a handler
*/
static
void
handle_signal
(
unsigned
long
sig
,
struct
k_sigaction
*
ka
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
struct
pt_regs
*
regs
,
unsigned
long
newsp
)
{
struct
sigcontext
__user
*
sc
;
struct
sigregs
__user
*
frame
;
unsigned
long
origsp
=
newsp
;
/* Set up Signal Frame */
newsp
-=
sizeof
(
struct
sigregs
);
frame
=
(
struct
sigregs
__user
*
)
newsp
;
/* Put a sigcontext on the stack */
newsp
-=
sizeof
(
*
sc
);
sc
=
(
struct
sigcontext
__user
*
)
newsp
;
/* create a stack frame for the caller of the handler */
newsp
-=
__SIGNAL_FRAMESIZE
;
if
(
!
access_ok
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
#if _NSIG != 64
#error "Please adjust handle_signal()"
#endif
if
(
__put_user
((
unsigned
long
)
ka
->
sa
.
sa_handler
,
&
sc
->
handler
)
||
__put_user
(
oldset
->
sig
[
0
],
&
sc
->
oldmask
)
||
__put_user
(
oldset
->
sig
[
1
],
&
sc
->
_unused
[
3
])
||
__put_user
((
struct
pt_regs
__user
*
)
frame
,
&
sc
->
regs
)
||
__put_user
(
sig
,
&
sc
->
signal
))
goto
badframe
;
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
__NR_sigreturn
))
goto
badframe
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
__user
*
)
newsp
))
goto
badframe
;
regs
->
gpr
[
1
]
=
newsp
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
sc
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
link
=
(
unsigned
long
)
frame
->
mctx
.
tramp
;
regs
->
trap
=
0
;
return
;
badframe:
#ifdef DEBUG_SIG
printk
(
"badframe in handle_signal, regs=%p frame=%p newsp=%lx
\n
"
,
regs
,
frame
,
newsp
);
#endif
force_sigsegv
(
sig
,
current
);
}
/*
* Do a signal return; undo the signal stack.
*/
int
sys_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
struct
sigcontext
__user
*
sc
;
struct
sigcontext
sigctx
;
struct
mcontext
__user
*
sr
;
sigset_t
set
;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
sc
=
(
struct
sigcontext
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
);
if
(
copy_from_user
(
&
sigctx
,
sc
,
sizeof
(
sigctx
)))
goto
badframe
;
set
.
sig
[
0
]
=
sigctx
.
oldmask
;
set
.
sig
[
1
]
=
sigctx
.
_unused
[
3
];
restore_sigmask
(
&
set
);
sr
=
(
struct
mcontext
__user
*
)
sigctx
.
regs
;
if
(
!
access_ok
(
VERIFY_READ
,
sr
,
sizeof
(
*
sr
))
||
restore_user_regs
(
regs
,
sr
,
1
))
goto
badframe
;
sigreturn_exit
(
regs
);
/* doesn't return */
return
0
;
badframe:
force_sig
(
SIGSEGV
,
current
);
return
0
;
}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
int
do_signal
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
)
{
siginfo_t
info
;
struct
k_sigaction
ka
;
unsigned
long
frame
,
newsp
;
int
signr
,
ret
;
if
(
try_to_freeze
())
{
signr
=
0
;
if
(
!
signal_pending
(
current
))
goto
no_signal
;
}
if
(
!
oldset
)
oldset
=
&
current
->
blocked
;
newsp
=
frame
=
0
;
signr
=
get_signal_to_deliver
(
&
info
,
&
ka
,
regs
,
NULL
);
no_signal:
if
(
TRAP
(
regs
)
==
0x0C00
/* System Call! */
&&
regs
->
ccr
&
0x10000000
/* error signalled */
&&
((
ret
=
regs
->
gpr
[
3
])
==
ERESTARTSYS
||
ret
==
ERESTARTNOHAND
||
ret
==
ERESTARTNOINTR
||
ret
==
ERESTART_RESTARTBLOCK
))
{
if
(
signr
>
0
&&
(
ret
==
ERESTARTNOHAND
||
ret
==
ERESTART_RESTARTBLOCK
||
(
ret
==
ERESTARTSYS
&&
!
(
ka
.
sa
.
sa_flags
&
SA_RESTART
))))
{
/* make the system call return an EINTR error */
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
/* note that the cr0.SO bit is already set */
}
else
{
regs
->
nip
-=
4
;
/* Back up & retry system call */
regs
->
result
=
0
;
regs
->
trap
=
0
;
if
(
ret
==
ERESTART_RESTARTBLOCK
)
regs
->
gpr
[
0
]
=
__NR_restart_syscall
;
else
regs
->
gpr
[
3
]
=
regs
->
orig_gpr3
;
}
}
if
(
signr
==
0
)
return
0
;
/* no signals delivered */
if
((
ka
.
sa
.
sa_flags
&
SA_ONSTACK
)
&&
current
->
sas_ss_size
&&
!
on_sig_stack
(
regs
->
gpr
[
1
]))
newsp
=
current
->
sas_ss_sp
+
current
->
sas_ss_size
;
else
newsp
=
regs
->
gpr
[
1
];
newsp
&=
~
0xfUL
;
/* Whee! Actually deliver the signal. */
if
(
ka
.
sa
.
sa_flags
&
SA_SIGINFO
)
handle_rt_signal
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
else
handle_signal
(
signr
,
&
ka
,
&
info
,
oldset
,
regs
,
newsp
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
sigorsets
(
&
current
->
blocked
,
&
current
->
blocked
,
&
ka
.
sa
.
sa_mask
);
if
(
!
(
ka
.
sa
.
sa_flags
&
SA_NODEFER
))
sigaddset
(
&
current
->
blocked
,
signr
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
return
1
;
}
arch/ppc64/kernel/Makefile
View file @
81e7009e
...
@@ -15,7 +15,7 @@ obj-y += irq.o idle.o dma.o \
...
@@ -15,7 +15,7 @@ obj-y += irq.o idle.o dma.o \
time.o signal.o
\
time.o signal.o
\
align.o bitops.o pacaData.o
\
align.o bitops.o pacaData.o
\
udbg.o ioctl32.o
\
udbg.o ioctl32.o
\
ptrace32.o
signal32.o
rtc.o
\
ptrace32.o rtc.o
\
cpu_setup_power4.o
\
cpu_setup_power4.o
\
iommu.o sysfs.o vdso.o pmc.o firmware.o
iommu.o sysfs.o vdso.o pmc.o firmware.o
obj-y
+=
vdso32/ vdso64/
obj-y
+=
vdso32/ vdso64/
...
...
include/asm-ppc64/ppc32.h
View file @
81e7009e
...
@@ -70,18 +70,18 @@ typedef struct compat_siginfo {
...
@@ -70,18 +70,18 @@ typedef struct compat_siginfo {
#define __old_sigaction32 old_sigaction32
#define __old_sigaction32 old_sigaction32
struct
__old_sigaction32
{
struct
__old_sigaction32
{
unsigned
sa_handler
;
compat_uptr_t
sa_handler
;
compat_old_sigset_t
sa_mask
;
compat_old_sigset_t
sa_mask
;
unsigned
int
sa_flags
;
unsigned
int
sa_flags
;
unsigned
sa_restorer
;
/* not used by Linux/SPARC yet */
compat_uptr_t
sa_restorer
;
/* not used by Linux/SPARC yet */
};
};
struct
sigaction32
{
struct
sigaction32
{
unsigned
in
t
sa_handler
;
/* Really a pointer, but need to deal with 32 bits */
compat_uptr_
t
sa_handler
;
/* Really a pointer, but need to deal with 32 bits */
unsigned
int
sa_flags
;
unsigned
int
sa_flags
;
unsigned
in
t
sa_restorer
;
/* Another 32 bit pointer */
compat_uptr_
t
sa_restorer
;
/* Another 32 bit pointer */
compat_sigset_t
sa_mask
;
/* A 32 bit mask */
compat_sigset_t
sa_mask
;
/* A 32 bit mask */
};
};
...
@@ -94,9 +94,9 @@ typedef struct sigaltstack_32 {
...
@@ -94,9 +94,9 @@ typedef struct sigaltstack_32 {
struct
sigcontext32
{
struct
sigcontext32
{
unsigned
int
_unused
[
4
];
unsigned
int
_unused
[
4
];
int
signal
;
int
signal
;
unsigned
in
t
handler
;
compat_uptr_
t
handler
;
unsigned
int
oldmask
;
unsigned
int
oldmask
;
u32
regs
;
/* 4 byte pointer to the pt_regs32 structure. */
compat_uptr_t
regs
;
/* 4 byte pointer to the pt_regs32 structure. */
};
};
struct
mcontext32
{
struct
mcontext32
{
...
@@ -111,7 +111,7 @@ struct ucontext32 {
...
@@ -111,7 +111,7 @@ struct ucontext32 {
unsigned
int
uc_link
;
unsigned
int
uc_link
;
stack_32_t
uc_stack
;
stack_32_t
uc_stack
;
int
uc_pad
[
7
];
int
uc_pad
[
7
];
u32
uc_regs
;
/* points to uc_mcontext field */
compat_uptr_t
uc_regs
;
/* points to uc_mcontext field */
compat_sigset_t
uc_sigmask
;
/* mask last for extensibility */
compat_sigset_t
uc_sigmask
;
/* mask last for extensibility */
/* glibc has 1024-bit signal masks, ours are 64-bit */
/* glibc has 1024-bit signal masks, ours are 64-bit */
int
uc_maskext
[
30
];
int
uc_maskext
[
30
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment