RNG.cpp 2.2 KB

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