diff options
| -rw-r--r-- | drivers/char/random.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index dfe918a21e32..d3bb7927fb49 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -267,6 +267,8 @@ | |||
| 267 | #define CREATE_TRACE_POINTS | 267 | #define CREATE_TRACE_POINTS |
| 268 | #include <trace/events/random.h> | 268 | #include <trace/events/random.h> |
| 269 | 269 | ||
| 270 | /* #define ADD_INTERRUPT_BENCH */ | ||
| 271 | |||
| 270 | /* | 272 | /* |
| 271 | * Configuration information | 273 | * Configuration information |
| 272 | */ | 274 | */ |
| @@ -558,25 +560,29 @@ struct fast_pool { | |||
| 558 | * collector. It's hardcoded for an 128 bit pool and assumes that any | 560 | * collector. It's hardcoded for an 128 bit pool and assumes that any |
| 559 | * locks that might be needed are taken by the caller. | 561 | * locks that might be needed are taken by the caller. |
| 560 | */ | 562 | */ |
| 561 | static void fast_mix(struct fast_pool *f, __u32 input[4]) | 563 | static void fast_mix(struct fast_pool *f) |
| 562 | { | 564 | { |
| 563 | __u32 w; | 565 | __u32 a = f->pool[0], b = f->pool[1]; |
| 564 | unsigned input_rotate = f->rotate; | 566 | __u32 c = f->pool[2], d = f->pool[3]; |
| 565 | 567 | ||
| 566 | w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; | 568 | a += b; c += d; |
| 567 | f->pool[0] = (w >> 3) ^ twist_table[w & 7]; | 569 | b = rol32(a, 6); d = rol32(c, 27); |
| 568 | input_rotate = (input_rotate + 14) & 31; | 570 | d ^= a; b ^= c; |
| 569 | w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; | 571 | |
| 570 | f->pool[1] = (w >> 3) ^ twist_table[w & 7]; | 572 | a += b; c += d; |
| 571 | input_rotate = (input_rotate + 7) & 31; | 573 | b = rol32(a, 16); d = rol32(c, 14); |
| 572 | w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; | 574 | d ^= a; b ^= c; |
| 573 | f->pool[2] = (w >> 3) ^ twist_table[w & 7]; | 575 | |
| 574 | input_rotate = (input_rotate + 7) & 31; | 576 | a += b; c += d; |
| 575 | w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; | 577 | b = rol32(a, 6); d = rol32(c, 27); |
| 576 | f->pool[3] = (w >> 3) ^ twist_table[w & 7]; | 578 | d ^= a; b ^= c; |
| 577 | input_rotate = (input_rotate + 7) & 31; | 579 | |
| 578 | 580 | a += b; c += d; | |
| 579 | f->rotate = input_rotate; | 581 | b = rol32(a, 16); d = rol32(c, 14); |
| 582 | d ^= a; b ^= c; | ||
| 583 | |||
| 584 | f->pool[0] = a; f->pool[1] = b; | ||
| 585 | f->pool[2] = c; f->pool[3] = d; | ||
| 580 | f->count++; | 586 | f->count++; |
| 581 | } | 587 | } |
| 582 | 588 | ||
| @@ -829,6 +835,27 @@ EXPORT_SYMBOL_GPL(add_input_randomness); | |||
| 829 | 835 | ||
| 830 | static DEFINE_PER_CPU(struct fast_pool, irq_randomness); | 836 | static DEFINE_PER_CPU(struct fast_pool, irq_randomness); |
| 831 | 837 | ||
| 838 | #ifdef ADD_INTERRUPT_BENCH | ||
| 839 | static unsigned long avg_cycles, avg_deviation; | ||
| 840 | |||
| 841 | #define AVG_SHIFT 8 /* Exponential average factor k=1/256 */ | ||
| 842 | #define FIXED_1_2 (1 << (AVG_SHIFT-1)) | ||
| 843 | |||
| 844 | static void add_interrupt_bench(cycles_t start) | ||
| 845 | { | ||
| 846 | long delta = random_get_entropy() - start; | ||
| 847 | |||
| 848 | /* Use a weighted moving average */ | ||
| 849 | delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT); | ||
| 850 | avg_cycles += delta; | ||
| 851 | /* And average deviation */ | ||
| 852 | delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT); | ||
| 853 | avg_deviation += delta; | ||
| 854 | } | ||
| 855 | #else | ||
| 856 | #define add_interrupt_bench(x) | ||
| 857 | #endif | ||
| 858 | |||
| 832 | void add_interrupt_randomness(int irq, int irq_flags) | 859 | void add_interrupt_randomness(int irq, int irq_flags) |
| 833 | { | 860 | { |
| 834 | struct entropy_store *r; | 861 | struct entropy_store *r; |
| @@ -836,22 +863,23 @@ void add_interrupt_randomness(int irq, int irq_flags) | |||
| 836 | struct pt_regs *regs = get_irq_regs(); | 863 | struct pt_regs *regs = get_irq_regs(); |
| 837 | unsigned long now = jiffies; | 864 | unsigned long now = jiffies; |
| 838 | cycles_t cycles = random_get_entropy(); | 865 | cycles_t cycles = random_get_entropy(); |
| 839 | __u32 input[4], c_high, j_high; | 866 | __u32 c_high, j_high; |
| 840 | __u64 ip; | 867 | __u64 ip; |
| 841 | unsigned long seed; | 868 | unsigned long seed; |
| 842 | int credit = 0; | 869 | int credit = 0; |
| 843 | 870 | ||
| 844 | c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; | 871 | c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; |
| 845 | j_high = (sizeof(now) > 4) ? now >> 32 : 0; | 872 | j_high = (sizeof(now) > 4) ? now >> 32 : 0; |
| 846 | input[0] = cycles ^ j_high ^ irq; | 873 | fast_pool->pool[0] ^= cycles ^ j_high ^ irq; |
| 847 | input[1] = now ^ c_high; | 874 | fast_pool->pool[1] ^= now ^ c_high; |
| 848 | ip = regs ? instruction_pointer(regs) : _RET_IP_; | 875 | ip = regs ? instruction_pointer(regs) : _RET_IP_; |
| 849 | input[2] = ip; | 876 | fast_pool->pool[2] ^= ip; |
| 850 | input[3] = ip >> 32; | 877 | fast_pool->pool[3] ^= ip >> 32; |
| 851 | 878 | ||
| 852 | fast_mix(fast_pool, input); | 879 | fast_mix(fast_pool); |
| 853 | if ((irq_flags & __IRQF_TIMER) == 0) | 880 | if ((irq_flags & __IRQF_TIMER) == 0) |
| 854 | fast_pool->notimer_count++; | 881 | fast_pool->notimer_count++; |
| 882 | add_interrupt_bench(cycles); | ||
| 855 | 883 | ||
| 856 | if (cycles) { | 884 | if (cycles) { |
| 857 | if ((fast_pool->count < 64) && | 885 | if ((fast_pool->count < 64) && |
| @@ -1650,6 +1678,22 @@ struct ctl_table random_table[] = { | |||
| 1650 | .mode = 0444, | 1678 | .mode = 0444, |
| 1651 | .proc_handler = proc_do_uuid, | 1679 | .proc_handler = proc_do_uuid, |
| 1652 | }, | 1680 | }, |
| 1681 | #ifdef ADD_INTERRUPT_BENCH | ||
| 1682 | { | ||
| 1683 | .procname = "add_interrupt_avg_cycles", | ||
| 1684 | .data = &avg_cycles, | ||
| 1685 | .maxlen = sizeof(avg_cycles), | ||
| 1686 | .mode = 0444, | ||
| 1687 | .proc_handler = proc_doulongvec_minmax, | ||
| 1688 | }, | ||
| 1689 | { | ||
| 1690 | .procname = "add_interrupt_avg_deviation", | ||
| 1691 | .data = &avg_deviation, | ||
| 1692 | .maxlen = sizeof(avg_deviation), | ||
| 1693 | .mode = 0444, | ||
| 1694 | .proc_handler = proc_doulongvec_minmax, | ||
| 1695 | }, | ||
| 1696 | #endif | ||
| 1653 | { } | 1697 | { } |
| 1654 | }; | 1698 | }; |
| 1655 | #endif /* CONFIG_SYSCTL */ | 1699 | #endif /* CONFIG_SYSCTL */ |
