rng

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: BSD-3-Clause Imports: 2 Imported by: 0

README

go-virtio/rng

Pure-Go virtio-rng (virtio-entropy) driver targeting the go-virtio/common transport interfaces. Implements the modern-transport (Virtio 1.0+) init sequence and the single-virtqueue entropy-read path for the standard PCI-bound virtio-rng device (VID 0x1AF4, DID 0x1044).

virtio-rng is the simplest device class in the spec (Virtio 1.1 §5.4): one virtqueue (the "requestq"), no device-specific feature bits, and no device-config region. The driver posts a device-writable buffer on the queue; the device fills it with random bytes and reports — via the used ring — how many bytes it wrote.

This package owns the spec-level driver (the feature-acceptance mask, the init sequence per Virtio 1.1 §3.1.1, the request-queue state machine) and routes every transport-level operation through go-virtio/common's Transport interface. Drop in any implementation of that interface (UEFI's EFI_PCI_IO_PROTOCOL, bare-metal MMIO, virtio-mmio adapter) and the same driver code drives the device.

Quick start

import (
    virtiorng "github.com/go-virtio/rng"
)

// transport is any value that implements go-virtio/common.Transport.
vr, err := virtiorng.OpenVirtioRng(transport)
if err != nil {
    return err
}

// Read always fills the whole buffer on success (io.ReadFull-style,
// matching crypto/rand's Reader contract).
buf := make([]byte, 32)
if _, err := vr.Read(buf); err != nil {
    return err
}

// ReadPoll takes an explicit busy-poll budget for tighter timeouts.
n, err := vr.ReadPoll(buf, 50000)

OpenVirtioRng leaves the device in DRIVER_OK state with an empty, ready request queue. Unlike virtio-net there is no device-config region to read and no buffers to pre-post — the driver posts a buffer on demand in Read.

Sibling packages

Note on the device ID

The modern virtio-entropy PCI device ID (0x1044) lives in go-virtio/common as PCIDeviceIDModernEntropy, alongside PCIDeviceIDModern{Net,Block} and the PCIDeviceIDIsEntropy helper. Because those constants were added after common's v0.1.0 tag, this module currently carries a replace github.com/go-virtio/common => ../common bridge in go.mod; drop it once common is re-tagged (v0.1.1) and bump the require.

License

BSD-3-Clause. See LICENSE.

Documentation

Overview

go-virtio/rng — driver core: feature negotiation + init sequence + entropy-read path for the modern virtio-entropy device (virtio-rng, Virtio 1.1 §5.4).

virtio-rng is the simplest device class in the spec: a single virtqueue (the "requestq"), no device-specific feature bits, and no device-config region. The driver places a device-writable buffer on the queue; the device fills it with random bytes and reports, via the used ring, how many bytes it wrote.

Index

Constants

View Source
const AcceptedFeatures uint64 = common.FeatureVersion1

AcceptedFeatures is the feature mask the driver negotiates ON. virtio-rng defines no device-specific feature bits (Virtio 1.1 §5.4.3), so the only bit we ever accept is the non-negotiable VIRTIO_F_VERSION_1 (modern transport).

View Source
const DefaultPollIterations = 200000

DefaultPollIterations is the busy-poll budget a plain Read spends waiting for the device to return a filled buffer. The entropy round-trip is sub-millisecond on every backend measured; this is a generous upper bound for the busy-poll model the driver uses.

View Source
const RequestQueueIdx uint16 = 0

RequestQueueIdx is the index of the single virtio-rng virtqueue (Virtio 1.1 §5.4.2 — "requestq", virtqueue 0).

View Source
const RequestQueueSize uint16 = 8

RequestQueueSize is the desired ring size for the request queue. A small ring is plenty: the driver keeps at most one buffer outstanding per Read call. Clamped down to the device's advertised maximum (and rounded to a power of two) during setup.

Variables

View Source
var (
	ErrNotModernDevice   = commonRngError("go-virtio/rng: device doesn't offer VIRTIO_F_VERSION_1 (legacy-only)")
	ErrFeaturesNotOK     = commonRngError("go-virtio/rng: FEATURES_OK status bit didn't stick after DriverFeature write")
	ErrInitWrongDeviceID = commonRngError("go-virtio/rng: PCI device ID is not 0x1044 (modern entropy device)")
	ErrQueueNotAvailable = commonRngError("go-virtio/rng: device reports QueueSize=0 for the request queue")
	ErrReadTimeout       = commonRngError("go-virtio/rng: read poll timeout (device returned no entropy within budget)")
)

Sentinel errors for the virtio-rng path. All exported so callers can branch + format them.

Functions

func AcceptFeatures

func AcceptFeatures(deviceFeatures uint64) (uint64, error)

AcceptFeatures returns the negotiated feature mask: the intersection of what the device offers and what we accept. The caller writes this back via DriverFeature.

We require VIRTIO_F_VERSION_1 — if the device doesn't offer it, the device is legacy-only and we return ErrNotModernDevice.

Types

type VirtioRng

type VirtioRng struct {
	// Cfg is the modern-transport handle (BARs + offsets + the
	// BARMemoryAccessor used for every register access).
	Cfg *common.ModernConfig

	// NegotiatedFeatures records what the driver-feature handshake
	// settled on. Exposed for diagnostic prints.
	NegotiatedFeatures uint64
	// contains filtered or unexported fields
}

VirtioRng wraps one initialised virtio-rng device. The caller holds this for the lifetime of the entropy source; the underlying virtqueue pages live as long as the supplied PageAllocator's lifetime contract.

func OpenVirtioRng

func OpenVirtioRng(t common.Transport) (*VirtioRng, error)

OpenVirtioRng drives the full bring-up of one virtio-rng device:

  1. Verify the PCI device ID is 0x1044 (modern entropy).
  2. InitModernConfig walks PCI caps + populates the BAR locators.
  3. Reset → ACK → DRIVER status progression.
  4. Read DeviceFeature, mask to VERSION_1, write DriverFeature.
  5. Set FEATURES_OK, verify it stuck.
  6. Allocate + publish the request queue (queue 0).
  7. DRIVER_OK status.

On success the device is in DRIVER_OK state with an empty, ready request queue. Unlike virtio-net there is no device-config region to read and no buffers to pre-post — the driver posts a buffer on demand in Read.

func (*VirtioRng) Read

func (r *VirtioRng) Read(p []byte) (int, error)

Read fills p with entropy from the device, blocking (busy-poll) up to DefaultPollIterations per device round-trip. It always fills the whole of p on success (io.ReadFull-style semantics, matching crypto/rand's Reader contract) and returns len(p). A partial result is returned alongside an error if the device stalls or returns no bytes.

func (*VirtioRng) ReadPoll

func (r *VirtioRng) ReadPoll(p []byte, pollIterations int) (int, error)

ReadPoll is the parameterised variant of Read that takes an explicit busy-poll budget (iterations spent waiting for each device round-trip). Useful for callers that want a tighter timeout than DefaultPollIterations.

func (*VirtioRng) RequestQueue

func (r *VirtioRng) RequestQueue() *common.Virtqueue

RequestQueue exposes the request *common.Virtqueue handle. Read-only accessor so callers can inspect ring state for diagnostic dumps; the field itself stays unexported.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL