1use crate::BAR0_LEN;
7use crate::DEVICE_ID;
8use crate::DOORBELL_STRIDE_BITS;
9use crate::IOCQES;
10use crate::IOSQES;
11use crate::MAX_QES;
12use crate::NVME_VERSION;
13use crate::NvmeControllerClient;
14use crate::PAGE_MASK;
15use crate::VENDOR_ID;
16use crate::spec;
17use crate::workers::IoQueueEntrySizes;
18use crate::workers::NvmeWorkers;
19use chipset_device::ChipsetDevice;
20use chipset_device::io::IoError;
21use chipset_device::io::IoError::InvalidRegister;
22use chipset_device::io::IoResult;
23use chipset_device::mmio::MmioIntercept;
24use chipset_device::mmio::RegisterMmioIntercept;
25use chipset_device::pci::ByteEnabledDwordRead;
26use chipset_device::pci::ByteEnabledDwordWrite;
27use chipset_device::pci::PciConfigSpace;
28use device_emulators::ReadWriteRequestType;
29use device_emulators::read_as_u32_chunks;
30use device_emulators::write_as_u32_chunks;
31use guid::Guid;
32use inspect::Inspect;
33use inspect::InspectMut;
34use parking_lot::Mutex;
35use pci_core::capabilities::msix::MsixEmulator;
36use pci_core::capabilities::pci_express::PciExpressCapability;
37use pci_core::cfg_space_emu::BarMemoryKind;
38use pci_core::cfg_space_emu::ConfigSpaceType0Emulator;
39use pci_core::cfg_space_emu::DeviceBars;
40use pci_core::dma::DmaTarget;
41use pci_core::spec::hwid::ClassCode;
42use pci_core::spec::hwid::HardwareIds;
43use pci_core::spec::hwid::ProgrammingInterface;
44use pci_core::spec::hwid::Subclass;
45use std::sync::Arc;
46use vmcore::device_state::ChangeDeviceState;
47use vmcore::save_restore::SaveError;
48use vmcore::save_restore::SaveRestore;
49use vmcore::save_restore::SavedStateNotSupported;
50use vmcore::vm_task::VmTaskDriverSource;
51
52#[derive(InspectMut)]
54pub struct NvmeController {
55 cfg_space: ConfigSpaceType0Emulator,
56 #[inspect(skip)]
57 msix: MsixEmulator,
58
59 registers: RegState,
60 #[inspect(skip)]
61 qe_sizes: Arc<Mutex<IoQueueEntrySizes>>,
62 #[inspect(flatten, mut)]
63 workers: NvmeWorkers,
64}
65
66#[derive(Inspect)]
67struct RegState {
68 #[inspect(hex)]
69 interrupt_mask: u32,
70 cc: spec::Cc,
71 csts: spec::Csts,
72 aqa: spec::Aqa,
73 #[inspect(hex)]
74 asq: u64,
75 #[inspect(hex)]
76 acq: u64,
77}
78
79impl RegState {
80 fn new() -> Self {
81 Self {
82 interrupt_mask: 0,
83 cc: spec::Cc::new(),
84 csts: spec::Csts::new(),
85 aqa: spec::Aqa::new(),
86 asq: 0,
87 acq: 0,
88 }
89 }
90}
91
92const CAP: spec::Cap = spec::Cap::new()
93 .with_dstrd(DOORBELL_STRIDE_BITS - 2)
94 .with_mqes_z(MAX_QES - 1)
95 .with_cqr(true)
96 .with_css_nvm(true)
97 .with_to(!0);
98
99#[derive(Debug, Copy, Clone)]
101pub struct NvmeControllerCaps {
102 pub msix_count: u16,
104 pub max_io_queues: u16,
106 pub subsystem_id: Guid,
109}
110
111impl NvmeController {
112 pub fn new(
114 driver_source: &VmTaskDriverSource,
115 dma_target: &DmaTarget,
116 register_mmio: &mut dyn RegisterMmioIntercept,
117 caps: NvmeControllerCaps,
118 ) -> Self {
119 let msi_target = dma_target.msi_target();
120 let guest_memory = dma_target.guest_memory().clone();
121 let (msix, msix_cap) = MsixEmulator::new(4, caps.msix_count, msi_target);
122 let bars = DeviceBars::new()
123 .bar0(
124 BAR0_LEN,
125 BarMemoryKind::Intercept(register_mmio.new_io_region("bar0", BAR0_LEN)),
126 )
127 .bar4(
128 msix.bar_len(),
129 BarMemoryKind::Intercept(register_mmio.new_io_region("msix", msix.bar_len())),
130 );
131
132 let cfg_space = ConfigSpaceType0Emulator::new(
133 HardwareIds {
134 vendor_id: VENDOR_ID,
135 device_id: DEVICE_ID,
136 revision_id: 0,
137 prog_if: ProgrammingInterface::MASS_STORAGE_CONTROLLER_NON_VOLATILE_MEMORY_NVME,
138 sub_class: Subclass::MASS_STORAGE_CONTROLLER_NON_VOLATILE_MEMORY,
139 base_class: ClassCode::MASS_STORAGE_CONTROLLER,
140 type0_sub_vendor_id: 0,
141 type0_sub_system_id: 0,
142 },
143 vec![
144 Box::new(msix_cap),
145 Box::new(PciExpressCapability::new(
146 pci_core::spec::caps::pci_express::DevicePortType::Endpoint,
147 None,
148 )),
149 ],
150 Vec::new(),
151 bars,
152 );
153
154 let interrupts = (0..caps.msix_count)
155 .map(|i| msix.interrupt(i).unwrap())
156 .collect();
157
158 let qe_sizes = Arc::new(Default::default());
159 let admin = NvmeWorkers::new(
160 driver_source,
161 guest_memory,
162 interrupts,
163 caps.max_io_queues,
164 caps.max_io_queues,
165 Arc::clone(&qe_sizes),
166 caps.subsystem_id,
167 );
168
169 Self {
170 cfg_space,
171 msix,
172 registers: RegState::new(),
173 workers: admin,
174 qe_sizes,
175 }
176 }
177
178 pub fn client(&self) -> NvmeControllerClient {
180 self.workers.client()
181 }
182
183 pub fn read_bar0(&mut self, addr: u64, data: &mut [u8]) -> IoResult {
185 if data.len() < 4 {
186 return IoResult::Err(IoError::InvalidAccessSize);
187 }
188 if addr & (data.len() as u64 - 1) != 0 {
189 return IoResult::Err(IoError::UnalignedAccess);
190 }
191
192 let d: Option<u64> = match spec::Register(addr & !7) {
194 spec::Register::CAP => Some(CAP.into()),
195 spec::Register::ASQ => Some(self.registers.asq),
196 spec::Register::ACQ => Some(self.registers.acq),
197 spec::Register::BPMBL => Some(0),
198 _ => None,
199 };
200 if let Some(d) = d {
201 if data.len() == 8 {
202 data.copy_from_slice(&d.to_ne_bytes());
203 } else if addr & 7 == 0 {
204 data.copy_from_slice(&(d as u32).to_ne_bytes());
205 } else {
206 data.copy_from_slice(&((d >> 32) as u32).to_ne_bytes());
207 }
208 return IoResult::Ok;
209 }
210
211 if data.len() != 4 {
212 return IoResult::Err(IoError::InvalidAccessSize);
213 }
214
215 let d: u32 = match spec::Register(addr) {
217 spec::Register::VS => NVME_VERSION,
218 spec::Register::INTMS => self.registers.interrupt_mask,
219 spec::Register::INTMC => self.registers.interrupt_mask,
220 spec::Register::CC => self.registers.cc.into(),
221 spec::Register::RESERVED => 0,
222 spec::Register::CSTS => self.get_csts(),
223 spec::Register::NSSR => 0,
224 spec::Register::AQA => self.registers.aqa.into(),
225 spec::Register::CMBLOC => 0,
226 spec::Register::CMBSZ => 0,
227 spec::Register::BPINFO => 0,
228 spec::Register::BPRSEL => 0,
229 _ => return IoResult::Err(InvalidRegister),
230 };
231 data.copy_from_slice(&d.to_ne_bytes());
232 IoResult::Ok
233 }
234
235 pub fn write_bar0(&mut self, addr: u64, data: &[u8]) -> IoResult {
237 if addr >= 0x1000 {
238 let base = addr - 0x1000;
240 let db_id = base >> DOORBELL_STRIDE_BITS;
241 if (db_id << DOORBELL_STRIDE_BITS) != base {
242 return IoResult::Err(InvalidRegister);
243 }
244 let Ok(data) = data.try_into() else {
245 return IoResult::Err(IoError::InvalidAccessSize);
246 };
247 let value = u32::from_ne_bytes(data);
248 let db_id = match u16::try_from(db_id) {
249 Ok(id) => id,
250 Err(_) => return IoResult::Err(InvalidRegister),
251 };
252 self.workers.doorbell(db_id, value);
253 return IoResult::Ok;
254 }
255
256 if data.len() < 4 {
257 return IoResult::Err(IoError::InvalidAccessSize);
258 }
259 if addr & (data.len() as u64 - 1) != 0 {
260 return IoResult::Err(IoError::UnalignedAccess);
261 }
262
263 let update_reg = |x: u64| {
264 if data.len() == 8 {
265 u64::from_ne_bytes(data.try_into().unwrap())
266 } else {
267 let data = u32::from_ne_bytes(data.try_into().unwrap()) as u64;
268 if addr & 7 == 0 {
269 (x & !(u32::MAX as u64)) | data
270 } else {
271 (x & u32::MAX as u64) | (data << 32)
272 }
273 }
274 };
275
276 let handled = match spec::Register(addr & !7) {
278 spec::Register::ASQ => {
279 if !self.registers.cc.en() {
280 self.registers.asq = update_reg(self.registers.asq) & PAGE_MASK;
281 } else {
282 tracelimit::warn_ratelimited!("attempt to set asq while enabled");
283 }
284 true
285 }
286 spec::Register::ACQ => {
287 if !self.registers.cc.en() {
288 self.registers.acq = update_reg(self.registers.acq) & PAGE_MASK;
289 } else {
290 tracelimit::warn_ratelimited!("attempt to set acq while enabled");
291 }
292 true
293 }
294 _ => false,
295 };
296 if handled {
297 return IoResult::Ok;
298 }
299
300 let Ok(data) = data.try_into() else {
301 return IoResult::Err(IoError::InvalidAccessSize);
302 };
303 let data = u32::from_ne_bytes(data);
304
305 match spec::Register(addr) {
307 spec::Register::INTMS => self.registers.interrupt_mask |= data,
308 spec::Register::INTMC => self.registers.interrupt_mask &= !data,
309 spec::Register::CC => self.set_cc(data.into()),
310 spec::Register::AQA => self.registers.aqa = data.into(),
311 _ => return IoResult::Err(InvalidRegister),
312 }
313 IoResult::Ok
314 }
315
316 fn set_cc(&mut self, cc: spec::Cc) {
317 tracing::debug!(?cc, "set cc");
318
319 if cc.mps() != 0 {
320 tracelimit::warn_ratelimited!(
321 "This implementation only supports memory page sizes of 4K."
322 );
323 self.fatal_error();
324 return;
325 }
326
327 if cc.css() != 0 {
328 tracelimit::warn_ratelimited!("This implementation only supports the NVM command set.");
329 self.fatal_error();
330 return;
331 }
332
333 if let 2..=6 = cc.ams() {
334 tracelimit::warn_ratelimited!("Undefined arbitration mechanism.");
335 self.fatal_error();
336 }
337
338 let mask: u32 = u32::from(
339 spec::Cc::new()
340 .with_en(true)
341 .with_shn(0b11)
342 .with_iosqes(0b1111)
343 .with_iocqes(0b1111),
344 );
345 let mut cc: spec::Cc = (u32::from(cc) & mask).into();
346
347 if cc.shn() != 0 {
348 self.registers.csts.set_shst(0b10);
352 }
353
354 if cc.en() != self.registers.cc.en() {
355 if cc.en() {
356 if cc.iocqes() == 0 {
358 cc.set_iocqes(IOCQES);
359 } else if cc.iocqes() != IOCQES {
360 tracelimit::warn_ratelimited!(
361 "This implementation only supports CQEs of the default size."
362 );
363 self.fatal_error();
364 return;
365 }
366
367 if cc.iosqes() == 0 {
368 cc.set_iosqes(IOSQES);
369 } else if cc.iosqes() != IOSQES {
370 tracelimit::warn_ratelimited!(
371 "This implementation only supports SQEs of the default size."
372 );
373 self.fatal_error();
374 return;
375 }
376
377 if self.registers.csts.rdy() {
378 tracelimit::warn_ratelimited!("enabling during reset");
379 return;
380 }
381 if cc.shn() == 0 {
382 self.registers.csts.set_shst(0);
383 }
384
385 self.workers.enable(
386 self.registers.asq,
387 self.registers.aqa.asqs_z().max(1) + 1,
388 self.registers.acq,
389 self.registers.aqa.acqs_z().max(1) + 1,
390 );
391 } else if self.registers.csts.rdy() {
392 self.workers.controller_reset();
393 } else {
394 tracelimit::warn_ratelimited!("disabling while not ready");
395 return;
396 }
397 }
398
399 self.registers.cc = cc;
400 *self.qe_sizes.lock() = IoQueueEntrySizes {
401 sqe_bits: cc.iosqes(),
402 cqe_bits: cc.iocqes(),
403 };
404 }
405
406 fn get_csts(&mut self) -> u32 {
407 if !self.registers.cc.en() && self.registers.csts.rdy() {
408 if self.workers.poll_controller_reset() {
410 self.registers.csts = 0.into();
412 self.registers.cc = 0.into();
413 self.registers.interrupt_mask = 0;
414 }
415 } else if self.registers.cc.en() && !self.registers.csts.rdy() {
416 if self.workers.poll_enabled() {
417 self.registers.csts.set_rdy(true);
418 }
419 }
420
421 let csts = self.registers.csts;
422 tracing::debug!(?csts, "get csts");
423 csts.into()
424 }
425
426 pub fn fatal_error(&mut self) {
429 self.registers.csts.set_cfs(true);
430 }
431}
432
433impl ChangeDeviceState for NvmeController {
434 fn start(&mut self) {}
435
436 async fn stop(&mut self) {}
437
438 async fn reset(&mut self) {
439 let Self {
440 cfg_space,
441 msix: _,
442 registers,
443 qe_sizes,
444 workers,
445 } = self;
446 workers.reset().await;
447 cfg_space.reset();
448 *registers = RegState::new();
449 *qe_sizes.lock() = Default::default();
450 }
451}
452
453impl ChipsetDevice for NvmeController {
454 fn supports_mmio(&mut self) -> Option<&mut dyn MmioIntercept> {
455 Some(self)
456 }
457
458 fn supports_pci(&mut self) -> Option<&mut dyn PciConfigSpace> {
459 Some(self)
460 }
461}
462
463impl MmioIntercept for NvmeController {
464 fn mmio_read(&mut self, addr: u64, data: &mut [u8]) -> IoResult {
465 match self.cfg_space.find_bar(addr) {
466 Some((0, offset)) => self.read_bar0(offset, data),
467 Some((4, offset)) => {
468 read_as_u32_chunks(offset, data, |offset| self.msix.read_u32(offset));
469 IoResult::Ok
470 }
471 _ => IoResult::Err(InvalidRegister),
472 }
473 }
474
475 fn mmio_write(&mut self, addr: u64, data: &[u8]) -> IoResult {
476 match self.cfg_space.find_bar(addr) {
477 Some((0, offset)) => self.write_bar0(offset, data),
478 Some((4, offset)) => {
479 write_as_u32_chunks(offset, data, |offset, ty| match ty {
480 ReadWriteRequestType::Read => Some(self.msix.read_u32(offset)),
481 ReadWriteRequestType::Write(val) => {
482 self.msix.write_u32(offset, val);
483 None
484 }
485 });
486 IoResult::Ok
487 }
488 _ => IoResult::Err(InvalidRegister),
489 }
490 }
491}
492
493impl PciConfigSpace for NvmeController {
494 fn pci_cfg_read(&mut self, offset: u16, value: ByteEnabledDwordRead<'_>) -> IoResult {
495 self.cfg_space.read_byte_enabled(offset, value)
496 }
497
498 fn pci_cfg_write(&mut self, offset: u16, value: ByteEnabledDwordWrite) -> IoResult {
499 self.cfg_space.write_byte_enabled(offset, value)
500 }
501}
502
503impl SaveRestore for NvmeController {
504 type SavedState = SavedStateNotSupported;
505
506 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
507 Err(SaveError::NotSupported)
508 }
509
510 fn restore(
511 &mut self,
512 state: Self::SavedState,
513 ) -> Result<(), vmcore::save_restore::RestoreError> {
514 match state {}
515 }
516}