aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2012-08-21 20:38:50 +0200
committerAnders Roxell <anders.roxell@linaro.org>2015-08-17 08:59:46 +0200
commit843ce2458e1ca537a8ca7bed618bc681f9d60b10 (patch)
tree0d57c4f3c0ba5cc3ae46fafca4c53f126fd6ba15
parentcab0b2666ea0656159e3c690c0f94930f3d9839f (diff)
random: Make it work on rt
Delegate the random insertion to the forced threaded interrupt handler. Store the return IP of the hard interrupt handler in the irq descriptor and feed it into the random generator as a source of entropy. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/char/random.c11
-rw-r--r--include/linux/irqdesc.h1
-rw-r--r--include/linux/random.h2
-rw-r--r--kernel/irq/handle.c8
-rw-r--r--kernel/irq/manage.c6
5 files changed, 20 insertions, 8 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 9a07ef22fab1..eb47efec2506 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -868,28 +868,27 @@ static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
return *(ptr + f->reg_idx++);
}
-void add_interrupt_randomness(int irq, int irq_flags)
+void add_interrupt_randomness(int irq, int irq_flags, __u64 ip)
{
struct entropy_store *r;
struct fast_pool *fast_pool = this_cpu_ptr(&irq_randomness);
- struct pt_regs *regs = get_irq_regs();
unsigned long now = jiffies;
cycles_t cycles = random_get_entropy();
__u32 c_high, j_high;
- __u64 ip;
unsigned long seed;
int credit = 0;
if (cycles == 0)
- cycles = get_reg(fast_pool, regs);
+ cycles = get_reg(fast_pool, NULL);
c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
fast_pool->pool[1] ^= now ^ c_high;
- ip = regs ? instruction_pointer(regs) : _RET_IP_;
+ if (!ip)
+ ip = _RET_IP_;
fast_pool->pool[2] ^= ip;
fast_pool->pool[3] ^= (sizeof(ip) > 4) ? ip >> 32 :
- get_reg(fast_pool, regs);
+ get_reg(fast_pool, NULL);
fast_mix(fast_pool);
add_interrupt_bench(cycles);
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index dd1109fb241e..9d97cd5bb7c7 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -63,6 +63,7 @@ struct irq_desc {
unsigned int irqs_unhandled;
atomic_t threads_handled;
int threads_handled_last;
+ u64 random_ip;
raw_spinlock_t lock;
struct cpumask *percpu_enabled;
#ifdef CONFIG_SMP
diff --git a/include/linux/random.h b/include/linux/random.h
index b05856e16b75..4a64ad52dcb7 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -11,7 +11,7 @@
extern void add_device_randomness(const void *, unsigned int);
extern void add_input_randomness(unsigned int type, unsigned int code,
unsigned int value);
-extern void add_interrupt_randomness(int irq, int irq_flags);
+extern void add_interrupt_randomness(int irq, int irq_flags, __u64 ip);
extern void get_random_bytes(void *buf, int nbytes);
extern void get_random_bytes_arch(void *buf, int nbytes);
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 635480270858..26a63672c263 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -133,6 +133,8 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
+ struct pt_regs *regs = get_irq_regs();
+ u64 ip = regs ? instruction_pointer(regs) : 0;
irqreturn_t retval = IRQ_NONE;
unsigned int flags = 0, irq = desc->irq_data.irq;
@@ -173,7 +175,11 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
action = action->next;
} while (action);
- add_interrupt_randomness(irq, flags);
+#ifndef CONFIG_PREEMPT_RT_FULL
+ add_interrupt_randomness(irq, flags, ip);
+#else
+ desc->random_ip = ip;
+#endif
if (!noirqdebug)
note_interrupt(irq, desc, retval);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 61ceb76ee5e6..1b5c50a68e23 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -991,6 +991,12 @@ static int irq_thread(void *data)
if (action_ret == IRQ_HANDLED)
atomic_inc(&desc->threads_handled);
+#ifdef CONFIG_PREEMPT_RT_FULL
+ migrate_disable();
+ add_interrupt_randomness(action->irq, 0,
+ desc->random_ip ^ (unsigned long) action);
+ migrate_enable();
+#endif
wake_threads_waitq(desc);
}