rust-kernel
Rustbelt: a hobby x86_64 kernel written in Rust
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | //! Virtio: the "virtual hardware" standard QEMU, KVM, cloud VMs and
//! Firecracker all speak. (Stage 13; virtio-blk and virtio-net from stages
//! 6 and 12 predate this module and talk the older *legacy* interface on
//! their own -- see block/virtio_blk.rs.)
//!
//! A virtio device is a PCI card that doesn't pretend to be real hardware.
//! Instead of emulating, say, a 1990s graphics chip register by register,
//! guest and host agree on a simple shared-memory protocol:
//!
//! * **Feature bits.** The device offers features, the driver accepts the
//! subset it understands. (We always accept VERSION_1, bit 32: "I speak
//! the modern, little-endian, spec-1.0 interface".)
//! * **Virtqueues** (queue.rs): ring buffers in guest RAM. The driver puts
//! buffer addresses into a queue and *notifies* the device (one register
//! write); the device does the work and puts the buffer back on the
//! "used" ring. A request is just bytes in a buffer whose format each
//! device type defines (a GPU command, a block read, random bytes...).
//! * **Config space**: a few device-specific registers (the console's size,
//! the GPU's number of scanouts...).
//!
//! **Legacy vs modern.** Old ("legacy", virtio 0.9.5) devices put all that in
//! one I/O-port BAR with fixed offsets -- simple, and what virtio_blk.rs and
//! virtio_net.rs use. Modern (virtio 1.0+) devices put several register
//! blocks into memory BARs and describe *where* with PCI capabilities
//! (vendor-specific, id 0x09). QEMU's rng, console and net cards are
//! "transitional" (they speak both); virtio-gpu is modern-only, so this
//! module does the modern way, and the three stage-13 drivers share it:
//!
//! rng.rs virtio-rng: entropy for getrandom(), /dev/random, smoltcp
//! console.rs virtio-console: a second terminal, /dev/hvc0
//! gpu.rs virtio-gpu (2D): a framebuffer, /dev/fb0, the fb console
//!
//! Spec: https://docs.oasis-open.org/virtio/virtio/v1.2/virtio-v1.2.html
use cratePciDevice;
use ;
pub use Virtqueue;
/// Virtio's PCI vendor id (Red Hat's). Modern device ids are 0x1040 + type
/// (gpu = type 16 -> 0x1050); transitional ones are 0x1000.. (rng 0x1005,
/// console 0x1003).
pub const VENDOR: u16 = 0x1af4;
// Device status bits: the driver walks through these while starting up.
const STATUS_ACKNOWLEDGE: u8 = 1; // "I noticed you"
const STATUS_DRIVER: u8 = 2; // "and I have a driver for you"
const STATUS_DRIVER_OK: u8 = 4; // "set up, go"
const STATUS_FEATURES_OK: u8 = 8; // "I accept these features"
/// Feature bit 32: the modern interface. Required for modern-only devices.
const F_VERSION_1: u64 = 1 << 32;
// Capability types (the `cfg_type` byte of a virtio PCI capability).
const CAP_COMMON: u8 = 1; // the common config: features, status, queues
const CAP_NOTIFY: u8 = 2; // doorbells: write a queue number to kick it
const CAP_ISR: u8 = 3; // interrupt status (reading it acknowledges)
const CAP_DEVICE: u8 = 4; // device-specific config
// Offsets inside the common config block (virtio spec 4.1.4.3).
const DEVICE_FEATURE_SELECT: u64 = 0x00;
const DEVICE_FEATURE: u64 = 0x04;
const DRIVER_FEATURE_SELECT: u64 = 0x08;
const DRIVER_FEATURE: u64 = 0x0c;
const DEVICE_STATUS: u64 = 0x14;
const QUEUE_SELECT: u64 = 0x16;
const QUEUE_SIZE: u64 = 0x18;
const QUEUE_ENABLE: u64 = 0x1c;
const QUEUE_NOTIFY_OFF: u64 = 0x1e;
const QUEUE_DESC: u64 = 0x20;
const QUEUE_DRIVER: u64 = 0x28; // the "available" ring
const QUEUE_DEVICE: u64 = 0x30; // the "used" ring
/// A modern virtio PCI device: virtual addresses of its register blocks.
// Plain MMIO helpers. Volatile: every access must really reach the device.
/// Interrupt handler part, called by interrupts.rs for shared PCI lines.
/// Every device on a shared line must have its ISR read, or (level
/// triggered) the line stays asserted forever. Only the console uses
/// interrupts; the rng and the GPU are polled.
/// Bring up all three stage-13 drivers. Returns boot log lines.
|