Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/drivers/char/hw_random.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 14033 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 14033 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | /* |
2 | Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) |
3 | (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> |
4 | |
5 | derived from |
6 | |
7 | Hardware driver for the AMD 768 Random Number Generator (RNG) |
8 | (c) Copyright 2001 Red Hat Inc <alan@redhat.com> |
9 | |
10 | derived from |
11 | |
12 | Hardware driver for Intel i810 Random Number Generator (RNG) |
13 | Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> |
14 | Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> |
15 | |
16 | Please read Documentation/hw_random.txt for details on use. |
17 | |
18 | ---------------------------------------------------------- |
19 | This software may be used and distributed according to the terms |
20 | of the GNU General Public License, incorporated herein by reference. |
21 | |
22 | */ |
23 | |
24 | |
25 | #include <linux/module.h> |
26 | #include <linux/kernel.h> |
27 | #include <linux/fs.h> |
28 | #include <linux/init.h> |
29 | #include <linux/pci.h> |
30 | #include <linux/interrupt.h> |
31 | #include <linux/spinlock.h> |
32 | #include <linux/random.h> |
33 | #include <linux/miscdevice.h> |
34 | #include <linux/smp_lock.h> |
35 | #include <linux/mm.h> |
36 | #include <linux/delay.h> |
37 | |
38 | #ifdef __i386__ |
39 | #include <asm/msr.h> |
40 | #include <asm/cpufeature.h> |
41 | #endif |
42 | |
43 | #include <asm/io.h> |
44 | #include <asm/uaccess.h> |
45 | |
46 | |
47 | /* |
48 | * core module and version information |
49 | */ |
50 | #define RNG_VERSION "1.0.0" |
51 | #define RNG_MODULE_NAME "hw_random" |
52 | #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION |
53 | #define PFX RNG_MODULE_NAME ": " |
54 | |
55 | |
56 | /* |
57 | * debugging macros |
58 | */ |
59 | |
60 | /* pr_debug() collapses to a no-op if DEBUG is not defined */ |
61 | #define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args) |
62 | |
63 | |
64 | #undef RNG_NDEBUG /* define to enable lightweight runtime checks */ |
65 | #ifdef RNG_NDEBUG |
66 | #define assert(expr) \ |
67 | if(!(expr)) { \ |
68 | printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s," \ |
69 | "line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__); \ |
70 | } |
71 | #else |
72 | #define assert(expr) |
73 | #endif |
74 | |
75 | #define RNG_MISCDEV_MINOR 183 /* official */ |
76 | |
77 | static int rng_dev_open (struct inode *inode, struct file *filp); |
78 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, |
79 | loff_t * offp); |
80 | |
81 | static int __init intel_init (struct pci_dev *dev); |
82 | static void intel_cleanup(void); |
83 | static unsigned int intel_data_present (void); |
84 | static u32 intel_data_read (void); |
85 | |
86 | static int __init amd_init (struct pci_dev *dev); |
87 | static void amd_cleanup(void); |
88 | static unsigned int amd_data_present (void); |
89 | static u32 amd_data_read (void); |
90 | |
91 | #ifdef __i386__ |
92 | static int __init via_init(struct pci_dev *dev); |
93 | static void via_cleanup(void); |
94 | static unsigned int via_data_present (void); |
95 | static u32 via_data_read (void); |
96 | #endif |
97 | |
98 | struct rng_operations { |
99 | int (*init) (struct pci_dev *dev); |
100 | void (*cleanup) (void); |
101 | unsigned int (*data_present) (void); |
102 | u32 (*data_read) (void); |
103 | unsigned int n_bytes; /* number of bytes per ->data_read */ |
104 | }; |
105 | static struct rng_operations *rng_ops; |
106 | |
107 | static struct file_operations rng_chrdev_ops = { |
108 | .owner = THIS_MODULE, |
109 | .open = rng_dev_open, |
110 | .read = rng_dev_read, |
111 | }; |
112 | |
113 | |
114 | static struct miscdevice rng_miscdev = { |
115 | RNG_MISCDEV_MINOR, |
116 | RNG_MODULE_NAME, |
117 | &rng_chrdev_ops, |
118 | }; |
119 | |
120 | enum { |
121 | rng_hw_none, |
122 | rng_hw_intel, |
123 | rng_hw_amd, |
124 | rng_hw_via, |
125 | }; |
126 | |
127 | static struct rng_operations rng_vendor_ops[] = { |
128 | /* rng_hw_none */ |
129 | { }, |
130 | |
131 | /* rng_hw_intel */ |
132 | { intel_init, intel_cleanup, intel_data_present, |
133 | intel_data_read, 1 }, |
134 | |
135 | /* rng_hw_amd */ |
136 | { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 }, |
137 | |
138 | #ifdef __i386__ |
139 | /* rng_hw_via */ |
140 | { via_init, via_cleanup, via_data_present, via_data_read, 1 }, |
141 | #endif |
142 | }; |
143 | |
144 | /* |
145 | * Data for PCI driver interface |
146 | * |
147 | * This data only exists for exporting the supported |
148 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually |
149 | * register a pci_driver, because someone else might one day |
150 | * want to register another driver on the same PCI id. |
151 | */ |
152 | static struct pci_device_id rng_pci_tbl[] = { |
153 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, |
154 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, |
155 | |
156 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, |
157 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, |
158 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, |
159 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, |
160 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, |
161 | |
162 | { 0, }, /* terminate list */ |
163 | }; |
164 | MODULE_DEVICE_TABLE (pci, rng_pci_tbl); |
165 | |
166 | |
167 | /*********************************************************************** |
168 | * |
169 | * Intel RNG operations |
170 | * |
171 | */ |
172 | |
173 | /* |
174 | * RNG registers (offsets from rng_mem) |
175 | */ |
176 | #define INTEL_RNG_HW_STATUS 0 |
177 | #define INTEL_RNG_PRESENT 0x40 |
178 | #define INTEL_RNG_ENABLED 0x01 |
179 | #define INTEL_RNG_STATUS 1 |
180 | #define INTEL_RNG_DATA_PRESENT 0x01 |
181 | #define INTEL_RNG_DATA 2 |
182 | |
183 | /* |
184 | * Magic address at which Intel PCI bridges locate the RNG |
185 | */ |
186 | #define INTEL_RNG_ADDR 0xFFBC015F |
187 | #define INTEL_RNG_ADDR_LEN 3 |
188 | |
189 | /* token to our ioremap'd RNG register area */ |
190 | static void __iomem *rng_mem; |
191 | |
192 | static inline u8 intel_hwstatus (void) |
193 | { |
194 | assert (rng_mem != NULL); |
195 | return readb (rng_mem + INTEL_RNG_HW_STATUS); |
196 | } |
197 | |
198 | static inline u8 intel_hwstatus_set (u8 hw_status) |
199 | { |
200 | assert (rng_mem != NULL); |
201 | writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS); |
202 | return intel_hwstatus (); |
203 | } |
204 | |
205 | static unsigned int intel_data_present(void) |
206 | { |
207 | assert (rng_mem != NULL); |
208 | |
209 | return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ? |
210 | 1 : 0; |
211 | } |
212 | |
213 | static u32 intel_data_read(void) |
214 | { |
215 | assert (rng_mem != NULL); |
216 | |
217 | return readb (rng_mem + INTEL_RNG_DATA); |
218 | } |
219 | |
220 | static int __init intel_init (struct pci_dev *dev) |
221 | { |
222 | int rc; |
223 | u8 hw_status; |
224 | |
225 | DPRINTK ("ENTER\n"); |
226 | |
227 | rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); |
228 | if (rng_mem == NULL) { |
229 | printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); |
230 | rc = -EBUSY; |
231 | goto err_out; |
232 | } |
233 | |
234 | /* Check for Intel 82802 */ |
235 | hw_status = intel_hwstatus (); |
236 | if ((hw_status & INTEL_RNG_PRESENT) == 0) { |
237 | printk (KERN_ERR PFX "RNG not detected\n"); |
238 | rc = -ENODEV; |
239 | goto err_out_free_map; |
240 | } |
241 | |
242 | /* turn RNG h/w on, if it's off */ |
243 | if ((hw_status & INTEL_RNG_ENABLED) == 0) |
244 | hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED); |
245 | if ((hw_status & INTEL_RNG_ENABLED) == 0) { |
246 | printk (KERN_ERR PFX "cannot enable RNG, aborting\n"); |
247 | rc = -EIO; |
248 | goto err_out_free_map; |
249 | } |
250 | |
251 | DPRINTK ("EXIT, returning 0\n"); |
252 | return 0; |
253 | |
254 | err_out_free_map: |
255 | iounmap (rng_mem); |
256 | rng_mem = NULL; |
257 | err_out: |
258 | DPRINTK ("EXIT, returning %d\n", rc); |
259 | return rc; |
260 | } |
261 | |
262 | static void intel_cleanup(void) |
263 | { |
264 | u8 hw_status; |
265 | |
266 | hw_status = intel_hwstatus (); |
267 | if (hw_status & INTEL_RNG_ENABLED) |
268 | intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED); |
269 | else |
270 | printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); |
271 | iounmap(rng_mem); |
272 | rng_mem = NULL; |
273 | } |
274 | |
275 | /*********************************************************************** |
276 | * |
277 | * AMD RNG operations |
278 | * |
279 | */ |
280 | |
281 | static u32 pmbase; /* PMxx I/O base */ |
282 | static struct pci_dev *amd_dev; |
283 | |
284 | static unsigned int amd_data_present (void) |
285 | { |
286 | return inl(pmbase + 0xF4) & 1; |
287 | } |
288 | |
289 | |
290 | static u32 amd_data_read (void) |
291 | { |
292 | return inl(pmbase + 0xF0); |
293 | } |
294 | |
295 | static int __init amd_init (struct pci_dev *dev) |
296 | { |
297 | int rc; |
298 | u8 rnen; |
299 | |
300 | DPRINTK ("ENTER\n"); |
301 | |
302 | pci_read_config_dword(dev, 0x58, &pmbase); |
303 | |
304 | pmbase &= 0x0000FF00; |
305 | |
306 | if (pmbase == 0) |
307 | { |
308 | printk (KERN_ERR PFX "power management base not set\n"); |
309 | rc = -EIO; |
310 | goto err_out; |
311 | } |
312 | |
313 | pci_read_config_byte(dev, 0x40, &rnen); |
314 | rnen |= (1 << 7); /* RNG on */ |
315 | pci_write_config_byte(dev, 0x40, rnen); |
316 | |
317 | pci_read_config_byte(dev, 0x41, &rnen); |
318 | rnen |= (1 << 7); /* PMIO enable */ |
319 | pci_write_config_byte(dev, 0x41, rnen); |
320 | |
321 | pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n", |
322 | pmbase); |
323 | |
324 | amd_dev = dev; |
325 | |
326 | DPRINTK ("EXIT, returning 0\n"); |
327 | return 0; |
328 | |
329 | err_out: |
330 | DPRINTK ("EXIT, returning %d\n", rc); |
331 | return rc; |
332 | } |
333 | |
334 | static void amd_cleanup(void) |
335 | { |
336 | u8 rnen; |
337 | |
338 | pci_read_config_byte(amd_dev, 0x40, &rnen); |
339 | rnen &= ~(1 << 7); /* RNG off */ |
340 | pci_write_config_byte(amd_dev, 0x40, rnen); |
341 | |
342 | /* FIXME: twiddle pmio, also? */ |
343 | } |
344 | |
345 | #ifdef __i386__ |
346 | /*********************************************************************** |
347 | * |
348 | * VIA RNG operations |
349 | * |
350 | */ |
351 | |
352 | enum { |
353 | VIA_STRFILT_CNT_SHIFT = 16, |
354 | VIA_STRFILT_FAIL = (1 << 15), |
355 | VIA_STRFILT_ENABLE = (1 << 14), |
356 | VIA_RAWBITS_ENABLE = (1 << 13), |
357 | VIA_RNG_ENABLE = (1 << 6), |
358 | VIA_XSTORE_CNT_MASK = 0x0F, |
359 | |
360 | VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ |
361 | VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ |
362 | VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, |
363 | VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ |
364 | VIA_RNG_CHUNK_2_MASK = 0xFFFF, |
365 | VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ |
366 | VIA_RNG_CHUNK_1_MASK = 0xFF, |
367 | }; |
368 | |
369 | static u32 via_rng_datum; |
370 | |
371 | /* |
372 | * Investigate using the 'rep' prefix to obtain 32 bits of random data |
373 | * in one insn. The upside is potentially better performance. The |
374 | * downside is that the instruction becomes no longer atomic. Due to |
375 | * this, just like familiar issues with /dev/random itself, the worst |
376 | * case of a 'rep xstore' could potentially pause a cpu for an |
377 | * unreasonably long time. In practice, this condition would likely |
378 | * only occur when the hardware is failing. (or so we hope :)) |
379 | * |
380 | * Another possible performance boost may come from simply buffering |
381 | * until we have 4 bytes, thus returning a u32 at a time, |
382 | * instead of the current u8-at-a-time. |
383 | */ |
384 | |
385 | static inline u32 xstore(u32 *addr, u32 edx_in) |
386 | { |
387 | u32 eax_out; |
388 | |
389 | asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" |
390 | :"=m"(*addr), "=a"(eax_out) |
391 | :"D"(addr), "d"(edx_in)); |
392 | |
393 | return eax_out; |
394 | } |
395 | |
396 | static unsigned int via_data_present(void) |
397 | { |
398 | u32 bytes_out; |
399 | |
400 | /* We choose the recommended 1-byte-per-instruction RNG rate, |
401 | * for greater randomness at the expense of speed. Larger |
402 | * values 2, 4, or 8 bytes-per-instruction yield greater |
403 | * speed at lesser randomness. |
404 | * |
405 | * If you change this to another VIA_CHUNK_n, you must also |
406 | * change the ->n_bytes values in rng_vendor_ops[] tables. |
407 | * VIA_CHUNK_8 requires further code changes. |
408 | * |
409 | * A copy of MSR_VIA_RNG is placed in eax_out when xstore |
410 | * completes. |
411 | */ |
412 | via_rng_datum = 0; /* paranoia, not really necessary */ |
413 | bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK; |
414 | if (bytes_out == 0) |
415 | return 0; |
416 | |
417 | return 1; |
418 | } |
419 | |
420 | static u32 via_data_read(void) |
421 | { |
422 | return via_rng_datum; |
423 | } |
424 | |
425 | static int __init via_init(struct pci_dev *dev) |
426 | { |
427 | u32 lo, hi, old_lo; |
428 | |
429 | /* Control the RNG via MSR. Tread lightly and pay very close |
430 | * close attention to values written, as the reserved fields |
431 | * are documented to be "undefined and unpredictable"; but it |
432 | * does not say to write them as zero, so I make a guess that |
433 | * we restore the values we find in the register. |
434 | */ |
435 | rdmsr(MSR_VIA_RNG, lo, hi); |
436 | |
437 | old_lo = lo; |
438 | lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); |
439 | lo &= ~VIA_XSTORE_CNT_MASK; |
440 | lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); |
441 | lo |= VIA_RNG_ENABLE; |
442 | |
443 | if (lo != old_lo) |
444 | wrmsr(MSR_VIA_RNG, lo, hi); |
445 | |
446 | /* perhaps-unnecessary sanity check; remove after testing if |
447 | unneeded */ |
448 | rdmsr(MSR_VIA_RNG, lo, hi); |
449 | if ((lo & VIA_RNG_ENABLE) == 0) { |
450 | printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); |
451 | return -ENODEV; |
452 | } |
453 | |
454 | return 0; |
455 | } |
456 | |
457 | static void via_cleanup(void) |
458 | { |
459 | /* do nothing */ |
460 | } |
461 | #endif |
462 | |
463 | |
464 | /*********************************************************************** |
465 | * |
466 | * /dev/hwrandom character device handling (major 10, minor 183) |
467 | * |
468 | */ |
469 | |
470 | static int rng_dev_open (struct inode *inode, struct file *filp) |
471 | { |
472 | /* enforce read-only access to this chrdev */ |
473 | if ((filp->f_mode & FMODE_READ) == 0) |
474 | return -EINVAL; |
475 | if (filp->f_mode & FMODE_WRITE) |
476 | return -EINVAL; |
477 | |
478 | return 0; |
479 | } |
480 | |
481 | |
482 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, |
483 | loff_t * offp) |
484 | { |
485 | static DEFINE_SPINLOCK(rng_lock); |
486 | unsigned int have_data; |
487 | u32 data = 0; |
488 | ssize_t ret = 0; |
489 | |
490 | while (size) { |
491 | spin_lock(&rng_lock); |
492 | |
493 | have_data = 0; |
494 | if (rng_ops->data_present()) { |
495 | data = rng_ops->data_read(); |
496 | have_data = rng_ops->n_bytes; |
497 | } |
498 | |
499 | spin_unlock (&rng_lock); |
500 | |
501 | while (have_data && size) { |
502 | if (put_user((u8)data, buf++)) { |
503 | ret = ret ? : -EFAULT; |
504 | break; |
505 | } |
506 | size--; |
507 | ret++; |
508 | have_data--; |
509 | data>>=8; |
510 | } |
511 | |
512 | if (filp->f_flags & O_NONBLOCK) |
513 | return ret ? : -EAGAIN; |
514 | |
515 | if(need_resched()) |
516 | { |
517 | current->state = TASK_INTERRUPTIBLE; |
518 | schedule_timeout(1); |
519 | } |
520 | else |
521 | udelay(200); /* FIXME: We could poll for 250uS ?? */ |
522 | |
523 | if (signal_pending (current)) |
524 | return ret ? : -ERESTARTSYS; |
525 | } |
526 | return ret; |
527 | } |
528 | |
529 | |
530 | |
531 | /* |
532 | * rng_init_one - look for and attempt to init a single RNG |
533 | */ |
534 | static int __init rng_init_one (struct pci_dev *dev) |
535 | { |
536 | int rc; |
537 | |
538 | DPRINTK ("ENTER\n"); |
539 | |
540 | assert(rng_ops != NULL); |
541 | |
542 | rc = rng_ops->init(dev); |
543 | if (rc) |
544 | goto err_out; |
545 | |
546 | rc = misc_register (&rng_miscdev); |
547 | if (rc) { |
548 | printk (KERN_ERR PFX "misc device register failed\n"); |
549 | goto err_out_cleanup_hw; |
550 | } |
551 | |
552 | DPRINTK ("EXIT, returning 0\n"); |
553 | return 0; |
554 | |
555 | err_out_cleanup_hw: |
556 | rng_ops->cleanup(); |
557 | err_out: |
558 | DPRINTK ("EXIT, returning %d\n", rc); |
559 | return rc; |
560 | } |
561 | |
562 | |
563 | |
564 | MODULE_AUTHOR("The Linux Kernel team"); |
565 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); |
566 | MODULE_LICENSE("GPL"); |
567 | |
568 | |
569 | /* |
570 | * rng_init - initialize RNG module |
571 | */ |
572 | static int __init rng_init (void) |
573 | { |
574 | int rc; |
575 | struct pci_dev *pdev = NULL; |
576 | const struct pci_device_id *ent; |
577 | |
578 | DPRINTK ("ENTER\n"); |
579 | |
580 | /* Probe for Intel, AMD RNGs */ |
581 | for_each_pci_dev(pdev) { |
582 | ent = pci_match_device (rng_pci_tbl, pdev); |
583 | if (ent) { |
584 | rng_ops = &rng_vendor_ops[ent->driver_data]; |
585 | goto match; |
586 | } |
587 | } |
588 | |
589 | #ifdef __i386__ |
590 | /* Probe for VIA RNG */ |
591 | if (cpu_has_xstore) { |
592 | rng_ops = &rng_vendor_ops[rng_hw_via]; |
593 | pdev = NULL; |
594 | goto match; |
595 | } |
596 | #endif |
597 | |
598 | DPRINTK ("EXIT, returning -ENODEV\n"); |
599 | return -ENODEV; |
600 | |
601 | match: |
602 | rc = rng_init_one (pdev); |
603 | if (rc) |
604 | return rc; |
605 | |
606 | pr_info( RNG_DRIVER_NAME " loaded\n"); |
607 | |
608 | DPRINTK ("EXIT, returning 0\n"); |
609 | return 0; |
610 | } |
611 | |
612 | |
613 | /* |
614 | * rng_init - shutdown RNG module |
615 | */ |
616 | static void __exit rng_cleanup (void) |
617 | { |
618 | DPRINTK ("ENTER\n"); |
619 | |
620 | misc_deregister (&rng_miscdev); |
621 | |
622 | if (rng_ops->cleanup) |
623 | rng_ops->cleanup(); |
624 | |
625 | DPRINTK ("EXIT\n"); |
626 | } |
627 | |
628 | |
629 | module_init (rng_init); |
630 | module_exit (rng_cleanup); |