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
Kirill Smelkov
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