Skip to main content

nvme/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! NVMe controller emulator (NVMe 2.0, NVM command set).
5//!
6//! This crate emulates an NVMe controller as a PCI device with MMIO BAR0,
7//! MSI-X, and admin + I/O queue pairs. It targets the
8//! [NVMe Base 2.0](https://nvmexpress.org/specifications/) specification
9//! (version register reports 0x00020000) with vendor ID 0x1414 (Microsoft).
10//!
11//! # Architecture
12//!
13//! - **PCI layer** ([`NvmeController`]) — MMIO BAR0 register handling, PCI
14//!   config space, MSI-X interrupt routing, doorbell writes.
15//! - **Coordinator** — manages enable/reset sequencing, namespace add/remove.
16//! - **Admin worker** — processes admin commands: Identify Controller/Namespace,
17//!   Create/Delete I/O Queue, Get/Set Features, Async Event Request.
18//! - **I/O workers** — pool of tasks (one per completion queue) processing NVM
19//!   commands: READ, WRITE, FLUSH, Dataset Management (TRIM), and persistent
20//!   reservation commands.
21//!
22//! # What it doesn't implement
23//!
24//! Firmware update, admin-level namespace management (create/delete), multi-path
25//! I/O, end-to-end data protection (PI), and save/restore (`SaveRestore`
26//! returns not-supported).
27//!
28//! # Namespace management
29//!
30//! Namespaces can be added and removed at runtime via [`NvmeControllerClient`].
31//! Each namespace wraps a [`Disk`](disk_backend::Disk) and a background task
32//! monitors capacity changes via `wait_resize`, completing Async Event Requests
33//! with `CHANGED_NAMESPACE_LIST` when the disk size changes.
34//!
35//! # Key constants
36//!
37//! - `MAX_DATA_TRANSFER_SIZE`: 256 KB
38//! - `MAX_QES`: 256 queue entries
39//! - `BAR0_LEN`: 64 KB
40
41#![forbid(unsafe_code)]
42
43mod error;
44mod namespace;
45mod pci;
46mod prp;
47mod queue;
48pub mod resolver;
49mod workers;
50
51#[cfg(test)]
52mod tests;
53
54pub use pci::NvmeController;
55pub use pci::NvmeControllerCaps;
56pub use workers::AddNamespaceError;
57pub use workers::NvmeControllerClient;
58
59use guestmem::ranges::PagedRange;
60use nvme_spec as spec;
61
62// Device configuration shared by PCI and NVMe.
63const DOORBELL_STRIDE_BITS: u8 = 2;
64/// Microsoft vendor ID.
65const VENDOR_ID: u16 = pci_core::microsoft::VENDOR_ID;
66/// Device ID allocated to the OpenVMM NVMe emulator.
67const DEVICE_ID: u16 = pci_core::microsoft::DeviceId::NVME.0;
68const NVME_VERSION: u32 = 0x00020000;
69const MAX_QES: u16 = 256;
70/// Maximum valid namespace ID for the NVM subsystem, reported in the `NN`
71/// field of Identify Controller. This is a fixed property of the subsystem
72/// (the size of the NSID address space), identical across all controllers,
73/// and is independent of how many namespaces are currently present.
74const MAX_NSID: u32 = 1024;
75const BAR0_LEN: u64 = 0x10000;
76const IOSQES: u8 = 6;
77const IOCQES: u8 = 4;
78
79// NVMe page sizes. This must match the `PagedRange` page size.
80const PAGE_SIZE: usize = 4096;
81const PAGE_SIZE64: u64 = 4096;
82const PAGE_MASK: u64 = !(PAGE_SIZE64 - 1);
83const PAGE_SHIFT: u32 = PAGE_SIZE.trailing_zeros();
84const _: () = assert!(PAGE_SIZE == PagedRange::PAGE_SIZE);