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
7a96704c
Commit
7a96704c
authored
Mar 13, 2003
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[hw_random] add support for VIA Nehemiah RNG ("xstore" instruction)
parent
e696dce2
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
146 additions
and
2 deletions
+146
-2
drivers/char/Kconfig
drivers/char/Kconfig
+1
-1
drivers/char/hw_random.c
drivers/char/hw_random.c
+145
-1
No files found.
drivers/char/Kconfig
View file @
7a96704c
...
...
@@ -710,7 +710,7 @@ config NWFLASH
If you're not sure, say N.
config HW_RANDOM
tristate "Intel/AMD H/W Random Number Generator support"
tristate "Intel/AMD
/Via
H/W Random Number Generator support"
depends on (X86 || IA64) && PCI
---help---
This driver provides kernel-side support for the Random Number
...
...
drivers/char/hw_random.c
View file @
7a96704c
/*
Hardware driver for the Intel/AMD Random Number Generators (RNG)
Hardware driver for the Intel/AMD
/Via
Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
derived from
...
...
@@ -35,6 +35,11 @@
#include <linux/mm.h>
#include <linux/delay.h>
#ifdef __i386__
#include <asm/msr.h>
#include <asm/cpufeature.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h>
...
...
@@ -88,6 +93,11 @@ static void __exit amd_cleanup(void);
static
unsigned
int
amd_data_present
(
void
);
static
u32
amd_data_read
(
void
);
static
int
__init
via_init
(
struct
pci_dev
*
dev
);
static
void
__exit
via_cleanup
(
void
);
static
unsigned
int
via_data_present
(
void
);
static
u32
via_data_read
(
void
);
struct
rng_operations
{
int
(
*
init
)
(
struct
pci_dev
*
dev
);
void
(
*
cleanup
)
(
void
);
...
...
@@ -117,6 +127,7 @@ enum {
rng_hw_none
,
rng_hw_intel
,
rng_hw_amd
,
rng_hw_via
,
};
static
struct
rng_operations
rng_vendor_ops
[]
__initdata
=
{
...
...
@@ -129,6 +140,9 @@ static struct rng_operations rng_vendor_ops[] __initdata = {
/* rng_hw_amd */
{
amd_init
,
amd_cleanup
,
amd_data_present
,
amd_data_read
,
4
},
/* rng_hw_via */
{
via_init
,
via_cleanup
,
via_data_present
,
via_data_read
,
1
},
};
/*
...
...
@@ -330,6 +344,127 @@ static void __exit amd_cleanup(void)
/* FIXME: twiddle pmio, also? */
}
/***********************************************************************
*
* Via RNG operations
*
*/
enum
{
VIA_STRFILT_CNT_SHIFT
=
16
,
VIA_STRFILT_FAIL
=
(
1
<<
15
),
VIA_STRFILT_ENABLE
=
(
1
<<
14
),
VIA_RAWBITS_ENABLE
=
(
1
<<
13
),
VIA_RNG_ENABLE
=
(
1
<<
6
),
VIA_XSTORE_CNT_MASK
=
0x0F
,
VIA_RNG_CHUNK_8
=
0x00
,
/* 64 rand bits, 64 stored bits */
VIA_RNG_CHUNK_4
=
0x01
,
/* 32 rand bits, 32 stored bits */
VIA_RNG_CHUNK_4_MASK
=
0xFFFFFFFF
,
VIA_RNG_CHUNK_2
=
0x02
,
/* 16 rand bits, 32 stored bits */
VIA_RNG_CHUNK_2_MASK
=
0xFFFF
,
VIA_RNG_CHUNK_1
=
0x03
,
/* 8 rand bits, 32 stored bits */
VIA_RNG_CHUNK_1_MASK
=
0xFF
,
};
u32
via_rng_datum
;
/*
* Investigate using the 'rep' prefix to obtain 32 bits of random data
* in one insn. The upside is potentially better performance. The
* downside is that the instruction becomes no longer atomic. Due to
* this, just like familiar issues with /dev/random itself, the worst
* case of a 'rep xstore' could potentially pause a cpu for an
* unreasonably long time. In practice, this condition would likely
* only occur when the hardware is failing. (or so we hope :))
*
* Another possible performance boost may come from simply buffering
* until we have 4 bytes, thus returning a u32 at a time,
* instead of the current u8-at-a-time.
*/
static
inline
u32
xstore
(
u32
*
addr
,
u32
edx_in
)
{
u32
eax_out
;
asm
(
".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
:
"=m"
(
*
addr
),
"=a"
(
eax_out
)
:
"D"
(
addr
),
"d"
(
edx_in
));
return
eax_out
;
}
static
unsigned
int
via_data_present
(
void
)
{
u32
bytes_out
;
/* We choose the recommended 1-byte-per-instruction RNG rate,
* for greater randomness at the expense of speed. Larger
* values 2, 4, or 8 bytes-per-instruction yield greater
* speed at lesser randomness.
*
* If you change this to another VIA_CHUNK_n, you must also
* change the ->n_bytes values in rng_vendor_ops[] tables.
* VIA_CHUNK_8 requires further code changes.
*
* A copy of MSR_VIA_RNG is placed in eax_out when xstore
* completes.
*/
via_rng_datum
=
0
;
/* paranoia, not really necessary */
bytes_out
=
xstore
(
&
via_rng_datum
,
VIA_RNG_CHUNK_1
)
&
VIA_XSTORE_CNT_MASK
;
if
(
bytes_out
==
0
)
return
0
;
return
1
;
}
static
u32
via_data_read
(
void
)
{
return
via_rng_datum
;
}
static
int
__init
via_init
(
struct
pci_dev
*
dev
)
{
u32
lo
,
hi
,
old_lo
;
/* Control the RNG via MSR. Tread lightly and pay very close
* close attention to values written, as the reserved fields
* are documented to be "undefined and unpredictable"; but it
* does not say to write them as zero, so I make a guess that
* we restore the values we find in the register.
*/
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
old_lo
=
lo
;
lo
&=
~
(
0x7f
<<
VIA_STRFILT_CNT_SHIFT
);
lo
&=
~
VIA_XSTORE_CNT_MASK
;
lo
&=
~
(
VIA_STRFILT_ENABLE
|
VIA_STRFILT_FAIL
|
VIA_RAWBITS_ENABLE
);
lo
|=
VIA_RNG_ENABLE
;
if
(
lo
!=
old_lo
)
wrmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
/* perhaps-unnecessary sanity check; remove after testing if
unneeded */
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
if
((
lo
&
VIA_RNG_ENABLE
)
==
0
)
{
printk
(
KERN_ERR
PFX
"cannot enable Via C3 RNG, aborting
\n
"
);
return
-
ENODEV
;
}
return
0
;
}
static
void
__exit
via_cleanup
(
void
)
{
u32
lo
,
hi
;
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
lo
&=
~
VIA_RNG_ENABLE
;
wrmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
}
/***********************************************************************
*
* /dev/hwrandom character device handling (major 10, minor 183)
...
...
@@ -471,6 +606,15 @@ static int __init rng_init (void)
}
}
#ifdef __i386__
/* Probe for Via RNG */
if
(
cpu_has_xstore
)
{
rng_ops
=
&
rng_vendor_ops
[
rng_hw_via
];
pdev
=
NULL
;
goto
match
;
}
#endif
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
return
-
ENODEV
;
...
...
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