Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2550d7f1
Commit
2550d7f1
authored
Sep 07, 2003
by
Paul Mackerras
Browse files
Options
Browse Files
Download
Plain Diff
Merge samba.org:/home/paulus/kernel/linux-2.5
into samba.org:/home/paulus/kernel/for-linus-ppc
parents
7c2dd86b
f8c1260f
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
531 additions
and
344 deletions
+531
-344
arch/ppc/kernel/align.c
arch/ppc/kernel/align.c
+17
-15
arch/ppc/kernel/asm-offsets.c
arch/ppc/kernel/asm-offsets.c
+2
-1
arch/ppc/kernel/head.S
arch/ppc/kernel/head.S
+2
-0
arch/ppc/kernel/misc.S
arch/ppc/kernel/misc.S
+1
-1
arch/ppc/kernel/process.c
arch/ppc/kernel/process.c
+1
-0
arch/ppc/kernel/signal.c
arch/ppc/kernel/signal.c
+352
-255
arch/ppc/kernel/traps.c
arch/ppc/kernel/traps.c
+128
-60
include/asm-ppc/bitops.h
include/asm-ppc/bitops.h
+4
-4
include/asm-ppc/highmem.h
include/asm-ppc/highmem.h
+3
-2
include/asm-ppc/processor.h
include/asm-ppc/processor.h
+1
-0
include/asm-ppc/ucontext.h
include/asm-ppc/ucontext.h
+20
-6
No files found.
arch/ppc/kernel/align.c
View file @
2550d7f1
...
...
@@ -21,11 +21,11 @@ struct aligninfo {
unsigned
char
flags
;
};
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx)
|| defined(CONFIG_POWER4)
#define OPCD(inst) (((inst) & 0xFC000000) >> 26)
#define RS(inst) (((inst) & 0x03E00000) >> 21)
#define RA(inst) (((inst) & 0x001F0000) >> 16)
#define IS_
DFORM(code) ((code) >= 32 && (code) <= 55
)
#define IS_
XFORM(code) ((code) == 31
)
#endif
#define INVALID { 0, 0 }
...
...
@@ -61,9 +61,9 @@ static struct aligninfo aligninfo[128] = {
{
4
,
ST
+
F
+
S
},
/* 00 0 1010: stfs */
{
8
,
ST
+
F
},
/* 00 0 1011: stfd */
INVALID
,
/* 00 0 1100 */
INVALID
,
/* 00 0 1101 */
INVALID
,
/* 00 0 1101
: ld/ldu/lwa
*/
INVALID
,
/* 00 0 1110 */
INVALID
,
/* 00 0 1111 */
INVALID
,
/* 00 0 1111
: std/stdu
*/
{
4
,
LD
+
U
},
/* 00 1 0000: lwzu */
INVALID
,
/* 00 1 0001 */
{
4
,
ST
+
U
},
/* 00 1 0010: stwu */
...
...
@@ -80,12 +80,12 @@ static struct aligninfo aligninfo[128] = {
INVALID
,
/* 00 1 1101 */
INVALID
,
/* 00 1 1110 */
INVALID
,
/* 00 1 1111 */
INVALID
,
/* 01 0 0000 */
INVALID
,
/* 01 0 0000
: ldx
*/
INVALID
,
/* 01 0 0001 */
INVALID
,
/* 01 0 0010 */
INVALID
,
/* 01 0 0010
: stdx
*/
INVALID
,
/* 01 0 0011 */
INVALID
,
/* 01 0 0100 */
INVALID
,
/* 01 0 0101: lwax
??
*/
INVALID
,
/* 01 0 0101: lwax */
INVALID
,
/* 01 0 0110 */
INVALID
,
/* 01 0 0111 */
{
0
,
LD
+
HARD
},
/* 01 0 1000: lswx */
...
...
@@ -96,12 +96,12 @@ static struct aligninfo aligninfo[128] = {
INVALID
,
/* 01 0 1101 */
INVALID
,
/* 01 0 1110 */
INVALID
,
/* 01 0 1111 */
INVALID
,
/* 01 1 0000 */
INVALID
,
/* 01 1 0000
: ldux
*/
INVALID
,
/* 01 1 0001 */
INVALID
,
/* 01 1 0010 */
INVALID
,
/* 01 1 0010
: stdux
*/
INVALID
,
/* 01 1 0011 */
INVALID
,
/* 01 1 0100 */
INVALID
,
/* 01 1 0101: lwaux
??
*/
INVALID
,
/* 01 1 0101: lwaux */
INVALID
,
/* 01 1 0110 */
INVALID
,
/* 01 1 0111 */
INVALID
,
/* 01 1 1000 */
...
...
@@ -157,9 +157,9 @@ static struct aligninfo aligninfo[128] = {
{
4
,
ST
+
F
+
S
},
/* 11 0 1010: stfsx */
{
8
,
ST
+
F
},
/* 11 0 1011: stfdx */
INVALID
,
/* 11 0 1100 */
INVALID
,
/* 11 0 1101 */
INVALID
,
/* 11 0 1101
: lmd
*/
INVALID
,
/* 11 0 1110 */
INVALID
,
/* 11 0 1111 */
INVALID
,
/* 11 0 1111
: stmd
*/
{
4
,
LD
+
U
},
/* 11 1 0000: lwzux */
INVALID
,
/* 11 1 0001 */
{
4
,
ST
+
U
},
/* 11 1 0010: stwux */
...
...
@@ -184,7 +184,7 @@ int
fix_alignment
(
struct
pt_regs
*
regs
)
{
int
instr
,
nb
,
flags
;
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx)
|| defined(CONFIG_POWER4)
int
opcode
,
f1
,
f2
,
f3
;
#endif
int
i
,
t
;
...
...
@@ -199,9 +199,11 @@ fix_alignment(struct pt_regs *regs)
CHECK_FULL_REGS
(
regs
);
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx)
|| defined(CONFIG_POWER4)
/* The 4xx-family processors have no DSISR register,
* so we emulate it.
* The POWER4 has a DSISR register but doesn't set it on
* an alignment fault. -- paulus
*/
instr
=
*
((
unsigned
int
*
)
regs
->
nip
);
...
...
@@ -209,7 +211,7 @@ fix_alignment(struct pt_regs *regs)
reg
=
RS
(
instr
);
areg
=
RA
(
instr
);
if
(
IS_D
FORM
(
opcode
))
{
if
(
!
IS_X
FORM
(
opcode
))
{
f1
=
0
;
f2
=
(
instr
&
0x04000000
)
>>
26
;
f3
=
(
instr
&
0x78000000
)
>>
27
;
...
...
arch/ppc/kernel/asm-offsets.c
View file @
2550d7f1
...
...
@@ -52,6 +52,7 @@ main(void)
DEFINE
(
THREAD_VR0
,
offsetof
(
struct
thread_struct
,
vr
[
0
]));
DEFINE
(
THREAD_VRSAVE
,
offsetof
(
struct
thread_struct
,
vrsave
));
DEFINE
(
THREAD_VSCR
,
offsetof
(
struct
thread_struct
,
vscr
));
DEFINE
(
THREAD_USED_VR
,
offsetof
(
struct
thread_struct
,
used_vr
));
#endif
/* CONFIG_ALTIVEC */
/* Interrupt register frame */
DEFINE
(
STACK_FRAME_OVERHEAD
,
STACK_FRAME_OVERHEAD
);
...
...
@@ -101,7 +102,7 @@ main(void)
DEFINE
(
_XER
,
STACK_FRAME_OVERHEAD
+
offsetof
(
struct
pt_regs
,
xer
));
DEFINE
(
_DAR
,
STACK_FRAME_OVERHEAD
+
offsetof
(
struct
pt_regs
,
dar
));
DEFINE
(
_DSISR
,
STACK_FRAME_OVERHEAD
+
offsetof
(
struct
pt_regs
,
dsisr
));
/* The PowerPC 400-class processors have neither the DAR nor the DSISR
/* The PowerPC 400-class
& Book-E
processors have neither the DAR nor the DSISR
* SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
* for such processors. For critical interrupts we use them to
* hold SRR0 and SRR1.
...
...
arch/ppc/kernel/head.S
View file @
2550d7f1
...
...
@@ -915,7 +915,9 @@ load_up_altivec:
/
*
enable
use
of
AltiVec
after
return
*/
oris
r9
,
r9
,
MSR_VEC
@
h
mfspr
r5
,
SPRG3
/*
current
task
's THREAD (phys) */
li
r4
,
1
li
r10
,
THREAD_VSCR
stw
r4
,
THREAD_USED_VR
(
r5
)
lvx
vr0
,
r10
,
r5
mtvscr
vr0
REST_32VR
(0,
r10
,
r5
)
...
...
arch/ppc/kernel/misc.S
View file @
2550d7f1
...
...
@@ -1379,7 +1379,7 @@ _GLOBAL(sys_call_table)
.
long
sys_clock_gettime
.
long
sys_clock_getres
.
long
sys_clock_nanosleep
.
long
sys_
ni_syscall
/*
reserved
for
swapcontext
*/
.
long
sys_
swapcontext
.
long
sys_tgkill
/*
250
*/
.
long
sys_utimes
.
long
sys_statfs64
...
...
arch/ppc/kernel/process.c
View file @
2550d7f1
...
...
@@ -415,6 +415,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
memset
(
current
->
thread
.
vr
,
0
,
sizeof
(
current
->
thread
.
vr
));
memset
(
&
current
->
thread
.
vscr
,
0
,
sizeof
(
current
->
thread
.
vscr
));
current
->
thread
.
vrsave
=
0
;
current
->
thread
.
used_vr
=
0
;
#endif
/* CONFIG_ALTIVEC */
}
...
...
arch/ppc/kernel/signal.c
View file @
2550d7f1
...
...
@@ -41,18 +41,6 @@ extern void sigreturn_exit(struct pt_regs *);
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
/*
* These are the flags in the MSR that the user is allowed to change
* by modifying the saved value of the MSR on the stack. SE and BE
* should not be in this list since gdb may want to change these. I.e,
* you should be able to step out of a signal handler to see what
* instruction executes next after the signal handler completes.
* Alternately, if you stepped into a signal handler, you should be
* able to continue 'til the next breakpoint from within the signal
* handler, even if the handler returns.
*/
#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
int
do_signal
(
sigset_t
*
oldset
,
struct
pt_regs
*
regs
);
/*
...
...
@@ -72,8 +60,8 @@ sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
ccr
|=
0x10000000
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
...
...
@@ -103,8 +91,8 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4,
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
regs
->
result
=
-
EINTR
;
regs
->
ccr
|=
0x10000000
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
while
(
1
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule
();
...
...
@@ -164,305 +152,389 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
*
*/
struct
sigregs
{
elf_gregset_t
gp_regs
;
double
fp_regs
[
ELF_NFPREG
];
unsigned
long
tramp
[
2
];
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
];
};
struct
rt_sigframe
{
unsigned
long
_unused
[
2
];
struct
siginfo
*
pinfo
;
void
*
puc
;
struct
siginfo
info
;
struct
ucontext
uc
;
};
/* 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:
* a sigregs struct
* one rt_sigframe struct (siginfo + ucontext)
* a gap of __SIGNAL_FRAMESIZE bytes
* 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.
*
*/
int
sys_rt_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
struct
rt_sigframe
{
struct
rt_sigframe
__user
*
rt_sf
;
struct
sigcontext
sigctx
;
struct
sigregs
__user
*
sr
;
elf_gregset_t
saved_regs
;
/* an array of ELF_NGREG unsigned longs
*/
sigset_t
set
;
stack_t
st
;
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
]
;
}
;
rt_sf
=
(
struct
rt_sigframe
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
);
if
(
copy_from_user
(
&
sigctx
,
&
rt_sf
->
uc
.
uc_mcontext
,
sizeof
(
sigctx
))
||
copy_from_user
(
&
set
,
&
rt_sf
->
uc
.
uc_sigmask
,
sizeof
(
set
))
||
copy_from_user
(
&
st
,
&
rt_sf
->
uc
.
uc_stack
,
sizeof
(
st
)))
goto
badframe
;
sigdelsetmask
(
&
set
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
current
->
blocked
=
set
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
/*
* Save the current user registers on the user stack.
* We only save the altivec registers if the process has used
* altivec instructions at some point.
*/
static
int
save_user_regs
(
struct
pt_regs
*
regs
,
struct
mcontext
*
frame
,
int
sigret
)
{
/* save general and floating-point registers */
CHECK_FULL_REGS
(
regs
);
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
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
;
/* restore registers -
* sigctx is initialized to point to the
* preamble frame (where registers are stored)
* see handle_signal()
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
#ifdef CONFIG_ALTIVEC
/* save altivec registers */
if
(
current
->
thread
.
used_vr
)
{
if
(
regs
->
msr
&
MSR_VEC
)
giveup_altivec
(
current
);
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
*/
sr
=
(
struct
sigregs
__user
*
)
sigctx
.
regs
;
if
(
copy_from_user
(
saved_regs
,
&
sr
->
gp_regs
,
sizeof
(
sr
->
gp_regs
)))
goto
badframe
;
saved_regs
[
PT_MSR
]
=
(
regs
->
msr
&
~
MSR_USERCHANGE
)
|
(
saved_regs
[
PT_MSR
]
&
MSR_USERCHANGE
);
memcpy
(
regs
,
saved_regs
,
GP_REGS_SIZE
);
if
(
copy_from_user
(
current
->
thread
.
fpr
,
&
sr
->
fp_regs
,
sizeof
(
sr
->
fp_regs
)))
goto
badframe
;
if
(
__put_user
(
current
->
thread
.
vrsave
,
(
u32
*
)
&
frame
->
mc_vregs
[
32
]))
return
1
;
#endif
/* CONFIG_ALTIVEC */
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
]);
}
sigreturn_exit
(
regs
);
/* doesn't return here */
return
0
;
}
badframe:
do_exit
(
SIGSEGV
);
/*
* 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
)
{
#ifdef CONFIG_ALTIVEC
unsigned
long
msr
;
#endif
/* 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
;
/* force the process to reload the FP registers from
current->thread when it next does FP instructions */
regs
->
msr
&=
~
MSR_FP
;
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
,
sizeof
(
current
->
thread
.
vr
));
/* Always get VRSAVE back */
if
(
__get_user
(
current
->
thread
.
vrsave
,
(
u32
*
)
&
sr
->
mc_vregs
[
32
]))
return
1
;
#endif
/* CONFIG_ALTIVEC */
return
0
;
}
/*
* Restore the user process's signal mask
*/
static
void
setup_rt_frame
(
struct
pt_regs
*
regs
,
struct
sigregs
__user
*
frame
,
signed
long
newsp
)
restore_sigmask
(
sigset_t
*
set
)
{
struct
rt_sigframe
__user
*
rt_sf
=
(
struct
rt_sigframe
__user
*
)
newsp
;
sigdelsetmask
(
set
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
current
->
blocked
=
*
set
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
}
/* Set up preamble frame */
if
(
verify_area
(
VERIFY_WRITE
,
frame
,
sizeof
(
*
frame
)))
/*
* 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
(
verify_area
(
VERIFY_WRITE
,
(
void
__user
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
CHECK_FULL_REGS
(
regs
);
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
if
(
__copy_to_user
(
&
frame
->
gp_regs
,
regs
,
GP_REGS_SIZE
)
||
__
copy_to_user
(
&
frame
->
fp_regs
,
current
->
thread
.
fpr
,
ELF_NFPREG
*
sizeof
(
double
)
)
/* Set up to return from user space.
It calls the sc exception at offset 0x9999
for sys_rt_sigreturn().
*/
||
__
put_user
(
0x38000000UL
+
__NR_rt_sigreturn
,
&
frame
->
tramp
[
0
]
)
||
__
put_user
(
0x44000002UL
,
&
frame
->
tramp
[
1
]))
/* sc */
/* 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_oldsigmask
,
oldset
,
sizeof
(
*
oldset
)
)
||
__
copy_to_user
(
&
rt_sf
->
uc
.
uc_sigmask
,
oldset
,
sizeof
(
*
oldset
)))
goto
badframe
;
flush_icache_range
((
unsigned
long
)
&
frame
->
tramp
[
0
],
(
unsigned
long
)
&
frame
->
tramp
[
2
]);
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
/* Retrieve rt_sigframe from stack and
set up registers for signal handler
*/
newsp
-=
__SIGNAL_FRAMESIZE
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
__user
*
)
newsp
)
||
get_user
(
regs
->
nip
,
&
rt_sf
->
uc
.
uc_mcontext
.
handler
)
||
get_user
(
regs
->
gpr
[
3
],
&
rt_sf
->
uc
.
uc_mcontext
.
signal
)
||
get_user
(
regs
->
gpr
[
4
],
(
unsigned
long
__user
*
)
&
rt_sf
->
pinfo
)
||
get_user
(
regs
->
gpr
[
5
],
(
unsigned
long
__user
*
)
&
rt_sf
->
puc
))
/* 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:
#if DEBUG_SIG
printk
(
"badframe in
setup_rt_frame
, regs=%p frame=%p newsp=%lx
\n
"
,
printk
(
"badframe in
handle_rt_signal
, regs=%p frame=%p newsp=%lx
\n
"
,
regs
,
frame
,
newsp
);
#endif
do_exit
(
SIGSEGV
);
if
(
sig
==
SIGSEGV
)
ka
->
sa
.
sa_handler
=
SIG_DFL
;
force_sig
(
SIGSEGV
,
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
)
static
int
do_setcontext
(
struct
ucontext
__user
*
ucp
,
struct
pt_regs
*
regs
)
{
struct
sigcontext
__user
*
sc
;
struct
sigcontext
sigctx
;
struct
sigregs
__user
*
sr
;
elf_gregset_t
saved_regs
;
/* an array of ELF_NGREG unsigned longs */
sigset_t
set
;
sc
=
(
struct
sigcontext
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
);
if
(
copy_from_user
(
&
sigctx
,
sc
,
sizeof
(
sigctx
)))
goto
badframe
;
if
(
__copy_from_user
(
&
set
,
&
ucp
->
uc_sigmask
,
sizeof
(
set
)))
return
-
EFAULT
;
restore_sigmask
(
&
set
)
;
set
.
sig
[
0
]
=
sigctx
.
oldmask
;
#if _NSIG_WORDS > 1
set
.
sig
[
1
]
=
sigctx
.
_unused
[
3
];
#endif
sigdelsetmask
(
&
set
,
~
_BLOCKABLE
);
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
current
->
blocked
=
set
;
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
if
(
restore_user_regs
(
regs
,
&
ucp
->
uc_mcontext
))
return
-
EFAULT
;
/* restore registers */
sr
=
(
struct
sigregs
__user
*
)
sigctx
.
regs
;
if
(
copy_from_user
(
saved_regs
,
&
sr
->
gp_regs
,
sizeof
(
sr
->
gp_regs
)))
goto
badframe
;
saved_regs
[
PT_MSR
]
=
(
regs
->
msr
&
~
MSR_USERCHANGE
)
|
(
saved_regs
[
PT_MSR
]
&
MSR_USERCHANGE
);
memcpy
(
regs
,
saved_regs
,
GP_REGS_SIZE
);
return
0
;
}
if
(
copy_from_user
(
current
->
thread
.
fpr
,
&
sr
->
fp_regs
,
sizeof
(
sr
->
fp_regs
)))
goto
badframe
;
int
sys_swapcontext
(
struct
ucontext
__user
*
old_ctx
,
struct
ucontext
__user
*
new_ctx
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
unsigned
char
tmp
;
if
(
old_ctx
!=
NULL
)
{
if
(
verify_area
(
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
))
/* the next 2 things aren't strictly necessary */
||
__copy_to_user
(
&
old_ctx
->
uc_oldsigmask
,
&
current
->
blocked
,
sizeof
(
sigset_t
))
||
__put_user
(
&
old_ctx
->
uc_mcontext
,
&
old_ctx
->
uc_regs
))
return
-
EFAULT
;
}
if
(
new_ctx
==
NULL
)
return
0
;
if
(
verify_area
(
VERIFY_READ
,
new_ctx
,
sizeof
(
*
new_ctx
))
||
__get_user
(
tmp
,
(
u8
*
)
new_ctx
)
||
__get_user
(
tmp
,
(
u8
*
)
(
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 verify_area
* 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
))
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
;
rt_sf
=
(
struct
rt_sigframe
__user
*
)
(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
+
16
);
if
(
verify_area
(
VERIFY_READ
,
rt_sf
,
sizeof
(
struct
rt_sigframe
)))
goto
bad
;
if
(
do_setcontext
(
&
rt_sf
->
uc
,
regs
))
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
;
badframe:
do_exit
(
SIGSEGV
);
}
bad:
force_sig
(
SIGSEGV
,
current
);
return
0
;
}
/*
*
Set up a signal frame.
*
OK, we're invoking a handler
*/
static
void
setup_frame
(
struct
pt_regs
*
regs
,
struct
sigregs
__user
*
frame
,
unsigned
long
newsp
)
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
sigcontext
__user
*
)
newsp
;
struct
sigcontext
__user
*
sc
;
struct
sigregs
__user
*
frame
;
unsigned
long
origsp
=
newsp
;
if
(
verify_area
(
VERIFY_WRITE
,
frame
,
sizeof
(
*
frame
)))
/* 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
(
verify_area
(
VERIFY_WRITE
,
(
void
*
)
newsp
,
origsp
-
newsp
))
goto
badframe
;
CHECK_FULL_REGS
(
regs
);
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
if
(
__copy_to_user
(
&
frame
->
gp_regs
,
regs
,
GP_REGS_SIZE
)
||
__copy_to_user
(
&
frame
->
fp_regs
,
current
->
thread
.
fpr
,
ELF_NFPREG
*
sizeof
(
double
))
||
__put_user
(
0x38000000UL
+
__NR_sigreturn
,
&
frame
->
tramp
[
0
])
||
__put_user
(
0x44000002UL
,
&
frame
->
tramp
[
1
]))
/* sc */
#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
*
)
frame
,
&
sc
->
regs
)
||
__put_user
(
sig
,
&
sc
->
signal
))
goto
badframe
;
flush_icache_range
((
unsigned
long
)
&
frame
->
tramp
[
0
],
(
unsigned
long
)
&
frame
->
tramp
[
2
]);
current
->
thread
.
fpscr
=
0
;
/* turn off all fp exceptions */
newsp
-=
__SIGNAL_FRAMESIZE
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
__user
*
)
newsp
)
||
get_user
(
regs
->
nip
,
&
sc
->
handler
)
||
get_user
(
regs
->
gpr
[
3
],
&
sc
->
signal
))
if
(
save_user_regs
(
regs
,
&
frame
->
mctx
,
__NR_sigreturn
))
goto
badframe
;
if
(
put_user
(
regs
->
gpr
[
1
],
(
unsigned
long
*
)
newsp
))
goto
badframe
;
regs
->
gpr
[
1
]
=
newsp
;
regs
->
gpr
[
3
]
=
sig
;
regs
->
gpr
[
4
]
=
(
unsigned
long
)
sc
;
regs
->
link
=
(
unsigned
long
)
frame
->
tramp
;
regs
->
nip
=
(
unsigned
long
)
ka
->
sa
.
sa_handler
;
regs
->
link
=
(
unsigned
long
)
frame
->
mctx
.
tramp
;
regs
->
trap
=
0
;
return
;
badframe:
#if DEBUG_SIG
printk
(
"badframe in
setup_frame, regs=%p frame=%p
newsp=%lx
\n
"
,
regs
,
frame
,
news
p
);
printk
(
"badframe in
handle_signal, regs=%p frame=%lx
newsp=%lx
\n
"
,
regs
,
frame
,
*
newsp
p
);
#endif
do_exit
(
SIGSEGV
);
if
(
sig
==
SIGSEGV
)
ka
->
sa
.
sa_handler
=
SIG_DFL
;
force_sig
(
SIGSEGV
,
current
);
}
/*
*
OK, we're invoking a handler
*
Do a signal return; undo the signal stack.
*/
static
void
handle_signal
(
unsigned
long
sig
,
siginfo_t
*
info
,
sigset_t
*
oldset
,
struct
pt_regs
*
regs
,
unsigned
long
*
newspp
,
unsigned
long
frame
)
int
sys_sigreturn
(
int
r3
,
int
r4
,
int
r5
,
int
r6
,
int
r7
,
int
r8
,
struct
pt_regs
*
regs
)
{
struct
sigcontext
__user
*
sc
;
struct
rt_sigframe
__user
*
rt_sf
;
struct
k_sigaction
*
ka
=
&
current
->
sighand
->
action
[
sig
-
1
];
if
(
TRAP
(
regs
)
==
0x0C00
/* System Call! */
&&
((
int
)
regs
->
result
==
-
ERESTARTNOHAND
||
(
int
)
regs
->
result
==
-
ERESTART_RESTARTBLOCK
||
((
int
)
regs
->
result
==
-
ERESTARTSYS
&&
!
(
ka
->
sa
.
sa_flags
&
SA_RESTART
))))
{
if
((
int
)
regs
->
result
==
-
ERESTART_RESTARTBLOCK
)
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
regs
->
result
=
-
EINTR
;
regs
->
gpr
[
3
]
=
EINTR
;
regs
->
ccr
|=
0x10000000
;
}
struct
sigcontext
sigctx
;
struct
mcontext
__user
*
sr
;
sigset_t
set
;
/* Set up Signal Frame */
if
(
ka
->
sa
.
sa_flags
&
SA_SIGINFO
)
{
/* Put a Real Time Context onto stack */
*
newspp
-=
sizeof
(
*
rt_sf
);
rt_sf
=
(
struct
rt_sigframe
__user
*
)
*
newspp
;
if
(
verify_area
(
VERIFY_WRITE
,
rt_sf
,
sizeof
(
*
rt_sf
)))
goto
badframe
;
if
(
__put_user
((
unsigned
long
)
ka
->
sa
.
sa_handler
,
&
rt_sf
->
uc
.
uc_mcontext
.
handler
)
||
__put_user
(
&
rt_sf
->
info
,
&
rt_sf
->
pinfo
)
||
__put_user
(
&
rt_sf
->
uc
,
&
rt_sf
->
puc
)
/* Put the siginfo */
||
copy_siginfo_to_user
(
&
rt_sf
->
info
,
info
)
/* Create the ucontext */
||
__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
)
||
__copy_to_user
(
&
rt_sf
->
uc
.
uc_sigmask
,
oldset
,
sizeof
(
*
oldset
))
/* mcontext.regs points to preamble register frame */
||
__put_user
((
struct
pt_regs
*
)
frame
,
&
rt_sf
->
uc
.
uc_mcontext
.
regs
)
||
__put_user
(
sig
,
&
rt_sf
->
uc
.
uc_mcontext
.
signal
))
goto
badframe
;
}
else
{
/* Put a sigcontext on the stack */
*
newspp
-=
sizeof
(
*
sc
);
sc
=
(
struct
sigcontext
__user
*
)
*
newspp
;
if
(
verify_area
(
VERIFY_WRITE
,
sc
,
sizeof
(
*
sc
)))
goto
badframe
;
if
(
__put_user
((
unsigned
long
)
ka
->
sa
.
sa_handler
,
&
sc
->
handler
)
||
__put_user
(
oldset
->
sig
[
0
],
&
sc
->
oldmask
)
#if _NSIG_WORDS > 1
||
__put_user
(
oldset
->
sig
[
1
],
&
sc
->
_unused
[
3
])
#endif
||
__put_user
((
struct
pt_regs
*
)
frame
,
&
sc
->
regs
)
||
__put_user
(
sig
,
&
sc
->
signal
))
goto
badframe
;
}
sc
=
(
struct
sigcontext
__user
*
)(
regs
->
gpr
[
1
]
+
__SIGNAL_FRAMESIZE
);
if
(
copy_from_user
(
&
sigctx
,
sc
,
sizeof
(
sigctx
)))
goto
badframe
;
if
(
ka
->
sa
.
sa_flags
&
SA_ONESHOT
)
ka
->
sa
.
sa_handler
=
SIG_DFL
;
set
.
sig
[
0
]
=
sigctx
.
oldmask
;
set
.
sig
[
1
]
=
sigctx
.
_unused
[
3
];
restore_sigmask
(
&
set
);
if
(
!
(
ka
->
sa
.
sa_flags
&
SA_NODEFER
))
{
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
sigorsets
(
&
current
->
blocked
,
&
current
->
blocked
,
&
ka
->
sa
.
sa_mask
);
sigaddset
(
&
current
->
blocked
,
sig
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
}
return
;
sr
=
(
struct
mcontext
*
)
sigctx
.
regs
;
if
(
verify_area
(
VERIFY_READ
,
sr
,
sizeof
(
*
sr
))
||
restore_user_regs
(
regs
,
sr
))
goto
badframe
;
sigreturn_exit
(
regs
);
/* doesn't return */
return
0
;
badframe:
#if DEBUG_SIG
printk
(
"badframe in handle_signal, regs=%p frame=%lx newsp=%lx
\n
"
,
regs
,
frame
,
*
newspp
);
printk
(
"sc=%p sig=%d ka=%p info=%p oldset=%p
\n
"
,
sc
,
sig
,
ka
,
info
,
oldset
);
#endif
do_exit
(
SIGSEGV
);
force_sig
(
SIGSEGV
,
current
);
return
0
;
}
/*
...
...
@@ -475,7 +547,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
siginfo_t
info
;
struct
k_sigaction
*
ka
;
unsigned
long
frame
,
newsp
;
int
signr
;
int
signr
,
ret
;
if
(
!
oldset
)
oldset
=
&
current
->
blocked
;
...
...
@@ -483,40 +555,65 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
newsp
=
frame
=
0
;
signr
=
get_signal_to_deliver
(
&
info
,
regs
,
NULL
);
if
(
signr
>
0
)
{
ka
=
&
current
->
sighand
->
action
[
signr
-
1
];
if
(
(
ka
->
sa
.
sa_flags
&
SA_ONSTACK
)
&&
(
!
on_sig_stack
(
regs
->
gpr
[
1
])))
newsp
=
(
current
->
sas_ss_sp
+
current
->
sas_ss_size
);
else
newsp
=
regs
->
gpr
[
1
];
newsp
=
frame
=
newsp
-
sizeof
(
struct
sigregs
);
/* Whee! Actually deliver the signal. */
handle_signal
(
signr
,
&
info
,
oldset
,
regs
,
&
newsp
,
frame
);
}
if
(
TRAP
(
regs
)
==
0x0C00
)
{
/* System Call! */
if
((
int
)
regs
->
result
==
-
ERESTARTNOHAND
||
(
int
)
regs
->
result
==
-
ERESTARTSYS
||
(
int
)
regs
->
result
==
-
ERESTARTNOINTR
)
{
regs
->
gpr
[
3
]
=
regs
->
orig_gpr3
;
ka
=
(
signr
==
0
)
?
NULL
:
&
current
->
sighand
->
action
[
signr
-
1
];
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 */
/* clear any restart function that was set */
if
(
ret
==
ERESTART_RESTARTBLOCK
)
current_thread_info
()
->
restart_block
.
fn
=
do_no_restart_syscall
;
}
else
{
regs
->
nip
-=
4
;
/* Back up & retry system call */
regs
->
result
=
0
;
}
else
if
((
int
)
regs
->
result
==
-
ERESTART_RESTARTBLOCK
)
{
regs
->
gpr
[
0
]
=
__NR_restart_syscall
;
regs
->
nip
-=
4
;
regs
->
result
=
0
;
regs
->
trap
=
0
;
if
(
ret
==
ERESTART_RESTARTBLOCK
)
regs
->
gpr
[
0
]
=
__NR_restart_syscall
;
else
regs
->
gpr
[
3
]
=
regs
->
orig_gpr3
;
}
}
if
(
newsp
==
frame
)
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
)
setup_rt_frame
(
regs
,
(
struct
sigregs
__user
*
)
frame
,
newsp
);
handle_rt_signal
(
signr
,
ka
,
&
info
,
oldset
,
regs
,
newsp
);
else
setup_frame
(
regs
,
(
struct
sigregs
__user
*
)
frame
,
newsp
);
handle_signal
(
signr
,
ka
,
&
info
,
oldset
,
regs
,
newsp
);
if
(
ka
->
sa
.
sa_flags
&
SA_ONESHOT
)
ka
->
sa
.
sa_handler
=
SIG_DFL
;
if
(
!
(
ka
->
sa
.
sa_flags
&
SA_NODEFER
))
{
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
sigorsets
(
&
current
->
blocked
,
&
current
->
blocked
,
&
ka
->
sa
.
sa_mask
);
sigaddset
(
&
current
->
blocked
,
signr
);
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
}
return
1
;
}
arch/ppc/kernel/traps.c
View file @
2550d7f1
...
...
@@ -95,14 +95,19 @@ void die(const char * str, struct pt_regs * fp, long err)
}
void
_exception
(
int
signr
,
struct
pt_regs
*
regs
)
_exception
(
int
signr
,
struct
pt_regs
*
regs
,
int
code
,
unsigned
long
addr
)
{
if
(
!
user_mode
(
regs
))
{
siginfo_t
info
;
if
(
!
user_mode
(
regs
))
{
debugger
(
regs
);
die
(
"Exception in kernel mode"
,
regs
,
signr
);
}
force_sig
(
signr
,
current
);
info
.
si_signo
=
signr
;
info
.
si_errno
=
0
;
info
.
si_code
=
code
;
info
.
si_addr
=
(
void
*
)
addr
;
force_sig_info
(
signr
,
&
info
,
current
);
}
/*
...
...
@@ -154,12 +159,40 @@ static inline int check_io_access(struct pt_regs *regs)
return
0
;
}
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
#define REASON_FP 0
#define REASON_ILLEGAL ESR_PIL
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
/* single-step stuff */
#define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC)
#define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC)
#else
/* On non-4xx, the reason for the machine check or program
exception is in the MSR. */
#define get_reason(regs) ((regs)->msr)
#define REASON_FP 0x100000
#define REASON_ILLEGAL 0x80000
#define REASON_PRIVILEGED 0x40000
#define REASON_TRAP 0x20000
#define single_stepping(regs) ((regs)->msr & MSR_SE)
#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
#endif
void
MachineCheckException
(
struct
pt_regs
*
regs
)
{
unsigned
long
reason
=
get_reason
(
regs
);
if
(
user_mode
(
regs
))
{
regs
->
msr
|=
MSR_RI
;
_exception
(
SIG
SEGV
,
regs
);
_exception
(
SIG
BUS
,
regs
,
BUS_ADRERR
,
regs
->
nip
);
return
;
}
...
...
@@ -178,10 +211,18 @@ MachineCheckException(struct pt_regs *regs)
if
(
check_io_access
(
regs
))
return
;
#ifndef CONFIG_4xx
printk
(
KERN_CRIT
"Machine check in kernel mode.
\n
"
);
printk
(
KERN_CRIT
"Caused by (from SRR1=%lx): "
,
regs
->
msr
);
switch
(
regs
->
msr
&
0x601F0000
)
{
#ifdef CONFIG_4xx
if
(
reason
&
ESR_IMCP
)
{
printk
(
"Instruction"
);
mtspr
(
SPRN_ESR
,
reason
&
~
ESR_IMCP
);
}
else
printk
(
"Data"
);
printk
(
" machine check in kernel mode.
\n
"
);
#else
/* !CONFIG_4xx */
printk
(
"Machine check in kernel mode.
\n
"
);
printk
(
"Caused by (from SRR1=%lx): "
,
reason
);
switch
(
reason
&
0x601F0000
)
{
case
0x80000
:
printk
(
"Machine check signal
\n
"
);
break
;
...
...
@@ -208,15 +249,6 @@ MachineCheckException(struct pt_regs *regs)
default:
printk
(
"Unknown values in msr
\n
"
);
}
#else
/* CONFIG_4xx */
/* Note that the ESR gets stored in regs->dsisr on 4xx. */
if
(
regs
->
dsisr
&
ESR_MCI
)
{
printk
(
KERN_CRIT
"Instruction"
);
mtspr
(
SPRN_ESR
,
regs
->
dsisr
&
~
ESR_MCI
);
}
else
printk
(
KERN_CRIT
"Data"
);
printk
(
" machine check in kernel mode.
\n
"
);
#endif
/* CONFIG_4xx */
debugger
(
regs
);
...
...
@@ -238,7 +270,7 @@ UnknownException(struct pt_regs *regs)
{
printk
(
"Bad trap at PC: %lx, MSR: %lx, vector=%lx %s
\n
"
,
regs
->
nip
,
regs
->
msr
,
regs
->
trap
,
print_tainted
());
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
0
,
0
);
}
void
...
...
@@ -246,13 +278,13 @@ InstructionBreakpoint(struct pt_regs *regs)
{
if
(
debugger_iabr_match
(
regs
))
return
;
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
TRAP_BRKPT
,
0
);
}
void
RunModeException
(
struct
pt_regs
*
regs
)
{
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
0
,
0
);
}
/* Illegal instruction emulation support. Originally written to
...
...
@@ -271,17 +303,17 @@ RunModeException(struct pt_regs *regs)
static
int
emulate_instruction
(
struct
pt_regs
*
regs
)
{
u
int
instword
;
u
int
rd
;
uint
retval
;
u
32
instword
;
u
32
rd
;
int
retval
;
retval
=
EINVAL
;
retval
=
-
EINVAL
;
if
(
!
user_mode
(
regs
))
return
retval
;
CHECK_FULL_REGS
(
regs
);
if
(
get_user
(
instword
,
(
u
int
__user
*
)(
regs
->
nip
)))
if
(
get_user
(
instword
,
(
u
32
__user
*
)(
regs
->
nip
)))
return
-
EFAULT
;
/* Emulate the mfspr rD, PVR.
...
...
@@ -290,10 +322,23 @@ emulate_instruction(struct pt_regs *regs)
rd
=
(
instword
>>
21
)
&
0x1f
;
regs
->
gpr
[
rd
]
=
mfspr
(
PVR
);
retval
=
0
;
}
if
(
retval
==
0
)
regs
->
nip
+=
4
;
return
(
retval
);
}
return
retval
;
}
/*
* After we have successfully emulated an instruction, we have to
* check if the instruction was being single-stepped, and if so,
* pretend we got a single-step exception. This was pointed out
* by Kumar Gala. -- paulus
*/
static
void
emulate_single_step
(
struct
pt_regs
*
regs
)
{
if
(
single_stepping
(
regs
))
{
clear_single_step
(
regs
);
_exception
(
SIGTRAP
,
regs
,
TRAP_TRACE
,
0
);
}
}
/*
...
...
@@ -349,29 +394,47 @@ check_bug_trap(struct pt_regs *regs)
void
ProgramCheckException
(
struct
pt_regs
*
regs
)
{
int
errcode
;
#if defined(CONFIG_4xx)
unsigned
int
esr
=
regs
->
dsisr
;
int
isbpt
=
esr
&
ESR_PTR
;
unsigned
int
reason
=
get_reason
(
regs
);
extern
int
do_mathemu
(
struct
pt_regs
*
regs
);
#ifdef CONFIG_MATH_EMULATION
if
(
!
isbpt
&&
do_mathemu
(
regs
)
==
0
)
/* (reason & REASON_ILLEGAL) would be the obvious thing here,
* but there seems to be a hardware bug on the 405GP (RevD)
* that means ESR is sometimes set incorrectly - either to
* ESR_DST (!?) or 0. In the process of chasing this with the
* hardware people - not sure if it can happen on any illegal
* instruction or only on FP instructions, whether there is a
* pattern to occurences etc. -dgibson 31/Mar/2003 */
if
(
!
(
reason
&
REASON_TRAP
)
&&
do_mathemu
(
regs
)
==
0
)
{
emulate_single_step
(
regs
);
return
;
}
#endif
/* CONFIG_MATH_EMULATION */
#else
/* ! CONFIG_4xx */
int
isbpt
=
regs
->
msr
&
0x20000
;
if
(
regs
->
msr
&
0x100000
)
{
if
(
reason
&
REASON_FP
)
{
/* IEEE FP exception */
_exception
(
SIGFPE
,
regs
);
int
code
=
0
;
u32
fpscr
;
if
(
regs
->
msr
&
MSR_FP
)
giveup_fpu
(
current
);
fpscr
=
current
->
thread
.
fpscr
;
fpscr
&=
fpscr
<<
22
;
/* mask summary bits with enables */
if
(
fpscr
&
FPSCR_VX
)
code
=
FPE_FLTINV
;
else
if
(
fpscr
&
FPSCR_OX
)
code
=
FPE_FLTOVF
;
else
if
(
fpscr
&
FPSCR_UX
)
code
=
FPE_FLTUND
;
else
if
(
fpscr
&
FPSCR_ZX
)
code
=
FPE_FLTDIV
;
else
if
(
fpscr
&
FPSCR_XX
)
code
=
FPE_FLTRES
;
_exception
(
SIGFPE
,
regs
,
code
,
regs
->
nip
);
return
;
}
#endif
/* ! CONFIG_4xx */
if
(
isbpt
)
{
if
(
reason
&
REASON_TRAP
)
{
/* trap exception */
if
(
debugger_bpt
(
regs
))
return
;
...
...
@@ -379,17 +442,21 @@ ProgramCheckException(struct pt_regs *regs)
regs
->
nip
+=
4
;
return
;
}
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
TRAP_BRKPT
,
0
);
return
;
}
/* Try to emulate it if we should. */
if
((
errcode
=
emulate_instruction
(
regs
)))
{
if
(
errcode
==
-
EFAULT
)
_exception
(
SIGBUS
,
regs
);
else
_exception
(
SIGILL
,
regs
);
if
(
reason
&
REASON_PRIVILEGED
)
{
/* Try to emulate it if we should. */
if
(
emulate_instruction
(
regs
)
==
0
)
{
emulate_single_step
(
regs
);
return
;
}
_exception
(
SIGILL
,
regs
,
ILL_PRVOPC
,
regs
->
nip
);
return
;
}
_exception
(
SIGILL
,
regs
,
ILL_ILLOPC
,
regs
->
nip
);
}
void
...
...
@@ -398,7 +465,7 @@ SingleStepException(struct pt_regs *regs)
regs
->
msr
&=
~
MSR_SE
;
/* Turn off 'trace' bit */
if
(
debugger_sstep
(
regs
))
return
;
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
TRAP_TRACE
,
0
);
}
void
...
...
@@ -414,12 +481,12 @@ AlignmentException(struct pt_regs *regs)
if
(
fixed
==
-
EFAULT
)
{
/* fixed == -EFAULT means the operand address was bad */
if
(
user_mode
(
regs
))
force_sig
(
SIGSEGV
,
current
);
_exception
(
SIGSEGV
,
regs
,
SEGV_ACCERR
,
regs
->
dar
);
else
bad_page_fault
(
regs
,
regs
->
dar
,
SIGSEGV
);
return
;
}
_exception
(
SIGBUS
,
regs
);
_exception
(
SIGBUS
,
regs
,
BUS_ADRALN
,
regs
->
dar
);
}
void
...
...
@@ -470,16 +537,17 @@ SoftwareEmulation(struct pt_regs *regs)
#endif
if
(
errcode
)
{
if
(
errcode
>
0
)
_exception
(
SIGFPE
,
regs
);
_exception
(
SIGFPE
,
regs
,
0
,
0
);
else
if
(
errcode
==
-
EFAULT
)
_exception
(
SIGSEGV
,
regs
);
_exception
(
SIGSEGV
,
regs
,
0
,
0
);
else
_exception
(
SIGILL
,
regs
);
}
_exception
(
SIGILL
,
regs
,
ILL_ILLOPC
,
regs
->
nip
);
}
else
emulate_single_step
(
regs
);
}
#endif
/* CONFIG_8xx */
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx)
|| defined(CONFIG_BOOKE)
void
DebugException
(
struct
pt_regs
*
regs
,
unsigned
long
debug_status
)
{
...
...
@@ -487,7 +555,7 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status)
if (debug_status & DBSR_TIE) { /* trap instruction*/
if (!user_mode(regs) && debugger_bpt(regs))
return;
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs
, 0, 0
);
}
#endif
...
...
@@ -495,10 +563,10 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status)
if
(
!
user_mode
(
regs
)
&&
debugger_sstep
(
regs
))
return
;
current
->
thread
.
dbcr0
&=
~
DBCR0_IC
;
_exception
(
SIGTRAP
,
regs
);
_exception
(
SIGTRAP
,
regs
,
TRAP_TRACE
,
0
);
}
}
#endif
/* CONFIG_4xx */
#endif
/* CONFIG_4xx
|| CONFIG_BOOKE
*/
#if !defined(CONFIG_TAU_INT)
void
...
...
include/asm-ppc/bitops.h
View file @
2550d7f1
...
...
@@ -276,7 +276,7 @@ static __inline__ int fls(unsigned int x)
* Find the first bit set in a 140-bit bitmap.
* The first 100 bits are unlikely to be set.
*/
static
inline
int
sched_find_first_bit
(
unsigned
long
*
b
)
static
inline
int
sched_find_first_bit
(
const
unsigned
long
*
b
)
{
if
(
unlikely
(
b
[
0
]))
return
__ffs
(
b
[
0
]);
...
...
@@ -295,7 +295,7 @@ static inline int sched_find_first_bit(unsigned long *b)
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
*/
static
__inline__
unsigned
long
find_next_bit
(
unsigned
long
*
addr
,
static
__inline__
unsigned
long
find_next_bit
(
const
unsigned
long
*
addr
,
unsigned
long
size
,
unsigned
long
offset
)
{
unsigned
int
*
p
=
((
unsigned
int
*
)
addr
)
+
(
offset
>>
5
);
...
...
@@ -352,7 +352,7 @@ static __inline__ unsigned long find_next_bit(unsigned long *addr,
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
static
__inline__
unsigned
long
find_next_zero_bit
(
unsigned
long
*
addr
,
static
__inline__
unsigned
long
find_next_zero_bit
(
const
unsigned
long
*
addr
,
unsigned
long
size
,
unsigned
long
offset
)
{
unsigned
int
*
p
=
((
unsigned
int
*
)
addr
)
+
(
offset
>>
5
);
...
...
@@ -411,7 +411,7 @@ static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)
static
__inline__
unsigned
long
ext2_find_next_zero_bit
(
void
*
addr
,
static
__inline__
unsigned
long
ext2_find_next_zero_bit
(
const
void
*
addr
,
unsigned
long
size
,
unsigned
long
offset
)
{
unsigned
int
*
p
=
((
unsigned
int
*
)
addr
)
+
(
offset
>>
5
);
...
...
include/asm-ppc/highmem.h
View file @
2550d7f1
...
...
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <asm/kmap_types.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
/* undef for production */
#define HIGHMEM_DEBUG 1
...
...
@@ -41,8 +42,8 @@ extern void kmap_init(void) __init;
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
#define PKMAP_BASE CONFIG_HIGHMEM_START
#define LAST_PKMAP
1024
#define PKMAP_BASE
CONFIG_HIGHMEM_START
#define LAST_PKMAP
(1 << PTE_SHIFT)
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
...
...
include/asm-ppc/processor.h
View file @
2550d7f1
...
...
@@ -848,6 +848,7 @@ struct thread_struct {
/* AltiVec status */
vector128
vscr
__attribute
((
aligned
(
16
)));
unsigned
long
vrsave
;
int
used_vr
;
/* set if process has used altivec */
#endif
/* CONFIG_ALTIVEC */
};
...
...
include/asm-ppc/ucontext.h
View file @
2550d7f1
#ifndef _ASMPPC_UCONTEXT_H
#define _ASMPPC_UCONTEXT_H
/* Copied from i386. */
#include <asm/elf.h>
#include <asm/signal.h>
struct
mcontext
{
elf_gregset_t
mc_gregs
;
elf_fpregset_t
mc_fregs
;
unsigned
long
mc_pad
[
2
];
elf_vrregset_t
mc_vregs
__attribute__
((
__aligned__
(
16
)));
};
struct
ucontext
{
unsigned
long
uc_flags
;
struct
ucontext
*
uc_link
;
stack_t
uc_stack
;
struct
sigcontext
uc_mcontext
;
sigset_t
uc_sigmask
;
/* mask last for extensibility */
unsigned
long
uc_flags
;
struct
ucontext
*
uc_link
;
stack_t
uc_stack
;
int
uc_pad
[
7
];
struct
mcontext
*
uc_regs
;
/* backward compat */
sigset_t
uc_oldsigmask
;
/* backward compat */
int
uc_pad2
;
sigset_t
uc_sigmask
;
/* glibc has 1024-bit signal masks, ours are 64-bit */
int
uc_maskext
[
30
];
struct
mcontext
uc_mcontext
;
};
#endif
/* !_ASMPPC_UCONTEXT_H */
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