diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp index 788c592080..e85688a2ae 100644 --- a/Kernel/Random.cpp +++ b/Kernel/Random.cpp @@ -44,24 +44,48 @@ KernelRng& KernelRng::the() KernelRng::KernelRng() { - if (g_cpu_supports_rdseed) { + if (g_cpu_supports_rdseed || g_cpu_supports_rdrand) { for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) { u32 value = 0; - asm volatile( - "1:\n" - "rdseed %0\n" - "jnc 1b\n" - : "=r"(value)); + if (g_cpu_supports_rdseed) { + asm volatile( + "1:\n" + "rdseed %0\n" + "jnc 1b\n" + : "=r"(value)); + } else { + asm volatile( + "1:\n" + "rdrand %0\n" + "jnc 1b\n" + : "=r"(value)); + } this->resource().add_random_event(value, i % 32); } } } +void KernelRng::wait_for_entropy() +{ + if (!resource().is_ready()) { + Thread::current->wait_on(m_seed_queue); + } +} + +void KernelRng::wake_if_ready() +{ + if (resource().is_ready()) { + m_seed_queue.wake_all(); + } +} + size_t EntropySource::next_source { 0 }; void get_good_random_bytes(u8* buffer, size_t buffer_size) { + KernelRng::the().wait_for_entropy(); + // FIXME: What if interrupts are disabled because we're in an interrupt? if (are_interrupts_enabled()) { LOCKER(KernelRng::the().lock()); @@ -73,7 +97,25 @@ void get_good_random_bytes(u8* buffer, size_t buffer_size) void get_fast_random_bytes(u8* buffer, size_t buffer_size) { - return get_good_random_bytes(buffer, buffer_size); + if (KernelRng::the().resource().is_ready()) { + return get_good_random_bytes(buffer, buffer_size); + } + + static u32 next = 1; + + union { + u8 bytes[4]; + u32 value; + } u; + size_t offset = 4; + for (size_t i = 0; i < buffer_size; ++i) { + if (offset >= 4) { + next = next * 1103515245 + 12345; + u.value = next; + offset = 0; + } + buffer[i] = u.bytes[offset++]; + } } } diff --git a/Kernel/Random.h b/Kernel/Random.h index 2804731740..a6e506094f 100644 --- a/Kernel/Random.h +++ b/Kernel/Random.h @@ -61,7 +61,7 @@ public: this->reseed(); } - ASSERT(m_reseed_number > 0); + ASSERT(is_seeded()); // FIXME: More than 2^20 bytes cannot be generated without refreshing the key. ASSERT(n < (1 << 20)); @@ -86,6 +86,16 @@ public: m_pools[pool].update(reinterpret_cast(&event_data), sizeof(T)); } + bool is_seeded() const + { + return m_reseed_number > 0; + } + + bool is_ready() const + { + return is_seeded() || m_p0_len >= reseed_threshold; + } + private: void reseed() { @@ -118,8 +128,14 @@ class KernelRng : public Lockable event = { read_tsc(), m_source, event_data }; KernelRng::the().resource().add_random_event(event, m_pool); m_pool++; + KernelRng::the().wake_if_ready(); } private: @@ -153,7 +170,7 @@ private: }; // NOTE: These API's are primarily about expressing intent/needs in the calling code. -// We don't make any guarantees about actual fastness or goodness yet. +// The only difference is that get_fast_random is guaranteed not to block. void get_fast_random_bytes(u8*, size_t); void get_good_random_bytes(u8*, size_t); diff --git a/Kernel/VM/PageDirectory.cpp b/Kernel/VM/PageDirectory.cpp index 75f934f2c9..e04778dae9 100644 --- a/Kernel/VM/PageDirectory.cpp +++ b/Kernel/VM/PageDirectory.cpp @@ -79,7 +79,7 @@ PageDirectory::PageDirectory(Process& process, const RangeAllocator* parent_rang if (parent_range_allocator) { m_range_allocator.initialize_from_parent(*parent_range_allocator); } else { - size_t random_offset = (get_good_random() % 32 * MB) & PAGE_MASK; + size_t random_offset = (get_fast_random() % 32 * MB) & PAGE_MASK; u32 base = userspace_range_base + random_offset; m_range_allocator.initialize_with_range(VirtualAddress(base), userspace_range_ceiling - base); } diff --git a/Kernel/init.cpp b/Kernel/init.cpp index dc82ec79f3..8e041bc08a 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -131,7 +131,7 @@ extern "C" [[noreturn]] void init() klog() << "Starting SerenityOS..."; - __stack_chk_guard = get_good_random(); + __stack_chk_guard = get_fast_random(); TimeManagement::initialize(); @@ -169,7 +169,7 @@ extern "C" [[noreturn]] void init() extern "C" [[noreturn]] void init_ap(u32 cpu) { APIC::the().enable(cpu); - + #if 0 Scheduler::idle_loop(); #else