Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions dev/virtio/rng/include/dev/virtio/rng.h
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);
8 changes: 8 additions & 0 deletions dev/virtio/rng/rules.mk
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
114 changes: 114 additions & 0 deletions dev/virtio/rng/virtio-rng.cpp
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);
Comment thread
travisg marked this conversation as resolved.
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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reminds me we should implement a better system RNG

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be glad to help improve the system rng.
If there is anything specific you need help with or any direction you'd like me to explore, just let me know!

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);
13 changes: 13 additions & 0 deletions dev/virtio/virtio-mmio-bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#if WITH_DEV_VIRTIO_9P
#include <dev/virtio/9p.h>
#endif
#if WITH_DEV_VIRTIO_RNG
#include <dev/virtio/rng.h>
#endif

#define LOCAL_TRACE 0

Expand Down Expand Up @@ -237,6 +240,16 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride)
}
}
#endif // WITH_DEV_VIRTIO_NET
#if WITH_DEV_VIRTIO_RNG
if (mmio->device_id == 4) { // virtio-rng
LTRACEF("found rng device\n");

status_t err = virtio_rng_init(dev);
if (err >= 0) {
found++;
}
}
#endif // WITH_DEV_VIRTIO_RNG
#if WITH_DEV_VIRTIO_9P
if (mmio->device_id == 9) { // 9p device
LTRACEF("found 9p device\n");
Expand Down
31 changes: 31 additions & 0 deletions dev/virtio/virtio-pci-bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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[] = {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
};
Expand Down
1 change: 1 addition & 0 deletions platform/qemu-virt-arm/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ MODULE_DEPS += \
dev/virtio/block \
dev/virtio/gpu \
dev/virtio/net \
dev/virtio/rng \
lib/cbuf \
lib/fdtwalk \
lib/fs/9p \
Expand Down