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
febda3e4
Commit
febda3e4
authored
Mar 17, 2002
by
Anton Blanchard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ppc64: Alignment handler fixes - from Mike Corrigan
parent
1da1ba1a
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
190 additions
and
169 deletions
+190
-169
arch/ppc64/kernel/align.c
arch/ppc64/kernel/align.c
+190
-169
No files found.
arch/ppc64/kernel/align.c
View file @
febda3e4
/*
/* align.c - handle alignment exceptions for the Power PC.
* align.c - handle alignment exceptions for the Power PC.
*
*
* Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
* Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
* Copyright (c) 1998-1999 TiVo, Inc.
* Copyright (c) 1998-1999 TiVo, Inc.
* PowerPC 403GCX modifications.
* PowerPC 403GCX modifications.
* Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
* Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
* PowerPC 403GCX/405GP modifications.
* PowerPC 403GCX/405GP modifications.
* Copyright (c) 2001 PPC64 team, IBM Corp
* Copyright (c) 2001-2002 PPC64 team, IBM Corp
* 64-bit and Power4 support
*
*
* This program is free software; you can redistribute it and/or
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* modify it under the terms of the GNU General Public License
...
@@ -27,10 +27,8 @@ struct aligninfo {
...
@@ -27,10 +27,8 @@ struct aligninfo {
unsigned
char
flags
;
unsigned
char
flags
;
};
};
#define OPCD(inst) (((inst) & 0xFC000000) >> 26)
#define IS_XFORM(inst) (((inst) >> 26) == 31)
#define RS(inst) (((inst) & 0x03E00000) >> 21)
#define IS_DSFORM(inst) (((inst) >> 26) >= 56)
#define RA(inst) (((inst) & 0x001F0000) >> 16)
#define IS_DFORM(code) ((code) >= 32 && (code) <= 47)
#define INVALID { 0, 0 }
#define INVALID { 0, 0 }
...
@@ -40,9 +38,7 @@ struct aligninfo {
...
@@ -40,9 +38,7 @@ struct aligninfo {
#define F 8
/* to/from fp regs */
#define F 8
/* to/from fp regs */
#define U 0x10
/* update index register */
#define U 0x10
/* update index register */
#define M 0x20
/* multiple load/store */
#define M 0x20
/* multiple load/store */
#define S 0x40
/* single-precision fp, or byte-swap value */
#define SW 0x40
/* byte swap */
#define HARD 0x80
/* string, stwcx. */
#define D 0x100
/* double-word load/store */
#define DCBZ 0x5f
/* 8xx/82xx dcbz faults when cache not enabled */
#define DCBZ 0x5f
/* 8xx/82xx dcbz faults when cache not enabled */
...
@@ -61,9 +57,9 @@ static struct aligninfo aligninfo[128] = {
...
@@ -61,9 +57,9 @@ static struct aligninfo aligninfo[128] = {
{
2
,
LD
+
SE
},
/* 00 0 0101: lha */
{
2
,
LD
+
SE
},
/* 00 0 0101: lha */
{
2
,
ST
},
/* 00 0 0110: sth */
{
2
,
ST
},
/* 00 0 0110: sth */
{
4
,
LD
+
M
},
/* 00 0 0111: lmw */
{
4
,
LD
+
M
},
/* 00 0 0111: lmw */
{
4
,
LD
+
F
+
S
},
/* 00 0 1000: lfs */
{
4
,
LD
+
F
},
/* 00 0 1000: lfs */
{
8
,
LD
+
F
},
/* 00 0 1001: lfd */
{
8
,
LD
+
F
},
/* 00 0 1001: lfd */
{
4
,
ST
+
F
+
S
},
/* 00 0 1010: stfs */
{
4
,
ST
+
F
},
/* 00 0 1010: stfs */
{
8
,
ST
+
F
},
/* 00 0 1011: stfd */
{
8
,
ST
+
F
},
/* 00 0 1011: stfd */
INVALID
,
/* 00 0 1100 */
INVALID
,
/* 00 0 1100 */
{
8
,
LD
},
/* 00 0 1101: ld */
{
8
,
LD
},
/* 00 0 1101: ld */
...
@@ -77,12 +73,12 @@ static struct aligninfo aligninfo[128] = {
...
@@ -77,12 +73,12 @@ static struct aligninfo aligninfo[128] = {
{
2
,
LD
+
SE
+
U
},
/* 00 1 0101: lhau */
{
2
,
LD
+
SE
+
U
},
/* 00 1 0101: lhau */
{
2
,
ST
+
U
},
/* 00 1 0110: sthu */
{
2
,
ST
+
U
},
/* 00 1 0110: sthu */
{
4
,
ST
+
M
},
/* 00 1 0111: stmw */
{
4
,
ST
+
M
},
/* 00 1 0111: stmw */
{
4
,
LD
+
F
+
S
+
U
},
/* 00 1 1000: lfsu */
{
4
,
LD
+
F
+
U
},
/* 00 1 1000: lfsu */
{
8
,
LD
+
F
+
U
},
/* 00 1 1001: lfdu */
{
8
,
LD
+
F
+
U
},
/* 00 1 1001: lfdu */
{
4
,
ST
+
F
+
S
+
U
},
/* 00 1 1010: stfsu */
{
4
,
ST
+
F
+
U
},
/* 00 1 1010: stfsu */
{
8
,
ST
+
F
+
U
},
/* 00 1 1011: stfdu */
{
8
,
ST
+
F
+
U
},
/* 00 1 1011: stfdu */
INVALID
,
/* 00 1 1100 */
INVALID
,
/* 00 1 1100 */
{
8
,
ST
},
/* 00 1 1101: std
*/
INVALID
,
/* 00 1 1101
*/
INVALID
,
/* 00 1 1110 */
INVALID
,
/* 00 1 1110 */
INVALID
,
/* 00 1 1111 */
INVALID
,
/* 00 1 1111 */
{
8
,
LD
},
/* 01 0 0000: ldx */
{
8
,
LD
},
/* 01 0 0000: ldx */
...
@@ -90,13 +86,13 @@ static struct aligninfo aligninfo[128] = {
...
@@ -90,13 +86,13 @@ static struct aligninfo aligninfo[128] = {
{
8
,
ST
},
/* 01 0 0010: stdx */
{
8
,
ST
},
/* 01 0 0010: stdx */
INVALID
,
/* 01 0 0011 */
INVALID
,
/* 01 0 0011 */
INVALID
,
/* 01 0 0100 */
INVALID
,
/* 01 0 0100 */
INVALID
,
/* 01 0 0101: lwax??
*/
{
4
,
LD
+
SE
},
/* 01 0 0101: lwax
*/
INVALID
,
/* 01 0 0110 */
INVALID
,
/* 01 0 0110 */
INVALID
,
/* 01 0 0111 */
INVALID
,
/* 01 0 0111 */
{
0
,
LD
+
HARD
},
/* 01 0 1000: lswx */
{
0
,
LD
},
/* 01 0 1000: lswx */
{
0
,
LD
+
HARD
},
/* 01 0 1001: lswi */
{
0
,
LD
},
/* 01 0 1001: lswi */
{
0
,
ST
+
HARD
},
/* 01 0 1010: stswx */
{
0
,
ST
},
/* 01 0 1010: stswx */
{
0
,
ST
+
HARD
},
/* 01 0 1011: stswi */
{
0
,
ST
},
/* 01 0 1011: stswi */
INVALID
,
/* 01 0 1100 */
INVALID
,
/* 01 0 1100 */
{
8
,
LD
+
U
},
/* 01 0 1101: ldu */
{
8
,
LD
+
U
},
/* 01 0 1101: ldu */
INVALID
,
/* 01 0 1110 */
INVALID
,
/* 01 0 1110 */
...
@@ -106,7 +102,7 @@ static struct aligninfo aligninfo[128] = {
...
@@ -106,7 +102,7 @@ static struct aligninfo aligninfo[128] = {
{
8
,
ST
+
U
},
/* 01 1 0010: stdux */
{
8
,
ST
+
U
},
/* 01 1 0010: stdux */
INVALID
,
/* 01 1 0011 */
INVALID
,
/* 01 1 0011 */
INVALID
,
/* 01 1 0100 */
INVALID
,
/* 01 1 0100 */
INVALID
,
/* 01 1 0101: lwaux??
*/
{
4
,
LD
+
SE
+
U
},
/* 01 1 0101: lwaux
*/
INVALID
,
/* 01 1 0110 */
INVALID
,
/* 01 1 0110 */
INVALID
,
/* 01 1 0111 */
INVALID
,
/* 01 1 0111 */
INVALID
,
/* 01 1 1000 */
INVALID
,
/* 01 1 1000 */
...
@@ -119,19 +115,19 @@ static struct aligninfo aligninfo[128] = {
...
@@ -119,19 +115,19 @@ static struct aligninfo aligninfo[128] = {
INVALID
,
/* 01 1 1111 */
INVALID
,
/* 01 1 1111 */
INVALID
,
/* 10 0 0000 */
INVALID
,
/* 10 0 0000 */
INVALID
,
/* 10 0 0001 */
INVALID
,
/* 10 0 0001 */
{
0
,
ST
+
HARD
},
/* 10 0 0010: stwcx. */
{
0
,
ST
},
/* 10 0 0010: stwcx. */
INVALID
,
/* 10 0 0011 */
INVALID
,
/* 10 0 0011 */
INVALID
,
/* 10 0 0100 */
INVALID
,
/* 10 0 0100 */
INVALID
,
/* 10 0 0101 */
INVALID
,
/* 10 0 0101 */
INVALID
,
/* 10 0 0110 */
INVALID
,
/* 10 0 0110 */
INVALID
,
/* 10 0 0111 */
INVALID
,
/* 10 0 0111 */
{
4
,
LD
+
S
},
/* 10 0 1000: lwbrx */
{
4
,
LD
+
S
W
},
/* 10 0 1000: lwbrx */
INVALID
,
/* 10 0 1001 */
INVALID
,
/* 10 0 1001 */
{
4
,
ST
+
S
},
/* 10 0 1010: stwbrx */
{
4
,
ST
+
S
W
},
/* 10 0 1010: stwbrx */
INVALID
,
/* 10 0 1011 */
INVALID
,
/* 10 0 1011 */
{
2
,
LD
+
S
},
/* 10 0 1100: lhbrx */
{
2
,
LD
+
S
W
},
/* 10 0 1100: lhbrx */
INVALID
,
/* 10 0 1101
*/
{
4
,
LD
+
SE
},
/* 10 0 1101 lwa
*/
{
2
,
ST
+
S
},
/* 10 0 1110: sthbrx */
{
2
,
ST
+
S
W
},
/* 10 0 1110: sthbrx */
INVALID
,
/* 10 0 1111 */
INVALID
,
/* 10 0 1111 */
INVALID
,
/* 10 1 0000 */
INVALID
,
/* 10 1 0000 */
INVALID
,
/* 10 1 0001 */
INVALID
,
/* 10 1 0001 */
...
@@ -148,7 +144,7 @@ static struct aligninfo aligninfo[128] = {
...
@@ -148,7 +144,7 @@ static struct aligninfo aligninfo[128] = {
INVALID
,
/* 10 1 1100 */
INVALID
,
/* 10 1 1100 */
INVALID
,
/* 10 1 1101 */
INVALID
,
/* 10 1 1101 */
INVALID
,
/* 10 1 1110 */
INVALID
,
/* 10 1 1110 */
{
0
,
ST
+
HARD
},
/* 10 1 1111: dcbz */
{
L1_CACHE_BYTES
,
ST
},
/* 10 1 1111: dcbz */
{
4
,
LD
},
/* 11 0 0000: lwzx */
{
4
,
LD
},
/* 11 0 0000: lwzx */
INVALID
,
/* 11 0 0001 */
INVALID
,
/* 11 0 0001 */
{
4
,
ST
},
/* 11 0 0010: stwx */
{
4
,
ST
},
/* 11 0 0010: stwx */
...
@@ -157,14 +153,14 @@ static struct aligninfo aligninfo[128] = {
...
@@ -157,14 +153,14 @@ static struct aligninfo aligninfo[128] = {
{
2
,
LD
+
SE
},
/* 11 0 0101: lhax */
{
2
,
LD
+
SE
},
/* 11 0 0101: lhax */
{
2
,
ST
},
/* 11 0 0110: sthx */
{
2
,
ST
},
/* 11 0 0110: sthx */
INVALID
,
/* 11 0 0111 */
INVALID
,
/* 11 0 0111 */
{
4
,
LD
+
F
+
S
},
/* 11 0 1000: lfsx */
{
4
,
LD
+
F
},
/* 11 0 1000: lfsx */
{
8
,
LD
+
F
},
/* 11 0 1001: lfdx */
{
8
,
LD
+
F
},
/* 11 0 1001: lfdx */
{
4
,
ST
+
F
+
S
},
/* 11 0 1010: stfsx */
{
4
,
ST
+
F
},
/* 11 0 1010: stfsx */
{
8
,
ST
+
F
},
/* 11 0 1011: stfdx */
{
8
,
ST
+
F
},
/* 11 0 1011: stfdx */
INVALID
,
/* 11 0 1100 */
INVALID
,
/* 11 0 1100 */
INVALID
,
/* 11 0 1101
*/
{
8
,
LD
+
M
},
/* 11 0 1101: lmd
*/
INVALID
,
/* 11 0 1110 */
INVALID
,
/* 11 0 1110 */
INVALID
,
/* 11 0 1111
*/
{
8
,
ST
+
M
},
/* 11 0 1111: stmd
*/
{
4
,
LD
+
U
},
/* 11 1 0000: lwzux */
{
4
,
LD
+
U
},
/* 11 1 0000: lwzux */
INVALID
,
/* 11 1 0001 */
INVALID
,
/* 11 1 0001 */
{
4
,
ST
+
U
},
/* 11 1 0010: stwux */
{
4
,
ST
+
U
},
/* 11 1 0010: stwux */
...
@@ -173,9 +169,9 @@ static struct aligninfo aligninfo[128] = {
...
@@ -173,9 +169,9 @@ static struct aligninfo aligninfo[128] = {
{
2
,
LD
+
SE
+
U
},
/* 11 1 0101: lhaux */
{
2
,
LD
+
SE
+
U
},
/* 11 1 0101: lhaux */
{
2
,
ST
+
U
},
/* 11 1 0110: sthux */
{
2
,
ST
+
U
},
/* 11 1 0110: sthux */
INVALID
,
/* 11 1 0111 */
INVALID
,
/* 11 1 0111 */
{
4
,
LD
+
F
+
S
+
U
},
/* 11 1 1000: lfsux */
{
4
,
LD
+
F
+
U
},
/* 11 1 1000: lfsux */
{
8
,
LD
+
F
+
U
},
/* 11 1 1001: lfdux */
{
8
,
LD
+
F
+
U
},
/* 11 1 1001: lfdux */
{
4
,
ST
+
F
+
S
+
U
},
/* 11 1 1010: stfsux */
{
4
,
ST
+
F
+
U
},
/* 11 1 1010: stfsux */
{
8
,
ST
+
F
+
U
},
/* 11 1 1011: stfdux */
{
8
,
ST
+
F
+
U
},
/* 11 1 1011: stfdux */
INVALID
,
/* 11 1 1100 */
INVALID
,
/* 11 1 1100 */
INVALID
,
/* 11 1 1101 */
INVALID
,
/* 11 1 1101 */
...
@@ -185,73 +181,91 @@ static struct aligninfo aligninfo[128] = {
...
@@ -185,73 +181,91 @@ static struct aligninfo aligninfo[128] = {
#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
unsigned
static
inline
make_dsisr
(
unsigned
instr
)
{
unsigned
dsisr
;
/* create a DSISR value from the instruction */
dsisr
=
(
instr
&
0x03ff0000
)
>>
16
;
/* bits 6:15 --> 22:31 */
if
(
IS_XFORM
(
instr
)
)
{
dsisr
|=
(
instr
&
0x00000006
)
<<
14
;
/* bits 29:30 --> 15:16 */
dsisr
|=
(
instr
&
0x00000040
)
<<
8
;
/* bit 25 --> 17 */
dsisr
|=
(
instr
&
0x00000780
)
<<
3
;
/* bits 21:24 --> 18:21 */
}
else
{
dsisr
|=
(
instr
&
0x04000000
)
>>
12
;
/* bit 5 --> 17 */
dsisr
|=
(
instr
&
0x78000000
)
>>
17
;
/* bits 1: 4 --> 18:21 */
if
(
IS_DSFORM
(
instr
)
)
{
dsisr
|=
(
instr
&
0x00000003
)
<<
18
;
/* bits 30:31 --> 12:13 */
}
}
return
dsisr
;
}
int
int
fix_alignment
(
struct
pt_regs
*
regs
)
fix_alignment
(
struct
pt_regs
*
regs
)
{
{
int
instr
,
nb
,
flags
;
unsigned
int
instr
,
nb
,
flags
;
int
opcode
,
f1
,
f2
,
f3
;
int
t
;
int
i
,
t
;
unsigned
long
reg
,
areg
;
int
reg
,
areg
;
unsigned
long
i
;
unsigned
char
*
addr
;
int
ret
;
unsigned
dsisr
;
unsigned
char
*
addr
,
*
p
;
unsigned
long
*
lp
;
union
{
union
{
int
l
;
long
ll
;
long
ll
;
float
f
;
double
dd
;
double
d
;
unsigned
char
v
[
8
];
unsigned
char
v
[
8
];
struct
{
unsigned
hi32
;
int
low32
;
}
x32
;
struct
{
unsigned
char
hi48
[
6
];
short
low16
;
}
x16
;
}
data
;
}
data
;
if
(
__is_processor
(
PV_POWER4
))
{
/*
/*
* The POWER4 has a DSISR register but doesn't set it on
* Return 1 on success
* an alignment fault. -- paulus
* Return 0 if unable to handle the interrupt
* Return -EFAULT if data address is bad
*/
*/
instr
=
*
((
unsigned
int
*
)
regs
->
nip
);
dsisr
=
regs
->
dsisr
;
opcode
=
OPCD
(
instr
);
reg
=
RS
(
instr
);
areg
=
RA
(
instr
);
if
(
IS_DFORM
(
opcode
))
{
f1
=
0
;
f2
=
(
instr
&
0x04000000
)
>>
26
;
f3
=
(
instr
&
0x78000000
)
>>
27
;
}
else
{
f1
=
(
instr
&
0x00000006
)
>>
1
;
f2
=
(
instr
&
0x00000040
)
>>
6
;
f3
=
(
instr
&
0x00000780
)
>>
7
;
}
instr
=
((
f1
<<
5
)
|
(
f2
<<
4
)
|
f3
);
/* Power4 doesn't set DSISR for an alignment interrupt */
}
else
{
if
(
__is_processor
(
PV_POWER4
))
reg
=
(
regs
->
dsisr
>>
5
)
&
0x1f
;
/* source/dest register */
dsisr
=
make_dsisr
(
*
((
unsigned
*
)
regs
->
nip
)
);
areg
=
regs
->
dsisr
&
0x1f
;
/* register to update */
instr
=
(
regs
->
dsisr
>>
10
)
&
0x7f
;
/* extract the operation and registers from the dsisr */
instr
|=
(
regs
->
dsisr
>>
13
)
&
0x60
;
reg
=
(
dsisr
>>
5
)
&
0x1f
;
/* source/dest register */
}
areg
=
dsisr
&
0x1f
;
/* register to update */
instr
=
(
dsisr
>>
10
)
&
0x7f
;
instr
|=
(
dsisr
>>
13
)
&
0x60
;
/* Lookup the operation in our table */
nb
=
aligninfo
[
instr
].
len
;
nb
=
aligninfo
[
instr
].
len
;
if
(
nb
==
0
)
{
flags
=
aligninfo
[
instr
].
flags
;
long
*
p
;
int
i
;
if
(
instr
!=
DCBZ
)
/* DAR has the operand effective address */
addr
=
(
unsigned
char
*
)
regs
->
dar
;
/* A size of 0 indicates an instruction we don't support */
/* we also don't support the multiples (lmw, stmw, lmd, stmd) */
if
((
nb
==
0
)
||
(
flags
&
M
))
return
0
;
/* too hard or invalid instruction */
return
0
;
/* too hard or invalid instruction */
/*
/*
* The dcbz (data cache block zero) instruction
* Special handling for dcbz
* gives an alignment fault if used on non-cacheable
* dcbz may give an alignment exception for accesses to caching inhibited
* memory. We handle the fault mainly for the
* storage
* case when we are running with the cache disabled
* for debugging.
*/
*/
p
=
(
long
*
)
(
regs
->
dar
&
-
L1_CACHE_BYTES
);
if
(
instr
==
DCBZ
)
for
(
i
=
0
;
i
<
L1_CACHE_BYTES
/
sizeof
(
long
);
++
i
)
addr
=
(
unsigned
char
*
)
((
unsigned
long
)
addr
&
-
L1_CACHE_BYTES
);
p
[
i
]
=
0
;
return
1
;
}
flags
=
aligninfo
[
instr
].
flags
;
addr
=
(
unsigned
char
*
)
regs
->
dar
;
/* Verify the address of the operand */
/* Verify the address of the operand */
if
(
user_mode
(
regs
))
{
if
(
user_mode
(
regs
))
{
...
@@ -259,104 +273,111 @@ fix_alignment(struct pt_regs *regs)
...
@@ -259,104 +273,111 @@ fix_alignment(struct pt_regs *regs)
return
-
EFAULT
;
/* bad address */
return
-
EFAULT
;
/* bad address */
}
}
/* Force the fprs into the save area so we can reference them */
if
((
flags
&
F
)
&&
(
regs
->
msr
&
MSR_FP
))
if
((
flags
&
F
)
&&
(
regs
->
msr
&
MSR_FP
))
giveup_fpu
(
current
);
giveup_fpu
(
current
);
if
(
flags
&
M
)
return
0
;
/* too hard for now */
/* If we
read the operand, copy it in
*/
/* If we
are loading, get the data from user space
*/
if
(
flags
&
LD
)
{
if
(
flags
&
LD
)
{
if
(
nb
==
2
)
{
data
.
ll
=
0
;
data
.
v
[
0
]
=
data
.
v
[
1
]
=
0
;
ret
=
0
;
if
(
__get_user
(
data
.
v
[
2
],
addr
)
p
=
addr
;
||
__get_user
(
data
.
v
[
3
],
addr
+
1
))
switch
(
nb
)
{
return
-
EFAULT
;
case
8
:
}
else
{
ret
|=
__get_user
(
data
.
v
[
0
],
p
++
);
for
(
i
=
0
;
i
<
nb
;
++
i
)
ret
|=
__get_user
(
data
.
v
[
1
],
p
++
);
if
(
__get_user
(
data
.
v
[
i
],
addr
+
i
))
ret
|=
__get_user
(
data
.
v
[
2
],
p
++
);
ret
|=
__get_user
(
data
.
v
[
3
],
p
++
);
case
4
:
ret
|=
__get_user
(
data
.
v
[
4
],
p
++
);
ret
|=
__get_user
(
data
.
v
[
5
],
p
++
);
case
2
:
ret
|=
__get_user
(
data
.
v
[
6
],
p
++
);
ret
|=
__get_user
(
data
.
v
[
7
],
p
++
);
if
(
ret
)
return
-
EFAULT
;
return
-
EFAULT
;
}
}
}
}
/* Unfortunately D (== 0x100) doesn't fit in the aligninfo[n].flags
field. So synthesize it here. */
/* If we are storing, get the data from the saved gpr or fpr */
if
((
flags
&
F
)
==
0
&&
nb
==
8
)
if
(
flags
&
ST
)
{
flags
|=
D
;
if
(
flags
&
F
)
{
if
(
nb
==
4
)
{
switch
(
flags
&
~
U
)
{
/* Doing stfs, have to convert to single */
case
LD
+
SE
:
enable_kernel_fp
();
if
(
data
.
v
[
2
]
>=
0x80
)
cvt_df
(
&
current
->
thread
.
fpr
[
reg
],
(
float
*
)
&
data
.
v
[
4
],
&
current
->
thread
.
fpscr
);
data
.
v
[
0
]
=
data
.
v
[
1
]
=
-
1
;
/* fall through */
case
LD
:
regs
->
gpr
[
reg
]
=
data
.
l
;
break
;
case
LD
+
D
:
regs
->
gpr
[
reg
]
=
data
.
ll
;
break
;
case
LD
+
S
:
if
(
nb
==
2
)
{
SWAP
(
data
.
v
[
2
],
data
.
v
[
3
]);
}
else
{
SWAP
(
data
.
v
[
0
],
data
.
v
[
3
]);
SWAP
(
data
.
v
[
1
],
data
.
v
[
2
]);
}
}
regs
->
gpr
[
reg
]
=
data
.
l
;
else
break
;
data
.
dd
=
current
->
thread
.
fpr
[
reg
];
case
ST
:
}
data
.
l
=
regs
->
gpr
[
reg
];
else
break
;
case
ST
+
D
:
data
.
ll
=
regs
->
gpr
[
reg
];
data
.
ll
=
regs
->
gpr
[
reg
];
break
;
case
ST
+
S
:
data
.
l
=
regs
->
gpr
[
reg
];
if
(
nb
==
2
)
{
SWAP
(
data
.
v
[
2
],
data
.
v
[
3
]);
}
else
{
SWAP
(
data
.
v
[
0
],
data
.
v
[
3
]);
SWAP
(
data
.
v
[
1
],
data
.
v
[
2
]);
}
}
break
;
case
LD
+
F
:
/* Swap bytes as needed */
current
->
thread
.
fpr
[
reg
]
=
data
.
d
;
if
(
flags
&
SW
)
{
break
;
if
(
nb
==
2
)
case
ST
+
F
:
SWAP
(
data
.
v
[
6
],
data
.
v
[
7
]);
data
.
d
=
current
->
thread
.
fpr
[
reg
];
else
{
/* nb must be 4 */
break
;
SWAP
(
data
.
v
[
4
],
data
.
v
[
7
]);
/* these require some floating point conversions... */
SWAP
(
data
.
v
[
5
],
data
.
v
[
6
]);
/* we'd like to use the assignment, but we have to compile
}
* the kernel with -msoft-float so it doesn't use the
}
* fp regs for copying 8-byte objects. */
case
LD
+
F
+
S
:
/* Sign extend as needed */
enable_kernel_fp
();
if
(
flags
&
SE
)
{
cvt_fd
(
&
data
.
f
,
&
current
->
thread
.
fpr
[
reg
],
&
current
->
thread
.
fpscr
);
if
(
nb
==
2
)
/* current->thread.fpr[reg] = data.f; */
data
.
ll
=
data
.
x16
.
low16
;
break
;
else
/* nb must be 4 */
case
ST
+
F
+
S
:
data
.
ll
=
data
.
x32
.
low32
;
}
/* If we are loading, move the data to the gpr or fpr */
if
(
flags
&
LD
)
{
if
(
flags
&
F
)
{
if
(
nb
==
4
)
{
/* Doing lfs, have to convert to double */
enable_kernel_fp
();
enable_kernel_fp
();
cvt_df
(
&
current
->
thread
.
fpr
[
reg
],
&
data
.
f
,
&
current
->
thread
.
fpscr
);
cvt_fd
((
float
*
)
&
data
.
v
[
4
],
&
current
->
thread
.
fpr
[
reg
],
&
current
->
thread
.
fpscr
);
/* data.f = current->thread.fpr[reg]; */
}
break
;
else
default:
current
->
thread
.
fpr
[
reg
]
=
data
.
dd
;
printk
(
"align: can't handle flags=%x
\n
"
,
flags
);
}
return
0
;
else
regs
->
gpr
[
reg
]
=
data
.
ll
;
}
}
/* If we are storing, copy the data to the user */
if
(
flags
&
ST
)
{
if
(
flags
&
ST
)
{
if
(
nb
==
2
)
{
ret
=
0
;
if
(
__put_user
(
data
.
v
[
2
],
addr
)
p
=
addr
;
||
__put_user
(
data
.
v
[
3
],
addr
+
1
))
switch
(
nb
)
{
return
-
EFAULT
;
case
128
:
/* Special case - must be dcbz */
}
else
{
lp
=
(
unsigned
long
*
)
p
;
for
(
i
=
0
;
i
<
nb
;
++
i
)
for
(
i
=
0
;
i
<
L1_CACHE_BYTES
/
sizeof
(
long
);
++
i
)
if
(
__put_user
(
data
.
v
[
i
],
addr
+
i
))
ret
|=
__put_user
(
0
,
lp
++
);
return
-
EFAULT
;
break
;
case
8
:
ret
|=
__put_user
(
data
.
v
[
0
],
p
++
);
ret
|=
__put_user
(
data
.
v
[
1
],
p
++
);
ret
|=
__put_user
(
data
.
v
[
2
],
p
++
);
ret
|=
__put_user
(
data
.
v
[
3
],
p
++
);
case
4
:
ret
|=
__put_user
(
data
.
v
[
4
],
p
++
);
ret
|=
__put_user
(
data
.
v
[
5
],
p
++
);
case
2
:
ret
|=
__put_user
(
data
.
v
[
6
],
p
++
);
ret
|=
__put_user
(
data
.
v
[
7
],
p
++
);
}
}
if
(
ret
)
return
-
EFAULT
;
}
}
/* Update RA as needed */
if
(
flags
&
U
)
{
if
(
flags
&
U
)
{
regs
->
gpr
[
areg
]
=
regs
->
dar
;
regs
->
gpr
[
areg
]
=
regs
->
dar
;
}
}
return
1
;
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