Serenity Operating System
at master 78 lines 2.3 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/Bus/VirtIO/RNG.h> 8#include <Kernel/Sections.h> 9 10namespace Kernel::VirtIO { 11 12UNMAP_AFTER_INIT NonnullLockRefPtr<RNG> RNG::must_create(PCI::DeviceIdentifier const& device_identifier) 13{ 14 return adopt_lock_ref_if_nonnull(new RNG(device_identifier)).release_nonnull(); 15} 16 17UNMAP_AFTER_INIT void RNG::initialize() 18{ 19 Device::initialize(); 20 bool success = negotiate_features([&](auto) { 21 return 0; 22 }); 23 if (success) { 24 success = setup_queues(1); 25 } 26 if (success) { 27 finish_init(); 28 m_entropy_buffer = MM.allocate_contiguous_kernel_region(PAGE_SIZE, "VirtIO::RNG"sv, Memory::Region::Access::ReadWrite).release_value(); 29 if (m_entropy_buffer) { 30 memset(m_entropy_buffer->vaddr().as_ptr(), 0, m_entropy_buffer->size()); 31 request_entropy_from_host(); 32 } 33 } 34} 35 36UNMAP_AFTER_INIT RNG::RNG(PCI::DeviceIdentifier const& device_identifier) 37 : VirtIO::Device(device_identifier) 38{ 39} 40 41bool RNG::handle_device_config_change() 42{ 43 return false; // Device has no config 44} 45 46void RNG::handle_queue_update(u16 queue_index) 47{ 48 VERIFY(queue_index == REQUESTQ); 49 size_t available_entropy = 0, used; 50 auto& queue = get_queue(REQUESTQ); 51 { 52 SpinlockLocker lock(queue.lock()); 53 auto chain = queue.pop_used_buffer_chain(used); 54 if (chain.is_empty()) 55 return; 56 VERIFY(chain.length() == 1); 57 chain.for_each([&available_entropy](PhysicalAddress, size_t length) { 58 available_entropy = length; 59 }); 60 chain.release_buffer_slots_to_queue(); 61 } 62 dbgln_if(VIRTIO_DEBUG, "VirtIO::RNG: received {} bytes of entropy!", available_entropy); 63 for (auto i = 0u; i < available_entropy; i++) { 64 m_entropy_source.add_random_event(m_entropy_buffer->vaddr().as_ptr()[i]); 65 } 66 // TODO: When should we get some more entropy? 67} 68 69void RNG::request_entropy_from_host() 70{ 71 auto& queue = get_queue(REQUESTQ); 72 SpinlockLocker lock(queue.lock()); 73 QueueChain chain(queue); 74 chain.add_buffer_to_chain(m_entropy_buffer->physical_page(0)->paddr(), PAGE_SIZE, BufferType::DeviceWritable); 75 supply_chain_and_notify(REQUESTQ, chain); 76} 77 78}