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
68c1e696
Commit
68c1e696
authored
Nov 01, 2002
by
Richard Henderson
Browse files
Options
Browse Files
Download
Plain Diff
Merge are.twiddle.net:/home/rth/BK/linus-2.5
into are.twiddle.net:/home/rth/BK/axp-2.5
parents
0630b89d
31045ad2
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
259 additions
and
119 deletions
+259
-119
arch/alpha/kernel/entry.S
arch/alpha/kernel/entry.S
+5
-3
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/osf_sys.c
+19
-4
arch/alpha/kernel/process.c
arch/alpha/kernel/process.c
+5
-2
arch/alpha/kernel/signal.c
arch/alpha/kernel/signal.c
+20
-4
arch/alpha/kernel/traps.c
arch/alpha/kernel/traps.c
+148
-58
arch/alpha/math-emu/math.c
arch/alpha/math-emu/math.c
+25
-13
arch/alpha/mm/fault.c
arch/alpha/mm/fault.c
+34
-17
include/asm-alpha/siginfo.h
include/asm-alpha/siginfo.h
+3
-18
No files found.
arch/alpha/kernel/entry.S
View file @
68c1e696
...
@@ -452,7 +452,8 @@ sys_fork:
...
@@ -452,7 +452,8 @@ sys_fork:
bsr
$
1
,
do_switch_stack
bsr
$
1
,
do_switch_stack
bis
$
31
,
SIGCHLD
,
$
16
bis
$
31
,
SIGCHLD
,
$
16
mov
$
31
,
$
17
mov
$
31
,
$
17
mov
$
30
,
$
18
mov
$
31
,
$
18
mov
$
30
,
$
19
jsr
$
26
,
alpha_clone
jsr
$
26
,
alpha_clone
bsr
$
1
,
undo_switch_stack
bsr
$
1
,
undo_switch_stack
ret
$
31
,(
$
26
),
1
ret
$
31
,(
$
26
),
1
...
@@ -463,8 +464,9 @@ sys_fork:
...
@@ -463,8 +464,9 @@ sys_fork:
.
ent
sys_clone
.
ent
sys_clone
sys_clone
:
sys_clone
:
bsr
$
1
,
do_switch_stack
bsr
$
1
,
do_switch_stack
/
*
arg1
and
arg2
come
from
the
user
*/
/
*
$
16
,
$
17
,
$
18
,
$
19
come
from
the
user
; $19 is used later
mov
$
30
,
$
18
via
pt_regs
->
r19
.
*/
mov
$
30
,
$
19
jsr
$
26
,
alpha_clone
jsr
$
26
,
alpha_clone
bsr
$
1
,
undo_switch_stack
bsr
$
1
,
undo_switch_stack
ret
$
31
,(
$
26
),
1
ret
$
31
,(
$
26
),
1
...
...
arch/alpha/kernel/osf_sys.c
View file @
68c1e696
...
@@ -844,7 +844,7 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
...
@@ -844,7 +844,7 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
{
{
switch
(
op
)
{
switch
(
op
)
{
case
SSI_IEEE_FP_CONTROL
:
{
case
SSI_IEEE_FP_CONTROL
:
{
unsigned
long
swcr
,
fpcr
;
unsigned
long
swcr
,
fpcr
,
fex
;
/*
/*
* Alpha Architecture Handbook 4.7.7.3:
* Alpha Architecture Handbook 4.7.7.3:
...
@@ -867,9 +867,24 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
...
@@ -867,9 +867,24 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
wrfpcr
(
fpcr
);
wrfpcr
(
fpcr
);
/* If any exceptions are now unmasked, send a signal. */
/* If any exceptions are now unmasked, send a signal. */
if
(((
swcr
&
IEEE_STATUS_MASK
)
fex
=
((
swcr
&
IEEE_STATUS_MASK
)
>>
IEEE_STATUS_TO_EXCSUM_SHIFT
)
&
swcr
)
{
>>
IEEE_STATUS_TO_EXCSUM_SHIFT
)
&
swcr
;
send_sig
(
SIGFPE
,
current
,
1
);
if
(
fex
)
{
siginfo_t
info
;
int
si_code
=
0
;
if
(
fex
&
IEEE_TRAP_ENABLE_DNO
)
si_code
=
FPE_FLTUND
;
if
(
fex
&
IEEE_TRAP_ENABLE_INE
)
si_code
=
FPE_FLTRES
;
if
(
fex
&
IEEE_TRAP_ENABLE_UNF
)
si_code
=
FPE_FLTUND
;
if
(
fex
&
IEEE_TRAP_ENABLE_OVF
)
si_code
=
FPE_FLTOVF
;
if
(
fex
&
IEEE_TRAP_ENABLE_DZE
)
si_code
=
FPE_FLTDIV
;
if
(
fex
&
IEEE_TRAP_ENABLE_INV
)
si_code
=
FPE_FLTINV
;
info
.
si_signo
=
SIGFPE
;
info
.
si_errno
=
0
;
info
.
si_code
=
si_code
;
info
.
si_addr
=
0
;
/* FIXME */
send_sig_info
(
SIGFPE
,
&
info
,
current
);
}
}
return
0
;
return
0
;
...
...
arch/alpha/kernel/process.c
View file @
68c1e696
...
@@ -245,11 +245,10 @@ release_thread(struct task_struct *dead_task)
...
@@ -245,11 +245,10 @@ release_thread(struct task_struct *dead_task)
*/
*/
int
int
alpha_clone
(
unsigned
long
clone_flags
,
unsigned
long
usp
,
alpha_clone
(
unsigned
long
clone_flags
,
unsigned
long
usp
,
struct
switch_stack
*
swstack
)
int
*
user_tid
,
struct
switch_stack
*
swstack
)
{
{
struct
task_struct
*
p
;
struct
task_struct
*
p
;
struct
pt_regs
*
u_regs
=
(
struct
pt_regs
*
)
(
swstack
+
1
);
struct
pt_regs
*
u_regs
=
(
struct
pt_regs
*
)
(
swstack
+
1
);
int
*
user_tid
=
(
int
*
)
u_regs
->
r19
;
if
(
!
usp
)
if
(
!
usp
)
usp
=
rdusp
();
usp
=
rdusp
();
...
@@ -314,6 +313,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
...
@@ -314,6 +313,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childti
->
pcb
.
ksp
=
(
unsigned
long
)
childstack
;
childti
->
pcb
.
ksp
=
(
unsigned
long
)
childstack
;
childti
->
pcb
.
flags
=
1
;
/* set FEN, clear everything else */
childti
->
pcb
.
flags
=
1
;
/* set FEN, clear everything else */
/* Set a new TLS for the child thread? Peek back into the
syscall arguments that we saved on syscall entry. */
childti
->
pcb
.
unique
=
(
clone_flags
&
CLONE_SETTLS
?
regs
->
r19
:
0
);
return
0
;
return
0
;
}
}
...
...
arch/alpha/kernel/signal.c
View file @
68c1e696
...
@@ -293,8 +293,16 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
...
@@ -293,8 +293,16 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
goto
give_sigsegv
;
goto
give_sigsegv
;
/* Send SIGTRAP if we're single-stepping: */
/* Send SIGTRAP if we're single-stepping: */
if
(
ptrace_cancel_bpt
(
current
))
if
(
ptrace_cancel_bpt
(
current
))
{
send_sig
(
SIGTRAP
,
current
,
1
);
siginfo_t
info
;
info
.
si_signo
=
SIGTRAP
;
info
.
si_errno
=
0
;
info
.
si_code
=
TRAP_BRKPT
;
info
.
si_addr
=
(
void
*
)
regs
->
pc
;
info
.
si_trapno
=
0
;
send_sig_info
(
SIGTRAP
,
&
info
,
current
);
}
return
;
return
;
give_sigsegv:
give_sigsegv:
...
@@ -330,8 +338,16 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
...
@@ -330,8 +338,16 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
do_sigaltstack
(
&
st
,
NULL
,
rdusp
());
do_sigaltstack
(
&
st
,
NULL
,
rdusp
());
/* Send SIGTRAP if we're single-stepping: */
/* Send SIGTRAP if we're single-stepping: */
if
(
ptrace_cancel_bpt
(
current
))
if
(
ptrace_cancel_bpt
(
current
))
{
send_sig
(
SIGTRAP
,
current
,
1
);
siginfo_t
info
;
info
.
si_signo
=
SIGTRAP
;
info
.
si_errno
=
0
;
info
.
si_code
=
TRAP_BRKPT
;
info
.
si_addr
=
(
void
*
)
regs
->
pc
;
info
.
si_trapno
=
0
;
send_sig_info
(
SIGTRAP
,
&
info
,
current
);
}
return
;
return
;
give_sigsegv:
give_sigsegv:
...
...
arch/alpha/kernel/traps.c
View file @
68c1e696
...
@@ -213,25 +213,25 @@ do_entArith(unsigned long summary, unsigned long write_mask,
...
@@ -213,25 +213,25 @@ do_entArith(unsigned long summary, unsigned long write_mask,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a5
,
struct
pt_regs
regs
)
unsigned
long
a5
,
struct
pt_regs
regs
)
{
{
long
si_code
=
FPE_FLTINV
;
siginfo_t
info
;
if
(
summary
&
1
)
{
if
(
summary
&
1
)
{
/* Software-completion summary bit is set, so try to
/* Software-completion summary bit is set, so try to
emulate the instruction. */
emulate the instruction. If the processor supports
if
(
!
amask
(
AMASK_PRECISE_TRAP
))
{
precise exceptions, we don't have to search. */
/* 21264 (except pass 1) has precise exceptions. */
if
(
!
amask
(
AMASK_PRECISE_TRAP
))
if
(
alpha_fp_emul
(
regs
.
pc
-
4
))
si_code
=
alpha_fp_emul
(
regs
.
pc
-
4
);
return
;
else
}
else
{
si_code
=
alpha_fp_emul_imprecise
(
&
regs
,
write_mask
);
if
(
alpha_fp_emul_imprecise
(
&
regs
,
write_mask
))
return
;
}
}
}
#if 0
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel
(
"Arithmetic fault"
,
&
regs
,
0
,
0
);
die_if_kernel
(
"Arithmetic fault"
,
&
regs
,
0
,
0
);
send_sig
(
SIGFPE
,
current
,
1
);
info
.
si_signo
=
SIGFPE
;
info
.
si_errno
=
0
;
info
.
si_code
=
si_code
;
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
send_sig_info
(
SIGFPE
,
&
info
,
current
);
}
}
asmlinkage
void
asmlinkage
void
...
@@ -239,6 +239,9 @@ do_entIF(unsigned long type, unsigned long a1,
...
@@ -239,6 +239,9 @@ do_entIF(unsigned long type, unsigned long a1,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a5
,
struct
pt_regs
regs
)
unsigned
long
a5
,
struct
pt_regs
regs
)
{
{
siginfo_t
info
;
int
signo
,
code
;
if
(
!
opDEC_testing
||
type
!=
4
)
{
if
(
!
opDEC_testing
||
type
!=
4
)
{
if
(
type
==
1
)
{
if
(
type
==
1
)
{
const
unsigned
int
*
data
const
unsigned
int
*
data
...
@@ -253,55 +256,99 @@ do_entIF(unsigned long type, unsigned long a1,
...
@@ -253,55 +256,99 @@ do_entIF(unsigned long type, unsigned long a1,
switch
(
type
)
{
switch
(
type
)
{
case
0
:
/* breakpoint */
case
0
:
/* breakpoint */
info
.
si_signo
=
SIGTRAP
;
info
.
si_errno
=
0
;
info
.
si_code
=
TRAP_BRKPT
;
info
.
si_trapno
=
0
;
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
if
(
ptrace_cancel_bpt
(
current
))
{
if
(
ptrace_cancel_bpt
(
current
))
{
regs
.
pc
-=
4
;
/* make pc point to former bpt */
regs
.
pc
-=
4
;
/* make pc point to former bpt */
}
}
send_sig
(
SIGTRAP
,
current
,
1
);
send_sig_info
(
SIGTRAP
,
&
info
,
current
);
return
;
return
;
case
1
:
/* bugcheck */
case
1
:
/* bugcheck */
send_sig
(
SIGTRAP
,
current
,
1
);
info
.
si_signo
=
SIGTRAP
;
info
.
si_errno
=
0
;
info
.
si_code
=
__SI_FAULT
;
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
info
.
si_trapno
=
0
;
send_sig_info
(
SIGTRAP
,
&
info
,
current
);
return
;
return
;
case
2
:
/* gentrap */
case
2
:
/* gentrap */
/*
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
* The exception code should be passed on to the signal
info
.
si_trapno
=
regs
.
r16
;
* handler as the second argument. Linux doesn't do that
* yet (also notice that Linux *always* behaves like
* DEC Unix with SA_SIGINFO off; see DEC Unix man page
* for sigaction(2)).
*/
switch
((
long
)
regs
.
r16
)
{
switch
((
long
)
regs
.
r16
)
{
case
GEN_INTOVF
:
case
GEN_INTDIV
:
case
GEN_FLTOVF
:
case
GEN_INTOVF
:
case
GEN_FLTDIV
:
case
GEN_FLTUND
:
case
GEN_FLTINV
:
signo
=
SIGFPE
;
case
GEN_FLTINE
:
case
GEN_ROPRAND
:
code
=
FPE_INTOVF
;
send_sig
(
SIGFPE
,
current
,
1
);
break
;
return
;
case
GEN_INTDIV
:
signo
=
SIGFPE
;
case
GEN_DECOVF
:
code
=
FPE_INTDIV
;
case
GEN_DECDIV
:
break
;
case
GEN_DECINV
:
case
GEN_FLTOVF
:
case
GEN_ASSERTERR
:
signo
=
SIGFPE
;
case
GEN_NULPTRERR
:
code
=
FPE_FLTOVF
;
case
GEN_STKOVF
:
break
;
case
GEN_STRLENERR
:
case
GEN_FLTDIV
:
case
GEN_SUBSTRERR
:
signo
=
SIGFPE
;
case
GEN_RANGERR
:
code
=
FPE_FLTDIV
;
case
GEN_SUBRNG
:
break
;
case
GEN_SUBRNG1
:
case
GEN_FLTUND
:
case
GEN_SUBRNG2
:
signo
=
SIGFPE
;
case
GEN_SUBRNG3
:
code
=
FPE_FLTUND
;
case
GEN_SUBRNG4
:
break
;
case
GEN_SUBRNG5
:
case
GEN_FLTINV
:
case
GEN_SUBRNG6
:
signo
=
SIGFPE
;
case
GEN_SUBRNG7
:
code
=
FPE_FLTINV
;
send_sig
(
SIGTRAP
,
current
,
1
);
break
;
return
;
case
GEN_FLTINE
:
signo
=
SIGFPE
;
code
=
FPE_FLTRES
;
break
;
case
GEN_ROPRAND
:
signo
=
SIGFPE
;
code
=
__SI_FAULT
;
break
;
case
GEN_DECOVF
:
case
GEN_DECDIV
:
case
GEN_DECINV
:
case
GEN_ASSERTERR
:
case
GEN_NULPTRERR
:
case
GEN_STKOVF
:
case
GEN_STRLENERR
:
case
GEN_SUBSTRERR
:
case
GEN_RANGERR
:
case
GEN_SUBRNG
:
case
GEN_SUBRNG1
:
case
GEN_SUBRNG2
:
case
GEN_SUBRNG3
:
case
GEN_SUBRNG4
:
case
GEN_SUBRNG5
:
case
GEN_SUBRNG6
:
case
GEN_SUBRNG7
:
default:
signo
=
SIGTRAP
;
code
=
__SI_FAULT
;
break
;
}
}
break
;
info
.
si_signo
=
signo
;
info
.
si_errno
=
0
;
info
.
si_code
=
code
;
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
send_sig_info
(
signo
,
&
info
,
current
);
return
;
case
4
:
/* opDEC */
case
4
:
/* opDEC */
if
(
implver
()
==
IMPLVER_EV4
)
{
if
(
implver
()
==
IMPLVER_EV4
)
{
long
si_code
;
/* The some versions of SRM do not handle
/* The some versions of SRM do not handle
the opDEC properly - they return the PC of the
the opDEC properly - they return the PC of the
opDEC fault, not the instruction after as the
opDEC fault, not the instruction after as the
...
@@ -309,8 +356,7 @@ do_entIF(unsigned long type, unsigned long a1,
...
@@ -309,8 +356,7 @@ do_entIF(unsigned long type, unsigned long a1,
We do this by intentionally causing an opDEC
We do this by intentionally causing an opDEC
fault during the boot sequence and testing if
fault during the boot sequence and testing if
we get the correct PC. If not, we set a flag
we get the correct PC. If not, we set a flag
to correct it every time through.
to correct it every time through. */
*/
if
(
opDEC_testing
)
{
if
(
opDEC_testing
)
{
if
(
regs
.
pc
==
opDEC_test_pc
)
{
if
(
regs
.
pc
==
opDEC_test_pc
)
{
opDEC_fix
=
4
;
opDEC_fix
=
4
;
...
@@ -324,8 +370,17 @@ do_entIF(unsigned long type, unsigned long a1,
...
@@ -324,8 +370,17 @@ do_entIF(unsigned long type, unsigned long a1,
/* EV4 does not implement anything except normal
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
an illegal instruction. Emulate them. */
if
(
alpha_fp_emul
(
regs
.
pc
-
4
))
si_code
=
alpha_fp_emul
(
regs
.
pc
-
4
);
if
(
si_code
==
0
)
return
;
return
;
if
(
si_code
>
0
)
{
info
.
si_signo
=
SIGFPE
;
info
.
si_errno
=
0
;
info
.
si_code
=
si_code
;
info
.
si_addr
=
(
void
*
)
regs
.
pc
;
send_sig_info
(
SIGFPE
,
&
info
,
current
);
return
;
}
}
}
break
;
break
;
...
@@ -347,7 +402,12 @@ do_entIF(unsigned long type, unsigned long a1,
...
@@ -347,7 +402,12 @@ do_entIF(unsigned long type, unsigned long a1,
default:
/* unexpected instruction-fault type */
default:
/* unexpected instruction-fault type */
;
;
}
}
send_sig
(
SIGILL
,
current
,
1
);
info
.
si_signo
=
SIGILL
;
info
.
si_errno
=
0
;
info
.
si_code
=
ILL_ILLOPC
;
info
.
si_addr
=
regs
.
pc
;
send_sig_info
(
SIGILL
,
&
info
,
current
);
}
}
/* There is an ifdef in the PALcode in MILO that enables a
/* There is an ifdef in the PALcode in MILO that enables a
...
@@ -362,8 +422,15 @@ do_entDbg(unsigned long type, unsigned long a1,
...
@@ -362,8 +422,15 @@ do_entDbg(unsigned long type, unsigned long a1,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a2
,
unsigned
long
a3
,
unsigned
long
a4
,
unsigned
long
a5
,
struct
pt_regs
regs
)
unsigned
long
a5
,
struct
pt_regs
regs
)
{
{
siginfo_t
info
;
die_if_kernel
(
"Instruction fault"
,
&
regs
,
type
,
0
);
die_if_kernel
(
"Instruction fault"
,
&
regs
,
type
,
0
);
force_sig
(
SIGILL
,
current
);
info
.
si_signo
=
SIGILL
;
info
.
si_errno
=
0
;
info
.
si_code
=
ILL_ILLOPC
;
info
.
si_addr
=
regs
.
pc
;
force_sig_info
(
SIGILL
,
&
info
,
current
);
}
}
...
@@ -720,6 +787,7 @@ do_entUnaUser(void * va, unsigned long opcode,
...
@@ -720,6 +787,7 @@ do_entUnaUser(void * va, unsigned long opcode,
unsigned
long
tmp1
,
tmp2
,
tmp3
,
tmp4
;
unsigned
long
tmp1
,
tmp2
,
tmp3
,
tmp4
;
unsigned
long
fake_reg
,
*
reg_addr
=
&
fake_reg
;
unsigned
long
fake_reg
,
*
reg_addr
=
&
fake_reg
;
siginfo_t
info
;
long
error
;
long
error
;
/* Check the UAC bits to decide what the user wants us to do
/* Check the UAC bits to decide what the user wants us to do
...
@@ -984,12 +1052,34 @@ do_entUnaUser(void * va, unsigned long opcode,
...
@@ -984,12 +1052,34 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
give_sigsegv:
regs
->
pc
-=
4
;
/* make pc point to faulting insn */
regs
->
pc
-=
4
;
/* make pc point to faulting insn */
send_sig
(
SIGSEGV
,
current
,
1
);
info
.
si_signo
=
SIGSEGV
;
info
.
si_errno
=
0
;
/* We need to replicate some of the logic in mm/fault.c,
since we don't have access to the fault code in the
exception handling return path. */
if
(
!
__access_ok
((
unsigned
long
)
va
,
0
,
USER_DS
))
info
.
si_code
=
SEGV_ACCERR
;
else
{
struct
mm_struct
*
mm
=
current
->
mm
;
down_read
(
&
mm
->
mmap_sem
);
if
(
find_vma
(
mm
,
(
unsigned
long
)
va
))
info
.
si_code
=
SEGV_ACCERR
;
else
info
.
si_code
=
SEGV_MAPERR
;
up_read
(
&
mm
->
mmap_sem
);
}
info
.
si_addr
=
va
;
send_sig_info
(
SIGSEGV
,
&
info
,
current
);
return
;
return
;
give_sigbus:
give_sigbus:
regs
->
pc
-=
4
;
regs
->
pc
-=
4
;
send_sig
(
SIGBUS
,
current
,
1
);
info
.
si_signo
=
SIGBUS
;
info
.
si_errno
=
0
;
info
.
si_code
=
BUS_ADRALN
;
info
.
si_addr
=
va
;
send_sig_info
(
SIGBUS
,
&
info
,
current
);
return
;
return
;
}
}
...
...
arch/alpha/math-emu/math.c
View file @
68c1e696
...
@@ -86,11 +86,13 @@ void cleanup_module(void)
...
@@ -86,11 +86,13 @@ void cleanup_module(void)
/*
/*
* Emulate the floating point instruction at address PC. Returns 0 if
* Emulate the floating point instruction at address PC. Returns -1 if the
* emulation fails. Notice that the kernel does not and cannot use FP
* instruction to be emulated is illegal (such as with the opDEC trap), else
* regs. This is good because it means that instead of
* the SI_CODE for a SIGFPE signal, else 0 if everything's ok.
* saving/restoring all fp regs, we simply stick the result of the
*
* operation into the appropriate register.
* Notice that the kernel does not and cannot use FP regs. This is good
* because it means that instead of saving/restoring all fp regs, we simply
* stick the result of the operation into the appropriate register.
*/
*/
long
long
alpha_fp_emul
(
unsigned
long
pc
)
alpha_fp_emul
(
unsigned
long
pc
)
...
@@ -102,6 +104,7 @@ alpha_fp_emul (unsigned long pc)
...
@@ -102,6 +104,7 @@ alpha_fp_emul (unsigned long pc)
unsigned
long
fa
,
fb
,
fc
,
func
,
mode
,
src
;
unsigned
long
fa
,
fb
,
fc
,
func
,
mode
,
src
;
unsigned
long
res
,
va
,
vb
,
vc
,
swcr
,
fpcr
;
unsigned
long
res
,
va
,
vb
,
vc
,
swcr
,
fpcr
;
__u32
insn
;
__u32
insn
;
long
si_code
;
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
...
@@ -306,10 +309,19 @@ alpha_fp_emul (unsigned long pc)
...
@@ -306,10 +309,19 @@ alpha_fp_emul (unsigned long pc)
wrfpcr
(
fpcr
);
wrfpcr
(
fpcr
);
/* Do we generate a signal? */
/* Do we generate a signal? */
if
(
_fex
&
swcr
&
IEEE_TRAP_ENABLE_MASK
)
{
_fex
=
_fex
&
swcr
&
IEEE_TRAP_ENABLE_MASK
;
MOD_DEC_USE_COUNT
;
si_code
=
0
;
return
0
;
if
(
_fex
)
{
if
(
_fex
&
IEEE_TRAP_ENABLE_DNO
)
si_code
=
FPE_FLTUND
;
if
(
_fex
&
IEEE_TRAP_ENABLE_INE
)
si_code
=
FPE_FLTRES
;
if
(
_fex
&
IEEE_TRAP_ENABLE_UNF
)
si_code
=
FPE_FLTUND
;
if
(
_fex
&
IEEE_TRAP_ENABLE_OVF
)
si_code
=
FPE_FLTOVF
;
if
(
_fex
&
IEEE_TRAP_ENABLE_DZE
)
si_code
=
FPE_FLTDIV
;
if
(
_fex
&
IEEE_TRAP_ENABLE_INV
)
si_code
=
FPE_FLTINV
;
}
}
MOD_DEC_USE_COUNT
;
return
si_code
;
}
}
/* We used to write the destination register here, but DEC FORTRAN
/* We used to write the destination register here, but DEC FORTRAN
...
@@ -317,20 +329,20 @@ alpha_fp_emul (unsigned long pc)
...
@@ -317,20 +329,20 @@ alpha_fp_emul (unsigned long pc)
immediately after the operations above. */
immediately after the operations above. */
MOD_DEC_USE_COUNT
;
MOD_DEC_USE_COUNT
;
return
1
;
return
0
;
bad_insn:
bad_insn:
printk
(
KERN_ERR
"alpha_fp_emul: Invalid FP insn %#x at %#lx
\n
"
,
printk
(
KERN_ERR
"alpha_fp_emul: Invalid FP insn %#x at %#lx
\n
"
,
insn
,
pc
);
insn
,
pc
);
MOD_DEC_USE_COUNT
;
MOD_DEC_USE_COUNT
;
return
0
;
return
-
1
;
}
}
long
long
alpha_fp_emul_imprecise
(
struct
pt_regs
*
regs
,
unsigned
long
write_mask
)
alpha_fp_emul_imprecise
(
struct
pt_regs
*
regs
,
unsigned
long
write_mask
)
{
{
unsigned
long
trigger_pc
=
regs
->
pc
-
4
;
unsigned
long
trigger_pc
=
regs
->
pc
-
4
;
unsigned
long
insn
,
opcode
,
rc
,
no_signal
=
0
;
unsigned
long
insn
,
opcode
,
rc
,
si_code
=
0
;
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
...
@@ -384,7 +396,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
...
@@ -384,7 +396,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
if
(
!
write_mask
)
{
if
(
!
write_mask
)
{
/* Re-execute insns in the trap-shadow. */
/* Re-execute insns in the trap-shadow. */
regs
->
pc
=
trigger_pc
+
4
;
regs
->
pc
=
trigger_pc
+
4
;
no_signal
=
alpha_fp_emul
(
trigger_pc
);
si_code
=
alpha_fp_emul
(
trigger_pc
);
goto
egress
;
goto
egress
;
}
}
trigger_pc
-=
4
;
trigger_pc
-=
4
;
...
@@ -392,5 +404,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
...
@@ -392,5 +404,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
egress:
egress:
MOD_DEC_USE_COUNT
;
MOD_DEC_USE_COUNT
;
return
no_signal
;
return
si_code
;
}
}
arch/alpha/mm/fault.c
View file @
68c1e696
...
@@ -89,7 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
...
@@ -89,7 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
struct
vm_area_struct
*
vma
;
struct
vm_area_struct
*
vma
;
struct
mm_struct
*
mm
=
current
->
mm
;
struct
mm_struct
*
mm
=
current
->
mm
;
unsigned
int
fixup
;
unsigned
int
fixup
;
int
fault
;
int
fault
,
si_code
=
SEGV_MAPERR
;
siginfo_t
info
;
/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
(or is suppressed by the PALcode). Support that for older CPUs
(or is suppressed by the PALcode). Support that for older CPUs
...
@@ -129,6 +130,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
...
@@ -129,6 +130,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* Ok, we have a good vm_area for this memory access, so
/* Ok, we have a good vm_area for this memory access, so
we can handle it. */
we can handle it. */
good_area:
good_area:
si_code
=
SEGV_ACCERR
;
if
(
cause
<
0
)
{
if
(
cause
<
0
)
{
if
(
!
(
vma
->
vm_flags
&
VM_EXEC
))
if
(
!
(
vma
->
vm_flags
&
VM_EXEC
))
goto
bad_area
;
goto
bad_area
;
...
@@ -148,10 +150,20 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
...
@@ -148,10 +150,20 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
fault
=
handle_mm_fault
(
mm
,
vma
,
address
,
cause
>
0
);
fault
=
handle_mm_fault
(
mm
,
vma
,
address
,
cause
>
0
);
up_read
(
&
mm
->
mmap_sem
);
up_read
(
&
mm
->
mmap_sem
);
if
(
fault
<
0
)
switch
(
fault
)
{
goto
out_of_memory
;
case
VM_FAULT_MINOR
:
if
(
fault
==
0
)
current
->
min_flt
++
;
break
;
case
VM_FAULT_MAJOR
:
current
->
maj_flt
++
;
break
;
case
VM_FAULT_SIGBUS
:
goto
do_sigbus
;
goto
do_sigbus
;
case
VM_FAULT_OOM
:
goto
out_of_memory
;
default:
BUG
();
}
return
;
return
;
/* Something tried to access memory that isn't in our memory map.
/* Something tried to access memory that isn't in our memory map.
...
@@ -159,20 +171,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
...
@@ -159,20 +171,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
bad_area:
bad_area:
up_read
(
&
mm
->
mmap_sem
);
up_read
(
&
mm
->
mmap_sem
);
if
(
user_mode
(
regs
))
{
if
(
user_mode
(
regs
))
force_sig
(
SIGSEGV
,
current
);
goto
do_sigsegv
;
return
;
}
no_context:
no_context:
/* Are we prepared to handle this fault as an exception? */
/* Are we prepared to handle this fault as an exception? */
if
((
fixup
=
search_exception_table
(
regs
->
pc
,
regs
->
gp
))
!=
0
)
{
if
((
fixup
=
search_exception_table
(
regs
->
pc
,
regs
->
gp
))
!=
0
)
{
unsigned
long
newpc
;
unsigned
long
newpc
;
newpc
=
fixup_exception
(
dpf_reg
,
fixup
,
regs
->
pc
);
newpc
=
fixup_exception
(
dpf_reg
,
fixup
,
regs
->
pc
);
#if 0
printk("%s: Exception at [<%lx>] (%lx) handled successfully\n",
current->comm, regs->pc, newpc);
#endif
regs
->
pc
=
newpc
;
regs
->
pc
=
newpc
;
return
;
return
;
}
}
...
@@ -201,17 +207,28 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
...
@@ -201,17 +207,28 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
do_sigbus:
do_sigbus:
/* Send a sigbus, regardless of whether we were in kernel
/* Send a sigbus, regardless of whether we were in kernel
or user mode. */
or user mode. */
force_sig
(
SIGBUS
,
current
);
info
.
si_signo
=
SIGBUS
;
info
.
si_errno
=
0
;
info
.
si_code
=
BUS_ADRERR
;
info
.
si_addr
=
(
void
*
)
address
;
force_sig_info
(
SIGBUS
,
&
info
,
current
);
if
(
!
user_mode
(
regs
))
if
(
!
user_mode
(
regs
))
goto
no_context
;
goto
no_context
;
return
;
return
;
do_sigsegv:
info
.
si_signo
=
SIGSEGV
;
info
.
si_errno
=
0
;
info
.
si_code
=
si_code
;
info
.
si_addr
=
(
void
*
)
address
;
force_sig_info
(
SIGSEGV
,
&
info
,
current
);
return
;
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
vmalloc_fault:
vmalloc_fault:
if
(
user_mode
(
regs
))
{
if
(
user_mode
(
regs
))
force_sig
(
SIGSEGV
,
current
);
goto
do_sigsegv
;
return
;
else
{
}
else
{
/* Synchronize this task's top level page-table
/* Synchronize this task's top level page-table
with the "reference" page table from init. */
with the "reference" page table from init. */
long
offset
=
__pgd_offset
(
address
);
long
offset
=
__pgd_offset
(
address
);
...
...
include/asm-alpha/siginfo.h
View file @
68c1e696
#ifndef _ALPHA_SIGINFO_H
#ifndef _ALPHA_SIGINFO_H
#define _ALPHA_SIGINFO_H
#define _ALPHA_SIGINFO_H
#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4)
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define __ARCH_SI_TRAPNO
#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
#define HAVE_ARCH_COPY_SIGINFO
#include <asm-generic/siginfo.h>
#include <asm-generic/siginfo.h>
#ifdef __KERNEL__
#include <linux/string.h>
extern
inline
void
copy_siginfo
(
siginfo_t
*
to
,
siginfo_t
*
from
)
{
if
(
from
->
si_code
<
0
)
memcpy
(
to
,
from
,
sizeof
(
siginfo_t
));
else
/* _sigchld is currently the largest know union member */
memcpy
(
to
,
from
,
4
*
sizeof
(
int
)
+
sizeof
(
from
->
_sifields
.
_sigchld
));
}
#endif
/* __KERNEL__ */
#endif
#endif
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