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
2c5db17f
Commit
2c5db17f
authored
Dec 09, 2002
by
David Mosberger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ia64: Fix unaligned memory access handler.
parent
845eaa9b
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
57 additions
and
36 deletions
+57
-36
arch/ia64/kernel/unaligned.c
arch/ia64/kernel/unaligned.c
+57
-36
No files found.
arch/ia64/kernel/unaligned.c
View file @
2c5db17f
...
...
@@ -5,6 +5,10 @@
* Stephane Eranian <eranian@hpl.hp.com>
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* 2002/12/09 Fix rotating register handling (off-by-1 error, missing fr-rotation). Fix
* get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
* stacked register returns an undefined value; it does NOT trigger a
* "rsvd register fault").
* 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops.
* 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes.
* 2001/01/17 Add support emulation of unaligned kernel accesses.
...
...
@@ -276,6 +280,15 @@ invala_fr (int regno)
# undef F
}
static
inline
unsigned
long
rotate_reg
(
unsigned
long
sor
,
unsigned
long
rrb
,
unsigned
long
reg
)
{
reg
+=
rrb
;
if
(
reg
>=
sor
)
reg
-=
sor
;
return
reg
;
}
static
void
set_rse_reg
(
struct
pt_regs
*
regs
,
unsigned
long
r1
,
unsigned
long
val
,
int
nat
)
{
...
...
@@ -287,26 +300,22 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
long
sof
=
(
regs
->
cr_ifs
)
&
0x7f
;
long
sor
=
8
*
((
regs
->
cr_ifs
>>
14
)
&
0xf
);
long
rrb_gr
=
(
regs
->
cr_ifs
>>
18
)
&
0x7f
;
long
ridx
;
if
((
r1
-
32
)
>
sor
)
ridx
=
-
sof
+
(
r1
-
32
);
else
if
((
r1
-
32
)
<
(
sor
-
rrb_gr
))
ridx
=
-
sof
+
(
r1
-
32
)
+
rrb_gr
;
else
ridx
=
-
sof
+
(
r1
-
32
)
-
(
sor
-
rrb_gr
);
DPRINT
(
"r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld
\n
"
,
r1
,
sw
->
ar_bspstore
,
regs
->
ar_bspstore
,
sof
,
(
regs
->
cr_ifs
>>
7
)
&
0x7f
,
ridx
);
long
ridx
=
r1
-
32
;
if
(
(
r1
-
32
)
>=
sof
)
{
if
(
ridx
>=
sof
)
{
/* this should never happen, as the "rsvd register fault" has higher priority */
DPRINT
(
"ignoring write to r%lu; only %lu registers are allocated!
\n
"
,
r1
,
sof
);
return
;
}
if
(
ridx
<
sor
)
ridx
=
rotate_reg
(
sor
,
rrb_gr
,
ridx
);
DPRINT
(
"r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld
\n
"
,
r1
,
sw
->
ar_bspstore
,
regs
->
ar_bspstore
,
sof
,
(
regs
->
cr_ifs
>>
7
)
&
0x7f
,
ridx
);
on_kbs
=
ia64_rse_num_regs
(
kbs
,
(
unsigned
long
*
)
sw
->
ar_bspstore
);
addr
=
ia64_rse_skip_regs
((
unsigned
long
*
)
sw
->
ar_bspstore
,
ridx
);
addr
=
ia64_rse_skip_regs
((
unsigned
long
*
)
sw
->
ar_bspstore
,
-
sof
+
ridx
);
if
(
addr
>=
kbs
)
{
/* the register is on the kernel backing store: easy... */
rnat_addr
=
ia64_rse_rnat_addr
(
addr
);
...
...
@@ -334,7 +343,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
bspstore
=
(
unsigned
long
*
)
regs
->
ar_bspstore
;
ubs_end
=
ia64_rse_skip_regs
(
bspstore
,
on_kbs
);
bsp
=
ia64_rse_skip_regs
(
ubs_end
,
-
sof
);
addr
=
ia64_rse_skip_regs
(
bsp
,
ridx
+
sof
);
addr
=
ia64_rse_skip_regs
(
bsp
,
ridx
);
DPRINT
(
"ubs_end=%p bsp=%p addr=%p
\n
"
,
(
void
*
)
ubs_end
,
(
void
*
)
bsp
,
(
void
*
)
addr
);
...
...
@@ -368,26 +377,22 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na
long
sof
=
(
regs
->
cr_ifs
)
&
0x7f
;
long
sor
=
8
*
((
regs
->
cr_ifs
>>
14
)
&
0xf
);
long
rrb_gr
=
(
regs
->
cr_ifs
>>
18
)
&
0x7f
;
long
ridx
;
long
ridx
=
r1
-
32
;
if
((
r1
-
32
)
>
sor
)
ridx
=
-
sof
+
(
r1
-
32
);
else
if
((
r1
-
32
)
<
(
sor
-
rrb_gr
))
ridx
=
-
sof
+
(
r1
-
32
)
+
rrb_gr
;
else
ridx
=
-
sof
+
(
r1
-
32
)
-
(
sor
-
rrb_gr
);
if
(
ridx
>=
sof
)
{
/* read of out-of-frame register returns an undefined value; 0 in our case. */
DPRINT
(
"ignoring read from r%lu; only %lu registers are allocated!
\n
"
,
r1
,
sof
);
goto
fail
;
}
if
(
ridx
<
sor
)
ridx
=
rotate_reg
(
sor
,
rrb_gr
,
ridx
);
DPRINT
(
"r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld
\n
"
,
r1
,
sw
->
ar_bspstore
,
regs
->
ar_bspstore
,
sof
,
(
regs
->
cr_ifs
>>
7
)
&
0x7f
,
ridx
);
if
((
r1
-
32
)
>=
sof
)
{
/* this should never happen, as the "rsvd register fault" has higher priority */
DPRINT
(
"ignoring read from r%lu; only %lu registers are allocated!
\n
"
,
r1
,
sof
);
return
;
}
on_kbs
=
ia64_rse_num_regs
(
kbs
,
(
unsigned
long
*
)
sw
->
ar_bspstore
);
addr
=
ia64_rse_skip_regs
((
unsigned
long
*
)
sw
->
ar_bspstore
,
ridx
);
addr
=
ia64_rse_skip_regs
((
unsigned
long
*
)
sw
->
ar_bspstore
,
-
sof
+
ridx
);
if
(
addr
>=
kbs
)
{
/* the register is on the kernel backing store: easy... */
*
val
=
*
addr
;
...
...
@@ -407,13 +412,13 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na
*/
if
(
regs
->
r12
>=
TASK_SIZE
)
{
DPRINT
(
"ignoring kernel read of r%lu; register isn't on the RBS!"
,
r1
);
return
;
goto
fail
;
}
bspstore
=
(
unsigned
long
*
)
regs
->
ar_bspstore
;
ubs_end
=
ia64_rse_skip_regs
(
bspstore
,
on_kbs
);
bsp
=
ia64_rse_skip_regs
(
ubs_end
,
-
sof
);
addr
=
ia64_rse_skip_regs
(
bsp
,
ridx
+
sof
);
addr
=
ia64_rse_skip_regs
(
bsp
,
ridx
);
DPRINT
(
"ubs_end=%p bsp=%p addr=%p
\n
"
,
(
void
*
)
ubs_end
,
(
void
*
)
bsp
,
(
void
*
)
addr
);
...
...
@@ -428,6 +433,13 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na
ia64_peek
(
current
,
sw
,
(
unsigned
long
)
ubs_end
,
(
unsigned
long
)
rnat_addr
,
&
rnats
);
*
nat
=
(
rnats
&
nat_mask
)
!=
0
;
}
return
;
fail:
*
val
=
0
;
if
(
nat
)
*
nat
=
0
;
return
;
}
...
...
@@ -486,7 +498,16 @@ setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
DPRINT
(
"*0x%lx=0x%lx NaT=%d new unat: %p=%lx
\n
"
,
addr
,
val
,
nat
,
(
void
*
)
unat
,
*
unat
);
}
#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
/*
* Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
* range from 32-127, result is in the range from 0-95.
*/
static
inline
unsigned
long
fph_index
(
struct
pt_regs
*
regs
,
long
regnum
)
{
unsigned
long
rrb_fr
=
(
regs
->
cr_ifs
>>
25
)
&
0x7f
;
return
rotate_reg
(
96
,
rrb_fr
,
(
regnum
-
IA64_FIRST_ROTATING_FR
));
}
static
void
setfpreg
(
unsigned
long
regnum
,
struct
ia64_fpreg
*
fpval
,
struct
pt_regs
*
regs
)
...
...
@@ -507,7 +528,7 @@ setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
*/
if
(
regnum
>=
IA64_FIRST_ROTATING_FR
)
{
ia64_sync_fph
(
current
);
current
->
thread
.
fph
[
IA64_FPH_OFFS
(
regnum
)]
=
*
fpval
;
current
->
thread
.
fph
[
fph_index
(
regs
,
regnum
)]
=
*
fpval
;
}
else
{
/*
* pt_regs or switch_stack ?
...
...
@@ -566,7 +587,7 @@ getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
*/
if
(
regnum
>=
IA64_FIRST_ROTATING_FR
)
{
ia64_flush_fph
(
current
);
*
fpval
=
current
->
thread
.
fph
[
IA64_FPH_OFFS
(
regnum
)];
*
fpval
=
current
->
thread
.
fph
[
fph_index
(
regs
,
regnum
)];
}
else
{
/*
* f0 = 0.0, f1= 1.0. Those registers are constant and are thus
...
...
@@ -651,7 +672,7 @@ emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsi
* just in case.
*/
if
(
ld
.
x6_op
==
1
||
ld
.
x6_op
==
3
)
{
printk
(
"%s %s: register update on speculative load, error
\n
"
,
KERN_ERR
,
__FUNCTION__
);
printk
(
KERN_ERR
"%s: register update on speculative load, error
\n
"
,
__FUNCTION__
);
die_if_kernel
(
"unaligned reference on specualtive load with register update
\n
"
,
regs
,
30
);
}
...
...
@@ -1081,8 +1102,8 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs
* For this reason we keep this sanity check
*/
if
(
ld
.
x6_op
==
1
||
ld
.
x6_op
==
3
)
printk
(
"%s %s: register update on speculative load pair, "
"error
\n
"
,
KERN_ERR
,
__FUNCTION__
);
printk
(
KERN_ERR
"%s: register update on speculative load pair, error
\n
"
,
__FUNCTION__
);
setreg
(
ld
.
r3
,
ifa
,
0
,
regs
);
}
...
...
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