-
Notifications
You must be signed in to change notification settings - Fork 753
[dev][virtio-rng] Introduce virtio-rng driver to seed system prng #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
52c6b05
194815a
4cc6201
96b5782
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /* | ||
| * Copyright (c) 2026 Kuan-Wei Chiu <visitorckw@gmail.com> | ||
| * | ||
| * Use of this source code is governed by a MIT-style | ||
| * license that can be found in the LICENSE file or at | ||
| * https://opensource.org/licenses/MIT | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include <lk/err.h> | ||
|
|
||
| struct virtio_device; | ||
|
|
||
| status_t virtio_rng_init(virtio_device *dev); | ||
| ssize_t virtio_rng_read(void *buf, size_t len); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| LOCAL_DIR := $(GET_LOCAL_DIR) | ||
|
|
||
| MODULE := $(LOCAL_DIR) | ||
|
|
||
| MODULE_SRCS += \ | ||
| $(LOCAL_DIR)/virtio-rng.cpp | ||
|
|
||
| include make/module.mk |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| /* | ||
| * Copyright (c) 2026 Kuan-Wei Chiu <visitorckw@gmail.com> | ||
| * | ||
| * Use of this source code is governed by a MIT-style | ||
| * license that can be found in the LICENSE file or at | ||
| * https://opensource.org/licenses/MIT | ||
| */ | ||
|
|
||
| #include <dev/virtio/rng.h> | ||
| #include <dev/virtio/virtio-device.h> | ||
| #include <dev/virtio/virtio_ring.h> | ||
| #include <kernel/thread.h> | ||
| #include <kernel/vm.h> | ||
| #include <lk/debug.h> | ||
| #include <lk/err.h> | ||
| #include <lk/init.h> | ||
| #include <lk/trace.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| #define LOCAL_TRACE 0 | ||
|
|
||
| constexpr uint16_t RNG_QUEUE_INDEX = 0; | ||
|
|
||
| struct virtio_rng_state { | ||
| virtio_device *dev; | ||
| bool initialized; | ||
| volatile size_t last_rx_len; | ||
| }; | ||
|
|
||
| static virtio_rng_state rng; | ||
|
|
||
| static enum handler_return virtio_rng_irq(virtio_device *dev, uint ring_index, const vring_used_elem *e) { | ||
| if (ring_index == RNG_QUEUE_INDEX && e) | ||
| rng.last_rx_len = e->len; | ||
|
|
||
| return INT_NO_RESCHEDULE; | ||
| } | ||
|
|
||
| status_t virtio_rng_init(virtio_device *dev) { | ||
| LTRACE_ENTRY; | ||
|
|
||
| rng.dev = dev; | ||
| rng.initialized = false; | ||
| rng.last_rx_len = 0; | ||
|
|
||
| dev->set_irq_callbacks(virtio_rng_irq, nullptr); | ||
|
|
||
| status_t err = dev->virtio_alloc_ring(RNG_QUEUE_INDEX, 32); | ||
| if (err != NO_ERROR) { | ||
| TRACEF("virtio-rng: Failed to allocate virtqueue\n"); | ||
| return err; | ||
| } | ||
|
|
||
| dev->bus()->virtio_status_driver_ok(); | ||
| rng.initialized = true; | ||
|
|
||
| LTRACEF("virtio-rng: initialized successfully\n"); | ||
| return NO_ERROR; | ||
| } | ||
|
|
||
| ssize_t virtio_rng_read(void *buf, size_t len) { | ||
| if (!rng.initialized || len == 0) return ERR_NOT_CONFIGURED; | ||
|
|
||
| vaddr_t v_start = (vaddr_t)buf; | ||
| vaddr_t v_end = v_start + len - 1; | ||
| if ((v_start / PAGE_SIZE) != (v_end / PAGE_SIZE)) | ||
| return ERR_INVALID_ARGS; | ||
|
|
||
| paddr_t paddr = vaddr_to_paddr(buf); | ||
| if (!paddr) return ERR_INVALID_ARGS; | ||
|
|
||
| uint16_t desc_idx = rng.dev->virtio_alloc_desc(RNG_QUEUE_INDEX); | ||
| if (desc_idx == 0xffff) return ERR_NO_MEMORY; | ||
|
|
||
| vring_desc *desc = rng.dev->virtio_desc_index_to_desc(RNG_QUEUE_INDEX, desc_idx); | ||
| desc->addr = paddr; | ||
| desc->len = (uint32_t)len; | ||
| desc->flags = VRING_DESC_F_WRITE; | ||
|
|
||
| rng.last_rx_len = 0; | ||
| rng.dev->virtio_submit_chain(RNG_QUEUE_INDEX, desc_idx); | ||
| rng.dev->bus()->virtio_kick(RNG_QUEUE_INDEX); | ||
|
|
||
| while (rng.last_rx_len == 0) { | ||
| rng.dev->handle_queue_interrupt(); | ||
| thread_yield(); | ||
| } | ||
|
|
||
| size_t rx_len = rng.last_rx_len; | ||
| rng.last_rx_len = 0; | ||
|
|
||
| rng.dev->virtio_free_desc(RNG_QUEUE_INDEX, desc_idx); | ||
| return rx_len; | ||
| } | ||
|
|
||
| static void seed_system_prng(uint level) { | ||
| unsigned int seed = 0; | ||
| ssize_t bytes_read; | ||
|
|
||
| if (!rng.initialized) | ||
| return; | ||
|
|
||
| bytes_read = virtio_rng_read(&seed, sizeof(seed)); | ||
|
|
||
| if (bytes_read == sizeof(seed)) { | ||
| srand(seed); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reminds me we should implement a better system RNG
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be glad to help improve the system rng. |
||
| dprintf(INFO, "virtio-rng: System PRNG seeded with hardware entropy\n"); | ||
| } else { | ||
| dprintf(INFO, "virtio-rng: Failed to seed system PRNG\n"); | ||
| } | ||
| } | ||
|
|
||
| LK_INIT_HOOK(virtio_rng_seed, seed_system_prng, LK_INIT_LEVEL_TARGET + 1); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,9 @@ | |
| #if WITH_DEV_VIRTIO_GPU | ||
| #include <dev/virtio/gpu.h> | ||
| #endif | ||
| #if WITH_DEV_VIRTIO_RNG | ||
| #include <dev/virtio/rng.h> | ||
| #endif | ||
|
|
||
| #define LOCAL_TRACE 0 | ||
|
|
||
|
|
@@ -465,17 +468,45 @@ static status_t init_gpu(pci_location_t loc, const virtio_pci_devices &dev_table | |
| #endif | ||
| } | ||
|
|
||
| static status_t init_rng(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index) { | ||
| LTRACE_ENTRY; | ||
|
|
||
| #if WITH_DEV_VIRTIO_RNG | ||
| auto *bus = new virtio_pci_bus(); | ||
| auto *dev = new virtio_device(bus); | ||
|
|
||
| auto err = bus->init(dev, loc, index); | ||
| if (err != NO_ERROR) { | ||
| delete bus; | ||
| return err; | ||
| } | ||
|
|
||
| dev->set_config_ptr(bus->device_config()); | ||
|
|
||
| err = virtio_rng_init(dev); | ||
| if (err != NO_ERROR) { | ||
| PANIC_UNIMPLEMENTED; | ||
| } | ||
|
|
||
| return err; | ||
| #else | ||
| return ERR_NOT_FOUND; | ||
| #endif | ||
| } | ||
|
|
||
|
|
||
| int virtio_pci_init() { | ||
| LTRACE_ENTRY; | ||
|
|
||
| constexpr virtio_pci_devices devices[] = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you also add a virtio-mmio interface for this? Should be pretty easy, can test with the arm64 qemu since it can run with both mmio and PCI virtio interfaces (i think the -C flag switches to PCI from the default mmio)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack. Will do. |
||
| { 0x1000, true, &init_net }, // transitional network | ||
| { 0x1001, true, &init_block }, // transitional block | ||
| { 0x1005, true, &init_rng }, // transitional rng | ||
| { 0x1009, true, nullptr }, // legacy virtio 9p | ||
| { 0x1041, false, &init_net }, // non-transitional network | ||
| { 0x1042, false, &init_block }, // non-transitional block | ||
| { 0x1043, false, nullptr }, // non-transitional console | ||
| { 0x1044, false, &init_rng }, // non-transitional rng | ||
| { 0x1050, false, &init_gpu }, // non-transitional gpu | ||
| { 0x1052, false, nullptr }, // non-transitional input | ||
| }; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.