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
cee48bdc
Commit
cee48bdc
authored
Apr 07, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sparc64 math-emu fix:
- UltraSPARC-III can generate unfinished FPops for F{I,X}TO{S,D} so handle it.
parent
bb573986
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
58 additions
and
38 deletions
+58
-38
arch/sparc64/math-emu/math.c
arch/sparc64/math-emu/math.c
+58
-38
No files found.
arch/sparc64/math-emu/math.c
View file @
cee48bdc
/* $Id: math.c,v 1.1
2 2002/02/09 19:49:31
davem Exp $
/* $Id: math.c,v 1.1
1 1999/12/20 05:02:25
davem Exp $
* arch/sparc64/math-emu/math.c
*
* Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
...
...
@@ -10,7 +10,6 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/fpumacro.h>
#include <asm/ptrace.h>
...
...
@@ -58,6 +57,12 @@
#define FSTOD 0x0c9
#define FSTOI 0x0d1
#define FDTOI 0x0d2
#define FXTOS 0x084
/* Only Ultra-III generates this. */
#define FXTOD 0x088
/* Only Ultra-III generates this. */
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
#define FITOS 0x0c4 /* Only Ultra-III generates this. */
#endif
#define FITOD 0x0c8
/* Only Ultra-III generates this. */
/* FPOP2 */
#define FCMPQ 0x053
#define FCMPEQ 0x057
...
...
@@ -91,25 +96,25 @@
*/
static
inline
int
record_exception
(
struct
pt_regs
*
regs
,
int
eflag
)
{
u64
fsr
=
current
_thread_info
()
->
xfsr
[
0
];
u64
fsr
=
current
->
thread
.
xfsr
[
0
];
int
would_trap
;
/* Determine if this exception would have generated a trap. */
would_trap
=
(
fsr
&
((
long
)
eflag
<<
FSR_TEM_SHIFT
))
!=
0UL
;
/* If trapping, we only want to signal one bit. */
if
(
would_trap
!=
0
)
{
if
(
would_trap
!=
0
)
{
eflag
&=
((
fsr
&
FSR_TEM_MASK
)
>>
FSR_TEM_SHIFT
);
if
((
eflag
&
(
eflag
-
1
))
!=
0
)
{
if
(
eflag
&
FP_EX_INVALID
)
if
((
eflag
&
(
eflag
-
1
))
!=
0
)
{
if
(
eflag
&
FP_EX_INVALID
)
eflag
=
FP_EX_INVALID
;
else
if
(
eflag
&
FP_EX_OVERFLOW
)
else
if
(
eflag
&
FP_EX_OVERFLOW
)
eflag
=
FP_EX_OVERFLOW
;
else
if
(
eflag
&
FP_EX_UNDERFLOW
)
else
if
(
eflag
&
FP_EX_UNDERFLOW
)
eflag
=
FP_EX_UNDERFLOW
;
else
if
(
eflag
&
FP_EX_DIVZERO
)
else
if
(
eflag
&
FP_EX_DIVZERO
)
eflag
=
FP_EX_DIVZERO
;
else
if
(
eflag
&
FP_EX_INEXACT
)
else
if
(
eflag
&
FP_EX_INEXACT
)
eflag
=
FP_EX_INEXACT
;
}
}
...
...
@@ -129,19 +134,19 @@ static inline int record_exception(struct pt_regs *regs, int eflag)
* CEXC just generated is OR'd into the
* existing value of AEXC.
*/
if
(
would_trap
==
0
)
if
(
would_trap
==
0
)
fsr
|=
((
long
)
eflag
<<
FSR_AEXC_SHIFT
);
/* If trapping, indicate fault trap type IEEE. */
if
(
would_trap
!=
0
)
if
(
would_trap
!=
0
)
fsr
|=
(
1UL
<<
14
);
current
_thread_info
()
->
xfsr
[
0
]
=
fsr
;
current
->
thread
.
xfsr
[
0
]
=
fsr
;
/* If we will not trap, advance the program counter over
* the instruction being handled.
*/
if
(
would_trap
==
0
)
{
if
(
would_trap
==
0
)
{
regs
->
tpc
=
regs
->
tnpc
;
regs
->
tnpc
+=
4
;
}
...
...
@@ -175,10 +180,10 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
int
IR
;
long
XR
,
xfsr
;
if
(
tstate
&
TSTATE_PRIV
)
die_if_kernel
(
"
FPQuad
from kernel"
,
regs
);
if
(
test_thread_flag
(
TIF_32BIT
)
)
pc
&=
0xffffffff
;
if
(
tstate
&
TSTATE_PRIV
)
die_if_kernel
(
"
unfinished/unimplemented FPop
from kernel"
,
regs
);
if
(
current
->
thread
.
flags
&
SPARC_FLAG_32BIT
)
pc
=
(
u32
)
pc
;
if
(
get_user
(
insn
,
(
u32
*
)
pc
)
!=
-
EFAULT
)
{
if
((
insn
&
0xc1f80000
)
==
0x81a00000
)
/* FPOP1 */
{
switch
((
insn
>>
5
)
&
0x1ff
)
{
...
...
@@ -218,6 +223,14 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
case
FSTOD
:
TYPE
(
2
,
2
,
1
,
1
,
1
,
0
,
0
);
break
;
case
FSTOI
:
TYPE
(
2
,
1
,
0
,
1
,
1
,
0
,
0
);
break
;
case
FDTOI
:
TYPE
(
2
,
1
,
0
,
2
,
1
,
0
,
0
);
break
;
/* Only Ultra-III generates these */
case
FXTOS
:
TYPE
(
2
,
1
,
1
,
2
,
0
,
0
,
0
);
break
;
case
FXTOD
:
TYPE
(
2
,
2
,
1
,
2
,
0
,
0
,
0
);
break
;
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
case FITOS: TYPE(2,1,1,1,0,0,0); break;
#endif
case
FITOD
:
TYPE
(
2
,
2
,
1
,
1
,
0
,
0
,
0
);
break
;
}
}
else
if
((
insn
&
0xc1f80000
)
==
0x81a80000
)
/* FPOP2 */
{
...
...
@@ -232,9 +245,9 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
case
FMOVQ3
:
/* fmovq %fccX, %fY, %fZ */
if
(
!
((
insn
>>
11
)
&
3
))
XR
=
current
_thread_info
()
->
xfsr
[
0
]
>>
10
;
XR
=
current
->
thread
.
xfsr
[
0
]
>>
10
;
else
XR
=
current
_thread_info
()
->
xfsr
[
0
]
>>
(
30
+
((
insn
>>
10
)
&
0x6
));
XR
=
current
->
thread
.
xfsr
[
0
]
>>
(
30
+
((
insn
>>
10
)
&
0x6
));
XR
&=
3
;
IR
=
0
;
switch
((
insn
>>
14
)
&
0x7
)
{
...
...
@@ -283,7 +296,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
XR
=
0
;
else
if
(
freg
<
16
)
XR
=
regs
->
u_regs
[
freg
];
else
if
(
test_thread_flag
(
TIF_32BIT
)
)
{
else
if
(
current
->
thread
.
flags
&
SPARC_FLAG_32BIT
)
{
struct
reg_window32
*
win32
;
flushw_user
();
win32
=
(
struct
reg_window32
*
)((
unsigned
long
)((
u32
)
regs
->
u_regs
[
UREG_FP
]));
...
...
@@ -306,7 +319,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
}
if
(
IR
==
0
)
{
/* The fmov test was false. Do a nop instead */
current
_thread_info
()
->
xfsr
[
0
]
&=
~
(
FSR_CEXC_MASK
);
current
->
thread
.
xfsr
[
0
]
&=
~
(
FSR_CEXC_MASK
);
regs
->
tpc
=
regs
->
tnpc
;
regs
->
tnpc
+=
4
;
return
1
;
...
...
@@ -320,20 +333,20 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
if
(
type
)
{
argp
rs1
=
NULL
,
rs2
=
NULL
,
rd
=
NULL
;
freg
=
(
current
_thread_info
()
->
xfsr
[
0
]
>>
14
)
&
0xf
;
freg
=
(
current
->
thread
.
xfsr
[
0
]
>>
14
)
&
0xf
;
if
(
freg
!=
(
type
>>
9
))
goto
err
;
current
_thread_info
()
->
xfsr
[
0
]
&=
~
0x1c000
;
current
->
thread
.
xfsr
[
0
]
&=
~
0x1c000
;
freg
=
((
insn
>>
14
)
&
0x1f
);
switch
(
type
&
0x3
)
{
case
3
:
if
(
freg
&
2
)
{
current
_thread_info
()
->
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
current
->
thread
.
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
goto
err
;
}
case
2
:
freg
=
((
freg
&
1
)
<<
5
)
|
(
freg
&
0x1e
);
case
1
:
rs1
=
(
argp
)
&
f
->
regs
[
freg
];
flags
=
(
freg
<
32
)
?
FPRS_DL
:
FPRS_DU
;
if
(
!
(
current
_thread_info
()
->
fpsaved
[
0
]
&
flags
))
if
(
!
(
current
->
thread
.
fpsaved
[
0
]
&
flags
))
rs1
=
(
argp
)
&
zero
;
break
;
}
...
...
@@ -345,13 +358,13 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
freg
=
(
insn
&
0x1f
);
switch
((
type
>>
3
)
&
0x3
)
{
case
3
:
if
(
freg
&
2
)
{
current
_thread_info
()
->
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
current
->
thread
.
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
goto
err
;
}
case
2
:
freg
=
((
freg
&
1
)
<<
5
)
|
(
freg
&
0x1e
);
case
1
:
rs2
=
(
argp
)
&
f
->
regs
[
freg
];
flags
=
(
freg
<
32
)
?
FPRS_DL
:
FPRS_DU
;
if
(
!
(
current
_thread_info
()
->
fpsaved
[
0
]
&
flags
))
if
(
!
(
current
->
thread
.
fpsaved
[
0
]
&
flags
))
rs2
=
(
argp
)
&
zero
;
break
;
}
...
...
@@ -363,23 +376,23 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
freg
=
((
insn
>>
25
)
&
0x1f
);
switch
((
type
>>
6
)
&
0x3
)
{
case
3
:
if
(
freg
&
2
)
{
current
_thread_info
()
->
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
current
->
thread
.
xfsr
[
0
]
|=
(
6
<<
14
)
/* invalid_fp_register */
;
goto
err
;
}
case
2
:
freg
=
((
freg
&
1
)
<<
5
)
|
(
freg
&
0x1e
);
case
1
:
rd
=
(
argp
)
&
f
->
regs
[
freg
];
flags
=
(
freg
<
32
)
?
FPRS_DL
:
FPRS_DU
;
if
(
!
(
current
_thread_info
()
->
fpsaved
[
0
]
&
FPRS_FEF
))
{
current
_thread_info
()
->
fpsaved
[
0
]
=
FPRS_FEF
;
current
_thread_info
()
->
gsr
[
0
]
=
0
;
if
(
!
(
current
->
thread
.
fpsaved
[
0
]
&
FPRS_FEF
))
{
current
->
thread
.
fpsaved
[
0
]
=
FPRS_FEF
;
current
->
thread
.
gsr
[
0
]
=
0
;
}
if
(
!
(
current
_thread_info
()
->
fpsaved
[
0
]
&
flags
))
{
if
(
!
(
current
->
thread
.
fpsaved
[
0
]
&
flags
))
{
if
(
freg
<
32
)
memset
(
f
->
regs
,
0
,
32
*
sizeof
(
u32
));
else
memset
(
f
->
regs
+
32
,
0
,
32
*
sizeof
(
u32
));
}
current
_thread_info
()
->
fpsaved
[
0
]
|=
flags
;
current
->
thread
.
fpsaved
[
0
]
|=
flags
;
break
;
}
switch
((
insn
>>
5
)
&
0x1ff
)
{
...
...
@@ -421,6 +434,13 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
/* int to float */
case
FITOQ
:
IR
=
rs2
->
s
;
FP_FROM_INT_Q
(
QR
,
IR
,
32
,
int
);
break
;
case
FXTOQ
:
XR
=
rs2
->
d
;
FP_FROM_INT_Q
(
QR
,
XR
,
64
,
long
);
break
;
/* Only Ultra-III generates these */
case
FXTOS
:
XR
=
rs2
->
d
;
FP_FROM_INT_S
(
SR
,
XR
,
64
,
long
);
break
;
case
FXTOD
:
XR
=
rs2
->
d
;
FP_FROM_INT_D
(
DR
,
XR
,
64
,
long
);
break
;
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break;
#endif
case
FITOD
:
IR
=
rs2
->
s
;
FP_FROM_INT_D
(
DR
,
IR
,
32
,
int
);
break
;
/* float to float */
case
FSTOD
:
FP_CONV
(
D
,
S
,
1
,
1
,
DR
,
SB
);
break
;
case
FSTOQ
:
FP_CONV
(
Q
,
S
,
2
,
1
,
QR
,
SB
);
break
;
...
...
@@ -440,7 +460,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
}
if
(
!
FP_INHIBIT_RESULTS
)
{
switch
((
type
>>
6
)
&
0x7
)
{
case
0
:
xfsr
=
current
_thread_info
()
->
xfsr
[
0
];
case
0
:
xfsr
=
current
->
thread
.
xfsr
[
0
];
if
(
XR
==
-
1
)
XR
=
2
;
switch
(
freg
&
3
)
{
/* fcc0, 1, 2, 3 */
...
...
@@ -449,7 +469,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
case
2
:
xfsr
&=
~
0xc00000000UL
;
xfsr
|=
(
XR
<<
34
);
break
;
case
3
:
xfsr
&=
~
0x3000000000UL
;
xfsr
|=
(
XR
<<
36
);
break
;
}
current
_thread_info
()
->
xfsr
[
0
]
=
xfsr
;
current
->
thread
.
xfsr
[
0
]
=
xfsr
;
break
;
case
1
:
rd
->
s
=
IR
;
break
;
case
2
:
rd
->
d
=
XR
;
break
;
...
...
@@ -459,11 +479,11 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
}
}
if
(
_fex
!=
0
)
if
(
_fex
!=
0
)
return
record_exception
(
regs
,
_fex
);
/* Success and no exceptions detected. */
current
_thread_info
()
->
xfsr
[
0
]
&=
~
(
FSR_CEXC_MASK
);
current
->
thread
.
xfsr
[
0
]
&=
~
(
FSR_CEXC_MASK
);
regs
->
tpc
=
regs
->
tnpc
;
regs
->
tnpc
+=
4
;
return
1
;
...
...
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