1#![forbid(unsafe_code)]
36
37pub mod spec;
38
39use chipset_device::ChipsetDevice;
40use chipset_device::io::IoError;
41use chipset_device::io::IoResult;
42use chipset_device::mmio::MmioIntercept;
43use guestmem::GuestMemory;
44use guestmem::GuestMemoryError;
45use inspect::InspectMut;
46use parking_lot::RwLock;
47use parking_lot::RwLockWriteGuard;
48use pci_core::msi::SignalMsi;
49use spec::invalidation::DescriptorType;
50use spec::invalidation::DescriptorWidth;
51use spec::invalidation::InvalidationDescriptor256;
52use spec::invalidation::InvalidationError;
53use spec::invalidation::InvalidationWaitDw0Dw1;
54use spec::invalidation::InvalidationWaitDw2Dw3;
55use spec::irte::Irte;
56use spec::irte::IrteLo;
57use spec::irte::SourceValidationType;
58use spec::pte::SlPte;
59use spec::registers::CapReg;
60use spec::registers::CcmdReg;
61use spec::registers::EcapReg;
62use spec::registers::FaultReason;
63use spec::registers::FectlReg;
64use spec::registers::FrcdHi;
65use spec::registers::FrcdLo;
66use spec::registers::FstsReg;
67use spec::registers::GcmdReg;
68use spec::registers::GstsReg;
69use spec::registers::IcsReg;
70use spec::registers::IectlReg;
71use spec::registers::IotlbReg;
72use spec::registers::IqaReg;
73use spec::registers::IqhReg;
74use spec::registers::IqtReg;
75use spec::registers::IrtaReg;
76use spec::registers::MmioRegister as Reg;
77use spec::registers::NumDomains;
78use spec::registers::RtaddrReg;
79use spec::registers::TranslationTableMode;
80use spec::registers::VersionReg;
81use spec::root_context::AddressWidth;
82use spec::root_context::ContextEntry;
83use spec::root_context::RootEntry;
84use spec::root_context::TranslationType;
85use spec::scalable::PasidDirectoryEntry;
86use spec::scalable::PasidTableEntry;
87use spec::scalable::PasidTranslationType;
88use spec::scalable::ScalableContextEntry;
89use spec::scalable::ScalableRootEntry;
90use spec::scalable::ScalableValidationError;
91use std::ops::RangeInclusive;
92use std::sync::Arc;
93use zerocopy::FromBytes;
94use zerocopy::FromZeros;
95use zerocopy::Immutable;
96use zerocopy::IntoBytes;
97use zerocopy::KnownLayout;
98
99pub const MMIO_REGION_SIZE: u64 = spec::registers::MMIO_REGION_SIZE;
101
102const VER_VALUE: u32 = VersionReg::new().with_max(1).with_min(0).into_bits();
108
109const MGAW_BITS: u8 = 48;
111
112const HAW_BITS: u8 = 48;
115const HOST_ADDRESS_MASK: u64 = (1 << HAW_BITS) - 1;
116
117const MAX_AD_WALK_ATTEMPTS: usize = 16;
119
120const SAGAW_MASK: u8 = (1 << AddressWidth::AW_39BIT.0) | (1 << AddressWidth::AW_48BIT.0);
122
123const MAX_AGAW_BITS: u32 = 30 + 9 * SAGAW_MASK.ilog2();
125
126const NUM_FAULT_RECORDS: u8 = 1;
128
129const CAP_VALUE: u64 = CapReg::new()
131 .with_nd(NumDomains::ND_64K.0)
132 .with_afl(false)
133 .with_rwbf(false)
134 .with_cm(false)
135 .with_sagaw(SAGAW_MASK)
136 .with_mgaw(MGAW_BITS - 1)
137 .with_zlr(true)
138 .with_fro(Reg::FRCD_DW0.0 / 16)
139 .with_sllps(spec::registers::SLLPS_2MB | spec::registers::SLLPS_1GB)
140 .with_psi(true)
141 .with_nfr(NUM_FAULT_RECORDS - 1)
142 .with_mamv(30 - 12) .with_dwd(true)
144 .with_drd(true)
145 .into_bits();
146
147const ECAP_VALUE: u64 = EcapReg::new()
149 .with_c(true)
150 .with_qi(true)
151 .with_ir(true)
152 .with_eim(true)
153 .with_pt(true)
154 .with_sc(true)
155 .with_smts(true)
156 .with_ssts(true)
157 .with_smpwcs(true)
158 .with_ssads(true)
159 .with_rps(true)
160 .with_iro(Reg::IVA.0 / 16)
161 .with_mhmv(15) .into_bits();
163
164#[derive(Debug, Clone)]
170pub struct IntelVtdConfig {
171 pub mmio_base: u64,
173}
174
175#[derive(Debug, inspect::Inspect)]
184struct VtdState {
185 gsts: GstsReg,
188
189 rtaddr: RtaddrReg,
192 latched_rtaddr: RtaddrReg,
194
195 irta: IrtaReg,
198 latched_irta: IrtaReg,
200
201 ccmd: CcmdReg,
203
204 fsts: FstsReg,
207 fectl: FectlReg,
209 #[inspect(hex)]
211 fedata: u32,
212 #[inspect(hex)]
214 feaddr: u32,
215 #[inspect(hex)]
217 feuaddr: u32,
218 frcd_lo: FrcdLo,
220 frcd_hi: FrcdHi,
222
223 iqa: IqaReg,
226 iqh: IqhReg,
228 iqt: IqtReg,
230 ics: IcsReg,
232 iectl: IectlReg,
234 #[inspect(hex)]
236 iedata: u32,
237 #[inspect(hex)]
239 ieaddr: u32,
240 #[inspect(hex)]
242 ieuaddr: u32,
243
244 #[inspect(hex)]
247 iva: u64,
248 iotlb: IotlbReg,
250}
251
252impl VtdState {
253 fn new() -> Self {
254 Self {
255 fectl: FectlReg::new().with_im(true),
261 iectl: IectlReg::new().with_im(true),
262 gsts: GstsReg::new(),
263 rtaddr: RtaddrReg::new(),
264 latched_rtaddr: RtaddrReg::new(),
265 irta: IrtaReg::new(),
266 latched_irta: IrtaReg::new(),
267 ccmd: CcmdReg::new(),
268 fsts: FstsReg::new(),
269 fedata: 0,
270 feaddr: 0,
271 feuaddr: 0,
272 frcd_lo: FrcdLo::new(),
273 frcd_hi: FrcdHi::new(),
274 iqa: IqaReg::new(),
275 iqh: IqhReg::new(),
276 iqt: IqtReg::new(),
277 ics: IcsReg::new(),
278 iedata: 0,
279 ieaddr: 0,
280 ieuaddr: 0,
281 iva: 0,
282 iotlb: IotlbReg::new(),
283 }
284 }
285}
286
287struct InvalidationQueue {
289 base: u64,
290 size: u64,
291 width: DescriptorWidth,
292 head: u64,
293 pending: u64,
294}
295
296impl InvalidationQueue {
297 fn new(state: &VtdState, ecap: EcapReg) -> Result<Self, InvalidationError> {
298 let iqa = state.iqa;
299 let width = DescriptorWidth::checked(
300 iqa.dw(),
301 TranslationTableMode(state.latched_rtaddr.ttm()),
302 ecap,
303 )?;
304 let base = iqa.queue_base_address();
305 let size = iqa.queue_size_bytes();
306 if iqa.into_bits() & 0x7f8 != 0 || base.checked_add(size - 1).is_none() {
308 return Err(InvalidationError::QueueAddress);
309 }
310 let head = state.iqh.into_bits();
311 let tail = state.iqt.into_bits();
312 let stride = width.bytes() as u64;
313 if head >= size || !head.is_multiple_of(stride) {
314 return Err(InvalidationError::QueueHead(head));
315 }
316 if tail >= size || !tail.is_multiple_of(stride) {
317 return Err(InvalidationError::QueueTail(tail));
318 }
319 Ok(Self {
320 base,
321 size,
322 width,
323 head,
324 pending: (tail + size - head) % size / stride,
325 })
326 }
327}
328
329#[derive(Debug, Clone, Copy)]
335struct TranslationContext {
336 source_id: u16,
337 iova: u64,
338 mode: TranslationTableMode,
339 fpd: bool,
340}
341
342impl TranslationContext {
343 fn ad_fault(self, error: SecondStageAdError) -> VtdFault {
344 VtdFault::AdUpdate {
345 source_id: self.source_id,
346 iova: self.iova,
347 fpd: self.fpd,
348 error,
349 }
350 }
351
352 fn reason(self, legacy: FaultReason, scalable: FaultReason) -> FaultReason {
353 if self.mode == TranslationTableMode::LEGACY {
354 legacy
355 } else {
356 scalable
357 }
358 }
359
360 fn fault(self, reason: FaultReason) -> VtdFault {
361 let Self {
362 source_id,
363 iova,
364 fpd,
365 ..
366 } = self;
367 match reason {
368 FaultReason::ROOT_NOT_PRESENT => VtdFault::RootNotPresent { source_id, iova },
369 FaultReason::CONTEXT_NOT_PRESENT => VtdFault::ContextNotPresent {
370 source_id,
371 iova,
372 fpd,
373 },
374 FaultReason::INVALID_CONTEXT_ENTRY => VtdFault::InvalidContextEntry {
375 source_id,
376 iova,
377 fpd,
378 },
379 FaultReason::ADDRESS_BEYOND_MGAW => VtdFault::AddressBeyondMgaw {
380 source_id,
381 iova,
382 fpd,
383 },
384 FaultReason::WRITE_ACCESS_DENIED | FaultReason::READ_ACCESS_DENIED => {
385 VtdFault::AccessDenied {
386 source_id,
387 iova,
388 fpd,
389 write: reason == FaultReason::WRITE_ACCESS_DENIED,
390 }
391 }
392 FaultReason::ROOT_ENTRY_ACCESS_ERROR => {
393 VtdFault::RootEntryAccessError { source_id, iova }
394 }
395 FaultReason::CONTEXT_ENTRY_ACCESS_ERROR => {
396 VtdFault::ContextEntryAccessError { source_id, iova }
397 }
398 FaultReason::SL_PTE_ACCESS_ERROR => VtdFault::PageTableAccessError {
399 source_id,
400 iova,
401 fpd,
402 },
403 _ => VtdFault::Dma {
404 source_id,
405 iova,
406 reason,
407 fpd,
408 },
409 }
410 }
411}
412
413#[derive(Debug)]
415enum TranslationDescriptor {
416 PassThrough {
417 context: TranslationContext,
418 domain_id: u16,
419 },
420 SecondStage(SecondStageTranslation),
421}
422
423#[derive(Debug)]
424struct SecondStageTranslation {
425 context: TranslationContext,
426 root: u64,
427 levels: u8,
428 domain_id: u16,
429 ssade: bool,
430 pwsnp: bool,
431}
432
433pub struct VtdSharedState {
439 guest_memory: GuestMemory,
441 state: RwLock<VtdState>,
443 signal_msi: Arc<dyn SignalMsi>,
448 retranslate_interrupts: iommu_common::RetranslateInterruptsList,
450}
451
452impl VtdSharedState {
453 fn new(guest_memory: GuestMemory, signal_msi: Arc<dyn SignalMsi>) -> Self {
455 Self {
456 guest_memory,
457 state: RwLock::new(VtdState::new()),
458 signal_msi,
459 retranslate_interrupts: iommu_common::RetranslateInterruptsList::new(),
460 }
461 }
462
463 pub fn is_enabled(&self) -> bool {
465 let state = self.state.read();
466 state.gsts.tes()
467 }
468
469 pub fn is_ir_enabled(&self) -> bool {
471 let state = self.state.read();
472 state.gsts.ires()
473 }
474
475 pub fn translator(self: &Arc<Self>) -> VtdTranslator {
477 VtdTranslator {
478 shared: self.clone(),
479 }
480 }
481
482 pub fn wrap_signal_msi(self: &Arc<Self>, inner: Arc<dyn SignalMsi>) -> Arc<VtdSignalMsi> {
484 Arc::new(VtdSignalMsi {
485 shared: self.clone(),
486 inner,
487 })
488 }
489
490 fn deliver_fault_interrupt(&self, state: &VtdState) {
497 let fectl = state.fectl;
498 if fectl.im() {
499 return;
501 }
502 let addr = (state.feuaddr as u64) << 32 | (state.feaddr as u64);
503 let data = state.fedata;
504 self.signal_msi.signal_msi(None, addr, data);
505 }
506
507 fn deliver_invalidation_interrupt(&self, state: &VtdState) {
509 let iectl = state.iectl;
510 if iectl.im() {
511 return;
512 }
513 let addr = (state.ieuaddr as u64) << 32 | (state.ieaddr as u64);
514 let data = state.iedata;
515 self.signal_msi.signal_msi(None, addr, data);
516 }
517
518 fn record_fault_locked(
527 &self,
528 state: &mut VtdState,
529 source_id: u16,
530 fault_reason: FaultReason,
531 fault_addr: u64,
532 is_read: bool,
533 fpd: bool,
534 ) {
535 if fpd {
536 return;
537 }
538
539 if state.frcd_hi.f() {
541 let mut fsts = state.fsts;
543 fsts.set_pfo(true);
544 state.fsts = fsts;
545 return;
546 }
547
548 let frcd_lo = FrcdLo::new().with_fi((fault_addr & ((1 << MAX_AGAW_BITS) - 1)) >> 12);
550 let frcd_hi = FrcdHi::new()
551 .with_sid(source_id)
552 .with_fr(fault_reason.0)
553 .with_t(is_read)
554 .with_f(true);
555
556 state.frcd_lo = frcd_lo;
557 state.frcd_hi = frcd_hi;
558
559 let fectl = state.fectl;
562 if !fectl.im() {
563 self.deliver_fault_interrupt(state);
564 } else {
565 state.fectl = state.fectl.with_ip(true);
567 }
568 }
569
570 fn translate_locked(
579 &self,
580 state: &VtdState,
581 bus: u8,
582 devfn: u8,
583 iova: u64,
584 write: bool,
585 ecap: EcapReg,
586 ) -> Result<u64, VtdFault> {
587 if !state.gsts.tes() {
588 return Ok(iova);
589 }
590
591 let context = TranslationContext {
592 source_id: bdf(bus, devfn),
593 iova,
594 mode: TranslationTableMode(state.latched_rtaddr.ttm()),
595 fpd: false,
596 };
597 let root = state.latched_rtaddr.root_table_address();
598 let translation = match context.mode {
599 TranslationTableMode::LEGACY => self.resolve_legacy(root, context, ecap)?,
600 TranslationTableMode::SCALABLE if ecap.smts() => {
601 self.resolve_scalable(root, context, ecap)?
602 }
603 _ => return Err(context.fault(FaultReason::INVALID_ROOT_TABLE_MODE)),
604 };
605 match translation {
606 TranslationDescriptor::PassThrough { context, domain_id } => {
607 tracing::trace!(domain_id, "vtd: pass-through DMA");
608 if iova > HOST_ADDRESS_MASK {
609 return Err(context.fault(context.reason(
610 FaultReason::ADDRESS_BEYOND_MGAW,
611 FaultReason::SCALABLE_ADDRESS_BEYOND_HAW,
612 )));
613 }
614 Self::check_dma_output(context, iova)
615 }
616 TranslationDescriptor::SecondStage(translation) => {
617 self.walk_sl_page_table(&translation, write, ecap)
618 }
619 }
620 }
621
622 fn resolve_legacy(
623 &self,
624 root: u64,
625 mut context: TranslationContext,
626 ecap: EcapReg,
627 ) -> Result<TranslationDescriptor, VtdFault> {
628 let entry: RootEntry = self.read_translation_entry(
629 root,
630 u64::from(context.source_id >> 8),
631 context,
632 FaultReason::ROOT_ENTRY_ACCESS_ERROR,
633 )?;
634 if !entry.lo.p() {
635 return Err(context.fault(FaultReason::ROOT_NOT_PRESENT));
636 }
637 if entry.lo.into_bits() & (0xffe | !HOST_ADDRESS_MASK) != 0 || entry.hi != 0 {
638 return Err(context.fault(FaultReason::ROOT_ENTRY_RESERVED_BIT));
639 }
640 let entry: ContextEntry = self.read_translation_entry(
641 entry.lo.context_table_address(),
642 u64::from(context.source_id & 0xff),
643 context,
644 FaultReason::CONTEXT_ENTRY_ACCESS_ERROR,
645 )?;
646 context.fpd = entry.lo.fpd();
647 if !entry.lo.p() {
648 return Err(context.fault(FaultReason::CONTEXT_NOT_PRESENT));
649 }
650 if entry.lo.into_bits() & 0xff0 != 0 || entry.hi.into_bits() & 0xffff_ffff_ff00_0080 != 0 {
652 return Err(context.fault(FaultReason::CONTEXT_ENTRY_RESERVED_BIT));
653 }
654 let aw = AddressWidth(entry.hi.aw());
655 let domain_id = entry.hi.did();
656 match TranslationType(entry.lo.tt()) {
657 TranslationType::PASS_THROUGH if ecap.pt() => {
658 if Self::supported_levels(aw).is_none() {
662 return Err(context.fault(FaultReason::INVALID_CONTEXT_ENTRY));
663 }
664 Ok(TranslationDescriptor::PassThrough { context, domain_id })
665 }
666 TranslationType::UNTRANSLATED_ONLY | TranslationType::ALL => {
667 if entry.lo.page_table_address() > HOST_ADDRESS_MASK {
668 return Err(context.fault(FaultReason::CONTEXT_ENTRY_RESERVED_BIT));
669 }
670 let levels = Self::supported_levels(aw)
671 .ok_or_else(|| context.fault(FaultReason::INVALID_CONTEXT_ENTRY))?;
672 Ok(TranslationDescriptor::SecondStage(SecondStageTranslation {
673 context,
674 root: entry.lo.page_table_address(),
675 levels,
676 domain_id,
677 ssade: false,
678 pwsnp: ecap.c(),
679 }))
680 }
681 _ => Err(context.fault(FaultReason::INVALID_CONTEXT_ENTRY)),
682 }
683 }
684
685 fn resolve_scalable(
687 &self,
688 root: u64,
689 mut context: TranslationContext,
690 ecap: EcapReg,
691 ) -> Result<TranslationDescriptor, VtdFault> {
692 let devfn = context.source_id as u8;
693 let entry: ScalableRootEntry = self.read_translation_entry(
694 root,
695 u64::from(context.source_id >> 8),
696 context,
697 FaultReason::SCALABLE_ROOT_ACCESS_ERROR,
698 )?;
699 let half = entry.half(devfn);
700 half.validate(HAW_BITS).map_err(|error| {
701 context.fault(match error {
702 ScalableValidationError::NotPresent => FaultReason::SCALABLE_ROOT_NOT_PRESENT,
703 _ => FaultReason::SCALABLE_ROOT_RESERVED_BIT,
704 })
705 })?;
706
707 let entry: ScalableContextEntry = self.read_translation_entry(
708 half.context_table_address(),
709 ScalableContextEntry::table_index(devfn) as u64,
710 context,
711 FaultReason::SCALABLE_CONTEXT_ACCESS_ERROR,
712 )?;
713 context.fpd |= entry.lo.fpd();
714 if entry.lo.p() && !ecap.rps() && entry.hi.rid_pasid() != 0 {
717 return Err(context.fault(FaultReason::SCALABLE_CONTEXT_RESERVED_BIT));
718 }
719 entry.validate(HAW_BITS).map_err(|error| {
720 context.fault(match error {
721 ScalableValidationError::NotPresent => FaultReason::SCALABLE_CONTEXT_NOT_PRESENT,
722 ScalableValidationError::PasidOutOfRange { .. } => {
723 FaultReason::SCALABLE_INVALID_CONTEXT
724 }
725 _ => FaultReason::SCALABLE_CONTEXT_RESERVED_BIT,
726 })
727 })?;
728 let (directory_index, table_index) = entry
729 .pasid_indices(entry.hi.rid_pasid())
730 .map_err(|_| context.fault(FaultReason::SCALABLE_INVALID_CONTEXT))?;
731
732 let entry: PasidDirectoryEntry = self.read_translation_entry(
733 entry.directory_address(),
734 u64::from(directory_index),
735 context,
736 FaultReason::PASID_DIRECTORY_ACCESS_ERROR,
737 )?;
738 context.fpd |= entry.fpd();
739 entry.validate(HAW_BITS).map_err(|error| {
740 context.fault(match error {
741 ScalableValidationError::NotPresent => FaultReason::PASID_DIRECTORY_NOT_PRESENT,
742 _ => FaultReason::PASID_DIRECTORY_RESERVED_BIT,
743 })
744 })?;
745
746 let entry: PasidTableEntry = self.read_translation_entry(
747 entry.table_address(),
748 u64::from(table_index),
749 context,
750 FaultReason::PASID_TABLE_ACCESS_ERROR,
751 )?;
752 context.fpd |= entry.lo.fpd();
753 if entry.lo.p()
756 && ((!ecap.ssts()
757 && (entry.lo.aw() != 0 || entry.lo.ssptptr() != 0 || entry.lo.ssade()))
758 || (!ecap.ssads() && entry.lo.ssade())
759 || (!ecap.smpwcs() && entry.hi.pwsnp())
760 || (!ecap.sc() && entry.hi.pgsnp()))
761 {
762 return Err(context.fault(FaultReason::PASID_TABLE_RESERVED_BIT));
763 }
764 entry.validate(HAW_BITS).map_err(|error| {
765 context.fault(match error {
766 ScalableValidationError::NotPresent => FaultReason::PASID_TABLE_NOT_PRESENT,
767 ScalableValidationError::UnsupportedTranslationType(_)
768 | ScalableValidationError::UnsupportedAddressWidth(_) => {
769 FaultReason::PASID_TABLE_INVALID_ENTRY
770 }
771 _ => FaultReason::PASID_TABLE_RESERVED_BIT,
772 })
773 })?;
774 let domain_id = entry.hi.did();
775 match PasidTranslationType(entry.lo.pgtt()) {
776 PasidTranslationType::PASS_THROUGH if ecap.pt() => {
777 Ok(TranslationDescriptor::PassThrough { context, domain_id })
778 }
779 PasidTranslationType::SECOND_STAGE if ecap.ssts() => {
780 let levels = Self::supported_levels(AddressWidth(entry.lo.aw()))
781 .ok_or_else(|| context.fault(FaultReason::PASID_TABLE_INVALID_ENTRY))?;
782 Ok(TranslationDescriptor::SecondStage(SecondStageTranslation {
783 context,
784 root: entry.page_table_address(),
785 levels,
786 domain_id,
787 ssade: entry.lo.ssade(),
788 pwsnp: entry.hi.pwsnp(),
789 }))
790 }
791 _ => Err(context.fault(FaultReason::PASID_TABLE_INVALID_ENTRY)),
792 }
793 }
794
795 fn supported_levels(aw: AddressWidth) -> Option<u8> {
796 match aw {
797 AddressWidth::AW_39BIT => Some(3),
798 AddressWidth::AW_48BIT => Some(4),
799 _ => None,
800 }
801 }
802
803 fn read_translation_entry<T: FromBytes + KnownLayout + Immutable>(
804 &self,
805 base: u64,
806 index: u64,
807 context: TranslationContext,
808 reason: FaultReason,
809 ) -> Result<T, VtdFault> {
810 let address = Self::translation_entry_address::<T>(base, index)
811 .ok_or_else(|| context.fault(reason))?;
812 self.guest_memory
813 .read_plain(address)
814 .map_err(|_| context.fault(reason))
815 }
816
817 fn translation_entry_address<T>(base: u64, index: u64) -> Option<u64> {
818 let size = size_of::<T>() as u64;
819 index
820 .checked_mul(size)
821 .and_then(|offset| base.checked_add(offset))
822 .filter(|address| {
823 address
824 .checked_add(size - 1)
825 .is_some_and(|end| end <= HOST_ADDRESS_MASK)
826 })
827 }
828
829 fn check_dma_output(context: TranslationContext, gpa: u64) -> Result<u64, VtdFault> {
830 if gpa & !0xf_ffff == 0xfee0_0000 {
831 return Err(context.fault(context.reason(
832 FaultReason::OUTPUT_ADDR_IN_INTR_RANGE,
833 FaultReason::SCALABLE_OUTPUT_ADDR_IN_INTR_RANGE,
834 )));
835 }
836 Ok(gpa)
837 }
838
839 fn walk_sl_page_table(
841 &self,
842 translation: &SecondStageTranslation,
843 write: bool,
844 ecap: EcapReg,
845 ) -> Result<u64, VtdFault> {
846 self.walk_sl_page_table_with_cas(translation, write, ecap, |address, current, new| {
847 self.guest_memory
848 .compare_exchange::<u64>(address, current.to_le(), new.to_le())
849 .map(|result| result.is_ok())
850 })
851 }
852
853 fn walk_sl_page_table_with_cas(
856 &self,
857 translation: &SecondStageTranslation,
858 write: bool,
859 ecap: EcapReg,
860 mut compare_exchange: impl FnMut(u64, u64, u64) -> Result<bool, GuestMemoryError>,
861 ) -> Result<u64, VtdFault> {
862 let &SecondStageTranslation {
863 context,
864 root,
865 levels,
866 domain_id,
867 ssade,
868 pwsnp,
869 } = translation;
870 tracing::trace!(domain_id, ssade, pwsnp, "vtd: second-stage DMA");
871 if !matches!(levels, 3 | 4) {
872 return Err(context.fault(context.reason(
873 FaultReason::INVALID_CONTEXT_ENTRY,
874 FaultReason::PASID_TABLE_INVALID_ENTRY,
875 )));
876 }
877 let iova = context.iova;
878 if iova >> MGAW_BITS.min(12 + 9 * levels) != 0 {
879 return Err(context.fault(context.reason(
880 FaultReason::ADDRESS_BEYOND_MGAW,
881 FaultReason::SCALABLE_ADDRESS_BEYOND_AGAW,
882 )));
883 }
884 let track_ad = ssade && context.mode == TranslationTableMode::SCALABLE;
885
886 'walk: for _ in 0..MAX_AD_WALK_ATTEMPTS {
887 let mut table_addr = root;
888 let mut can_read = true;
889 let mut can_write = true;
890 for level in (1..=levels).rev() {
891 let reason = if level == levels {
894 context.reason(
895 FaultReason::INVALID_CONTEXT_ENTRY,
896 FaultReason::SCALABLE_SL_ROOT_ACCESS_ERROR,
897 )
898 } else {
899 context.reason(
900 FaultReason::SL_PTE_ACCESS_ERROR,
901 FaultReason::SCALABLE_SL_PTE_ACCESS_ERROR,
902 )
903 };
904 let address = Self::translation_entry_address::<u64>(
905 table_addr,
906 SlPte::iova_index(iova, level) as u64,
907 )
908 .ok_or_else(|| context.fault(reason))?;
909 let raw = self
910 .guest_memory
911 .read_plain::<u64>(address)
912 .map(u64::from_le)
913 .map_err(|_| context.fault(reason))?;
914 let pte = SlPte::from(raw);
915 can_read &= pte.r();
916 can_write &= pte.w();
917 let denied = context.reason(
918 if write {
919 FaultReason::WRITE_ACCESS_DENIED
920 } else {
921 FaultReason::READ_ACCESS_DENIED
922 },
923 if write {
924 FaultReason::SCALABLE_WRITE_ACCESS_DENIED
925 } else {
926 FaultReason::SCALABLE_READ_ACCESS_DENIED
927 },
928 );
929 if !pte.is_present() || (!can_read && !can_write) {
930 return Err(context
931 .fault(context.reason(denied, FaultReason::SCALABLE_SL_PTE_NOT_PRESENT)));
932 }
933
934 let leaf = level == 1 || (pte.ps() && matches!(level, 2 | 3));
935 let offset_mask = SlPte::page_size_at_level(level) - 1;
936 let reserved = (1 << 62)
937 | (((1u64 << 52) - 1) & !HOST_ADDRESS_MASK)
938 | if !leaf || !ecap.sc() { 1 << 11 } else { 0 }
939 | if level == 4 { 1 << 7 } else { 0 }
940 | if leaf { offset_mask & !0xfff } else { 0 };
941 if raw & reserved != 0 {
942 return Err(context.fault(context.reason(
943 FaultReason::SL_PTE_RESERVED_BIT,
944 FaultReason::SCALABLE_SL_PTE_RESERVED_BIT,
945 )));
946 }
947 let output = if leaf {
948 if (write && !can_write) || (!write && !can_read) {
949 return Err(context.fault(denied));
950 }
951 Some(Self::check_dma_output(
952 context,
953 pte.phys_address() | (iova & offset_mask),
954 )?)
955 } else {
956 None
957 };
958 let updated = pte
961 .with_a(true)
962 .with_d(pte.d() || (leaf && write))
963 .into_bits();
964 if track_ad && updated != raw {
965 if !ecap.smpwcs() || !pwsnp {
966 return Err(context.ad_fault(SecondStageAdError::NonSnooping));
967 }
968 if !compare_exchange(address, raw, updated)
969 .map_err(|error| context.ad_fault(SecondStageAdError::Memory(error)))?
970 {
971 continue 'walk;
975 }
976 }
977 if let Some(gpa) = output {
978 return Ok(gpa);
979 }
980 table_addr = pte.phys_address();
981 }
982 }
983 Err(context.ad_fault(SecondStageAdError::RetryExhausted))
984 }
985
986 fn remap_msi_locked(
994 &self,
995 state: &VtdState,
996 source_id: u16,
997 address: u64,
998 data: u32,
999 ) -> Result<(u64, u32), VtdFault> {
1000 let gsts = state.gsts;
1001 if !gsts.ires() {
1002 return Ok((address, data));
1004 }
1005
1006 let is_remappable = (address >> 4) & 1 != 0;
1008 if !is_remappable {
1009 return self.handle_compat_format(state, source_id, address, data);
1010 }
1011
1012 let irte_index = Self::extract_irte_index(address, data);
1014
1015 let irta = state.latched_irta;
1017 let max_entries = irta.entry_count();
1018 if irte_index as u32 >= max_entries {
1019 return Err(VtdFault::IrteIndexExceedsSize {
1020 source_id,
1021 irte_index,
1022 });
1023 }
1024
1025 let irt_base = irta.irt_base_address();
1027 let irte = self.lookup_irte(irt_base, irte_index, source_id)?;
1028
1029 self.validate_irte_source(source_id, &irte, irte_index)?;
1031
1032 let irte_lo = irte.lo;
1034 if irte_lo.im() {
1035 return Err(VtdFault::IrteReservedField {
1036 source_id,
1037 irte_index,
1038 fpd: irte_lo.fpd(),
1039 });
1040 }
1041
1042 let eime = irta.eime();
1044 let (new_address, new_data) = Self::construct_remapped_msi(irte_lo, eime);
1045
1046 Ok((new_address, new_data))
1047 }
1048
1049 fn handle_compat_format(
1051 &self,
1052 state: &VtdState,
1053 source_id: u16,
1054 address: u64,
1055 data: u32,
1056 ) -> Result<(u64, u32), VtdFault> {
1057 let irta = state.latched_irta;
1058 let gsts = state.gsts;
1059
1060 if irta.eime() {
1062 return Err(VtdFault::CompatibilityFormatBlocked { source_id });
1063 }
1064
1065 if gsts.cfis() {
1067 return Ok((address, data));
1068 }
1069
1070 Err(VtdFault::CompatibilityFormatBlocked { source_id })
1072 }
1073
1074 fn extract_irte_index(address: u64, data: u32) -> u16 {
1081 let handle_lo = ((address >> 5) & 0x7FFF) as u16; let handle_hi = ((address >> 2) & 1) as u16; let handle = (handle_hi << 15) | handle_lo;
1084
1085 let shv = (address >> 3) & 1 != 0;
1086 if shv {
1087 handle.wrapping_add(data as u16)
1088 } else {
1089 handle
1090 }
1091 }
1092
1093 fn lookup_irte(
1095 &self,
1096 irt_base: u64,
1097 irte_index: u16,
1098 source_id: u16,
1099 ) -> Result<Irte, VtdFault> {
1100 let entry_addr = irt_base + (irte_index as u64) * 16;
1101 let irte: Irte =
1102 self.guest_memory
1103 .read_plain(entry_addr)
1104 .map_err(|_| VtdFault::IrteAccessError {
1105 source_id,
1106 irte_index,
1107 })?;
1108
1109 if !irte.lo.p() {
1110 return Err(VtdFault::IrteNotPresent {
1111 source_id,
1112 irte_index,
1113 fpd: irte.lo.fpd(),
1114 });
1115 }
1116
1117 Ok(irte)
1118 }
1119
1120 fn validate_irte_source(
1122 &self,
1123 source_id: u16,
1124 irte: &Irte,
1125 irte_index: u16,
1126 ) -> Result<(), VtdFault> {
1127 let svt = SourceValidationType(irte.hi.svt());
1128 let irte_sid = irte.hi.sid();
1129 let sq = irte.hi.sq();
1130 let fpd = irte.lo.fpd();
1131
1132 match svt {
1133 SourceValidationType::NONE => Ok(()),
1134 SourceValidationType::VERIFY_SID => {
1135 let mask: u16 = match sq {
1138 0b00 => 0xFFFF,
1139 0b01 => !0x04,
1140 0b10 => !0x06,
1141 0b11 => !0x07,
1142 _ => 0xFFFF,
1143 };
1144 if (source_id & mask) != (irte_sid & mask) {
1145 Err(VtdFault::SourceValidationFailed {
1146 source_id,
1147 irte_index,
1148 fpd,
1149 })
1150 } else {
1151 Ok(())
1152 }
1153 }
1154 SourceValidationType::VERIFY_BUS_RANGE => {
1155 let start_bus = (irte_sid & 0xFF) as u8;
1157 let end_bus = ((irte_sid >> 8) & 0xFF) as u8;
1158 let source_bus = ((source_id >> 8) & 0xFF) as u8;
1159 if source_bus < start_bus || source_bus > end_bus {
1160 Err(VtdFault::SourceValidationFailed {
1161 source_id,
1162 irte_index,
1163 fpd,
1164 })
1165 } else {
1166 Ok(())
1167 }
1168 }
1169 _ => {
1170 Ok(())
1172 }
1173 }
1174 }
1175
1176 fn construct_remapped_msi(irte_lo: IrteLo, eime: bool) -> (u64, u32) {
1178 let dst = if eime {
1179 irte_lo.dst()
1181 } else {
1182 irte_lo.xapic_destination() as u32
1184 };
1185
1186 let new_address = x86defs::msi::MsiAddress::new()
1187 .with_address(x86defs::msi::MSI_ADDRESS)
1188 .with_virt_destination(dst as u16)
1189 .with_destination_mode_logical(irte_lo.dm())
1190 .with_redirection_hint(irte_lo.rh());
1191
1192 let new_data = x86defs::msi::MsiData::new()
1193 .with_vector(irte_lo.vector())
1194 .with_delivery_mode(irte_lo.dlm())
1195 .with_trigger_mode_level(irte_lo.tm());
1196
1197 (new_address.into_bits() as u64, new_data.into_bits())
1198 }
1199}
1200
1201#[derive(Debug, thiserror::Error)]
1207pub enum SecondStageAdError {
1208 #[error("second-stage A/D update requires page-walk snooping")]
1210 NonSnooping,
1211 #[error("second-stage A/D atomic memory access failed")]
1213 Memory(#[source] GuestMemoryError),
1214 #[error("second-stage A/D walk retry budget exhausted")]
1216 RetryExhausted,
1217}
1218
1219#[derive(Debug, thiserror::Error)]
1224#[expect(missing_docs)]
1225pub enum VtdFault {
1226 #[error("{error} (source_id={source_id:#06x}, iova={iova:#x})")]
1227 AdUpdate {
1228 source_id: u16,
1229 iova: u64,
1230 fpd: bool,
1231 #[source]
1232 error: SecondStageAdError,
1233 },
1234
1235 #[error("DMA fault {reason:?} (source_id={source_id:#06x}, iova={iova:#x})")]
1236 Dma {
1237 source_id: u16,
1238 iova: u64,
1239 reason: FaultReason,
1240 fpd: bool,
1241 },
1242
1243 #[error("root entry not present (source_id={source_id:#06x})")]
1244 RootNotPresent { source_id: u16, iova: u64 },
1245
1246 #[error("context entry not present (source_id={source_id:#06x})")]
1247 ContextNotPresent {
1248 source_id: u16,
1249 iova: u64,
1250 fpd: bool,
1251 },
1252
1253 #[error("invalid context entry (source_id={source_id:#06x}, iova={iova:#x})")]
1254 InvalidContextEntry {
1255 source_id: u16,
1256 iova: u64,
1257 fpd: bool,
1258 },
1259
1260 #[error("IOVA beyond MGAW (source_id={source_id:#06x}, iova={iova:#x})")]
1261 AddressBeyondMgaw {
1262 source_id: u16,
1263 iova: u64,
1264 fpd: bool,
1265 },
1266
1267 #[error("{} access denied (source_id={source_id:#06x}, iova={iova:#x})", if *write { "write" } else { "read" })]
1268 AccessDenied {
1269 source_id: u16,
1270 iova: u64,
1271 fpd: bool,
1272 write: bool,
1273 },
1274
1275 #[error("root entry access error (source_id={source_id:#06x})")]
1276 RootEntryAccessError { source_id: u16, iova: u64 },
1277
1278 #[error("context entry access error (source_id={source_id:#06x})")]
1279 ContextEntryAccessError { source_id: u16, iova: u64 },
1280
1281 #[error("page table access error (source_id={source_id:#06x}, iova={iova:#x})")]
1282 PageTableAccessError {
1283 source_id: u16,
1284 iova: u64,
1285 fpd: bool,
1286 },
1287
1288 #[error("IRTE not present (source_id={source_id:#06x}, index={irte_index})")]
1289 IrteNotPresent {
1290 source_id: u16,
1291 irte_index: u16,
1292 fpd: bool,
1293 },
1294
1295 #[error("IRTE access error (source_id={source_id:#06x}, index={irte_index})")]
1296 IrteAccessError { source_id: u16, irte_index: u16 },
1297
1298 #[error("IRTE index exceeds IRT size (source_id={source_id:#06x}, index={irte_index})")]
1299 IrteIndexExceedsSize { source_id: u16, irte_index: u16 },
1300
1301 #[error("IRTE reserved field set (source_id={source_id:#06x}, index={irte_index})")]
1302 IrteReservedField {
1303 source_id: u16,
1304 irte_index: u16,
1305 fpd: bool,
1306 },
1307
1308 #[error("source validation failed (source_id={source_id:#06x})")]
1309 SourceValidationFailed {
1310 source_id: u16,
1311 irte_index: u16,
1312 fpd: bool,
1313 },
1314
1315 #[error("compatibility-format interrupt blocked (source_id={source_id:#06x})")]
1316 CompatibilityFormatBlocked { source_id: u16 },
1317}
1318
1319impl VtdFault {
1320 fn fault_reason(&self) -> FaultReason {
1322 match self {
1323 Self::AdUpdate { error, .. } => match error {
1324 SecondStageAdError::NonSnooping => FaultReason::SL_AD_UPDATE_NON_SNOOP,
1325 SecondStageAdError::Memory(_) | SecondStageAdError::RetryExhausted => {
1326 FaultReason::SL_AD_UPDATE_FAILED
1327 }
1328 },
1329 Self::Dma { reason, .. } => *reason,
1330 Self::RootNotPresent { .. } => FaultReason::ROOT_NOT_PRESENT,
1331 Self::ContextNotPresent { .. } => FaultReason::CONTEXT_NOT_PRESENT,
1332 Self::InvalidContextEntry { .. } => FaultReason::INVALID_CONTEXT_ENTRY,
1333 Self::AddressBeyondMgaw { .. } => FaultReason::ADDRESS_BEYOND_MGAW,
1334 Self::AccessDenied { write: true, .. } => FaultReason::WRITE_ACCESS_DENIED,
1335 Self::AccessDenied { write: false, .. } => FaultReason::READ_ACCESS_DENIED,
1336 Self::RootEntryAccessError { .. } => FaultReason::ROOT_ENTRY_ACCESS_ERROR,
1337 Self::ContextEntryAccessError { .. } => FaultReason::CONTEXT_ENTRY_ACCESS_ERROR,
1338 Self::PageTableAccessError { .. } => FaultReason::SL_PTE_ACCESS_ERROR,
1339 Self::IrteNotPresent { .. } => FaultReason::IRTE_NOT_PRESENT,
1340 Self::IrteAccessError { .. } => FaultReason::IRTE_ACCESS_ERROR,
1341 Self::IrteIndexExceedsSize { .. } => FaultReason::IR_INDEX_EXCEEDS_SIZE,
1342 Self::IrteReservedField { .. } => FaultReason::IRTE_RESERVED_FIELD,
1343 Self::SourceValidationFailed { .. } => FaultReason::SOURCE_ID_VERIFICATION_FAIL,
1344 Self::CompatibilityFormatBlocked { .. } => FaultReason::COMPAT_FORMAT_BLOCKED,
1345 }
1346 }
1347
1348 fn source_id(&self) -> u16 {
1350 match self {
1351 Self::AdUpdate { source_id, .. }
1352 | Self::Dma { source_id, .. }
1353 | Self::RootNotPresent { source_id, .. }
1354 | Self::ContextNotPresent { source_id, .. }
1355 | Self::InvalidContextEntry { source_id, .. }
1356 | Self::AddressBeyondMgaw { source_id, .. }
1357 | Self::AccessDenied { source_id, .. }
1358 | Self::RootEntryAccessError { source_id, .. }
1359 | Self::ContextEntryAccessError { source_id, .. }
1360 | Self::PageTableAccessError { source_id, .. }
1361 | Self::IrteNotPresent { source_id, .. }
1362 | Self::IrteAccessError { source_id, .. }
1363 | Self::IrteIndexExceedsSize { source_id, .. }
1364 | Self::IrteReservedField { source_id, .. }
1365 | Self::SourceValidationFailed { source_id, .. }
1366 | Self::CompatibilityFormatBlocked { source_id, .. } => *source_id,
1367 }
1368 }
1369
1370 fn fault_address(&self) -> u64 {
1372 match self {
1373 Self::AdUpdate { iova, .. }
1374 | Self::Dma { iova, .. }
1375 | Self::RootNotPresent { iova, .. }
1376 | Self::ContextNotPresent { iova, .. }
1377 | Self::InvalidContextEntry { iova, .. }
1378 | Self::AddressBeyondMgaw { iova, .. }
1379 | Self::AccessDenied { iova, .. }
1380 | Self::RootEntryAccessError { iova, .. }
1381 | Self::ContextEntryAccessError { iova, .. }
1382 | Self::PageTableAccessError { iova, .. } => *iova,
1383 Self::IrteNotPresent { .. }
1385 | Self::IrteAccessError { .. }
1386 | Self::IrteIndexExceedsSize { .. }
1387 | Self::IrteReservedField { .. }
1388 | Self::SourceValidationFailed { .. }
1389 | Self::CompatibilityFormatBlocked { .. } => 0,
1390 }
1391 }
1392
1393 fn fpd(&self) -> bool {
1395 match self {
1396 Self::Dma { reason, fpd, .. } => {
1399 *fpd && !matches!(
1400 *reason,
1401 FaultReason::INVALID_ROOT_TABLE_MODE
1402 | FaultReason::SCALABLE_ROOT_ACCESS_ERROR
1403 | FaultReason::SCALABLE_ROOT_NOT_PRESENT
1404 | FaultReason::SCALABLE_ROOT_RESERVED_BIT
1405 | FaultReason::SCALABLE_CONTEXT_ACCESS_ERROR
1406 | FaultReason::PASID_DIRECTORY_ACCESS_ERROR
1407 | FaultReason::PASID_TABLE_ACCESS_ERROR
1408 )
1409 }
1410 Self::AdUpdate { fpd, .. }
1411 | Self::ContextNotPresent { fpd, .. }
1412 | Self::AddressBeyondMgaw { fpd, .. }
1413 | Self::InvalidContextEntry { fpd, .. }
1414 | Self::AccessDenied { fpd, .. }
1415 | Self::PageTableAccessError { fpd, .. }
1416 | Self::IrteNotPresent { fpd, .. }
1417 | Self::IrteReservedField { fpd, .. }
1418 | Self::SourceValidationFailed { fpd, .. } => *fpd,
1419 Self::RootNotPresent { .. }
1421 | Self::RootEntryAccessError { .. }
1422 | Self::ContextEntryAccessError { .. }
1423 | Self::IrteAccessError { .. }
1424 | Self::IrteIndexExceedsSize { .. }
1425 | Self::CompatibilityFormatBlocked { .. } => false,
1426 }
1427 }
1428
1429 fn record(&self, shared: &VtdSharedState, is_write: bool) {
1437 let mut state = shared.state.write();
1438 shared.record_fault_locked(
1439 &mut state,
1440 self.source_id(),
1441 self.fault_reason(),
1442 self.fault_address(),
1443 !is_write, self.fpd(),
1445 );
1446 }
1447}
1448
1449fn bdf(bus: u8, devfn: u8) -> u16 {
1451 ((bus as u16) << 8) | devfn as u16
1452}
1453
1454#[derive(Clone)]
1463pub struct VtdTranslator {
1464 shared: Arc<VtdSharedState>,
1465}
1466
1467impl iommu_common::IommuTranslator for VtdTranslator {
1468 type Error = VtdFault;
1469
1470 fn max_iova(&self) -> u64 {
1471 (1u64 << 48) - 1
1473 }
1474
1475 fn translate<R>(
1476 &self,
1477 rid: u16,
1478 iova: u64,
1479 write: bool,
1480 op: impl FnOnce(u64) -> R,
1481 ) -> Result<R, iommu_common::TranslationFault<VtdFault>> {
1482 self.translate_with_capabilities(rid, iova, write, EcapReg::from(ECAP_VALUE), op)
1483 }
1484}
1485
1486impl VtdTranslator {
1487 fn translate_with_capabilities<R>(
1488 &self,
1489 rid: u16,
1490 iova: u64,
1491 write: bool,
1492 ecap: EcapReg,
1493 op: impl FnOnce(u64) -> R,
1494 ) -> Result<R, iommu_common::TranslationFault<VtdFault>> {
1495 let bus = (rid >> 8) as u8;
1496 let devfn = rid as u8;
1497 self.translate_with(
1498 iova,
1499 write,
1500 |state| {
1501 self.shared
1502 .translate_locked(state, bus, devfn, iova, write, ecap)
1503 },
1504 op,
1505 )
1506 }
1507
1508 fn translate_with<R>(
1509 &self,
1510 iova: u64,
1511 write: bool,
1512 translate: impl FnOnce(&VtdState) -> Result<u64, VtdFault>,
1513 op: impl FnOnce(u64) -> R,
1514 ) -> Result<R, iommu_common::TranslationFault<VtdFault>> {
1515 let state = self.shared.state.read();
1517 let gpa = match translate(&state) {
1518 Ok(gpa) => gpa,
1519 Err(fault) => {
1520 drop(state);
1522 fault.record(&self.shared, write);
1523 return Err(iommu_common::TranslationFault { iova, error: fault });
1524 }
1525 };
1526
1527 let result = op(gpa);
1528 drop(state);
1529 Ok(result)
1530 }
1531}
1532
1533pub struct VtdSignalMsi {
1542 shared: Arc<VtdSharedState>,
1543 inner: Arc<dyn SignalMsi>,
1544}
1545
1546impl SignalMsi for VtdSignalMsi {
1547 fn signal_msi(&self, devid: Option<u32>, address: u64, data: u32) {
1548 let Some(device_id) = devid else {
1549 return;
1552 };
1553 let source_id = device_id as u16;
1554
1555 let state = self.shared.state.read();
1556 match self
1557 .shared
1558 .remap_msi_locked(&state, source_id, address, data)
1559 {
1560 Ok((new_address, new_data)) => {
1561 drop(state);
1562 self.inner.signal_msi(devid, new_address, new_data);
1563 }
1564 Err(fault) => {
1565 drop(state);
1566 tracelimit::warn_ratelimited!(
1567 source_id,
1568 address,
1569 data,
1570 error = &fault as &dyn std::error::Error,
1571 "vtd: MSI remapping fault, interrupt dropped"
1572 );
1573 fault.record(&self.shared, true);
1575 }
1576 }
1577 }
1578}
1579
1580impl iommu_common::InterruptRemapper for VtdSharedState {
1581 fn remap_msi(&self, device_id: u16, address: u64, data: u32) -> Option<(u64, u32)> {
1582 let state = self.state.read();
1583 match self.remap_msi_locked(&state, device_id, address, data) {
1584 Ok(result) => Some(result),
1585 Err(fault) => {
1586 drop(state);
1587 tracelimit::warn_ratelimited!(
1593 device_id,
1594 address,
1595 data,
1596 error = &fault as &dyn std::error::Error,
1597 "vtd: interrupt remapping fault on registered-route delivery, dropping interrupt"
1598 );
1599 fault.record(self, true);
1600 None
1601 }
1602 }
1603 }
1604
1605 fn register_route(&self, route: &Arc<dyn iommu_common::RetranslateInterrupts>) {
1606 self.retranslate_interrupts.register(route);
1607 }
1608
1609 fn unregister_route(&self, route: &Arc<dyn iommu_common::RetranslateInterrupts>) {
1610 self.retranslate_interrupts.unregister(route);
1611 }
1612}
1613
1614pub struct IntelVtdDevice {
1624 mmio_base: u64,
1626 mmio_region: (&'static str, RangeInclusive<u64>),
1628 shared: Arc<VtdSharedState>,
1630}
1631
1632impl IntelVtdDevice {
1633 pub fn new(
1639 guest_memory: GuestMemory,
1640 config: IntelVtdConfig,
1641 signal_msi: Arc<dyn SignalMsi>,
1642 ) -> (Self, Arc<VtdSharedState>) {
1643 let mmio_base = config.mmio_base;
1644 let shared = Arc::new(VtdSharedState::new(guest_memory, signal_msi));
1645
1646 let device = Self {
1647 mmio_base,
1648 mmio_region: (
1649 "intel-vtd-mmio",
1650 mmio_base..=mmio_base + MMIO_REGION_SIZE - 1,
1651 ),
1652 shared: shared.clone(),
1653 };
1654
1655 (device, shared)
1656 }
1657
1658 pub fn shared_state(&self) -> &Arc<VtdSharedState> {
1660 &self.shared
1661 }
1662
1663 fn read_register_dword(&self, offset: u16) -> u32 {
1673 let state = self.shared.state.read();
1674 self.read_register_dword_locked(&state, offset)
1675 }
1676
1677 fn read_register_dword_locked(&self, state: &VtdState, offset: u16) -> u32 {
1679 fn lo(val: u64) -> u32 {
1681 val as u32
1682 }
1683 fn hi(val: u64) -> u32 {
1685 (val >> 32) as u32
1686 }
1687
1688 match Reg(offset) {
1689 Reg::VER => VER_VALUE,
1690 Reg::CAP => lo(CAP_VALUE),
1691 Reg::CAP_HI => hi(CAP_VALUE),
1692 Reg::ECAP => lo(ECAP_VALUE),
1693 Reg::ECAP_HI => hi(ECAP_VALUE),
1694 Reg::GCMD => 0, Reg::GSTS => state.gsts.into_bits(),
1696 Reg::RTADDR => lo(state.rtaddr.into_bits()),
1697 Reg::RTADDR_HI => hi(state.rtaddr.into_bits()),
1698 Reg::CCMD => lo(state.ccmd.into_bits()),
1699 Reg::CCMD_HI => hi(state.ccmd.into_bits()),
1700 Reg::FSTS => self.read_fsts(state),
1701 Reg::FECTL => state.fectl.into_bits(),
1702 Reg::FEDATA => state.fedata,
1703 Reg::FEADDR => state.feaddr,
1704 Reg::FEUADDR => state.feuaddr,
1705 Reg::IQH => lo(state.iqh.into_bits()),
1706 Reg::IQH_HI => hi(state.iqh.into_bits()),
1707 Reg::IQT => lo(state.iqt.into_bits()),
1708 Reg::IQT_HI => hi(state.iqt.into_bits()),
1709 Reg::IQA => lo(state.iqa.into_bits()),
1710 Reg::IQA_HI => hi(state.iqa.into_bits()),
1711 Reg::ICS => state.ics.into_bits(),
1712 Reg::IECTL => state.iectl.into_bits(),
1713 Reg::IEDATA => state.iedata,
1714 Reg::IEADDR => state.ieaddr,
1715 Reg::IEUADDR => state.ieuaddr,
1716 Reg::IRTA => lo(state.irta.into_bits()),
1717 Reg::IRTA_HI => hi(state.irta.into_bits()),
1718 Reg::IVA => lo(state.iva),
1719 Reg::IVA_HI => hi(state.iva),
1720 Reg::IOTLB => lo(state.iotlb.into_bits()),
1721 Reg::IOTLB_HI => hi(state.iotlb.into_bits()),
1722 Reg::FRCD_DW0 => lo(state.frcd_lo.into_bits()),
1723 Reg::FRCD_DW1 => hi(state.frcd_lo.into_bits()),
1724 Reg::FRCD_DW2 => lo(state.frcd_hi.into_bits()),
1725 Reg::FRCD_DW3 => hi(state.frcd_hi.into_bits()),
1726 _ => 0,
1727 }
1728 }
1729
1730 fn read_fsts(&self, state: &VtdState) -> u32 {
1732 let mut fsts = state.fsts;
1733 fsts.set_ppf(state.frcd_hi.f());
1736 fsts.into_bits()
1737 }
1738
1739 fn reconcile_fault_interrupt(&self, state: &mut VtdState) {
1742 let fsts = FstsReg::from(self.read_fsts(state));
1743 if !fsts.ppf() && !fsts.pfo() && !fsts.iqe() && !fsts.ice() && !fsts.ite() {
1744 state.fectl.set_ip(false);
1745 }
1746 }
1747
1748 fn write_register_dword(&mut self, offset: u16, value: u32) {
1759 let mut state = self.shared.state.write();
1760 let mut process_queue = false;
1761 tracing::trace!(offset, value, "vtd mmio_write_dword");
1762
1763 fn write_lo(old: u64, value: u32) -> u64 {
1765 (old & !0xFFFF_FFFF) | value as u64
1766 }
1767 fn write_hi(old: u64, value: u32) -> u64 {
1768 (old & 0xFFFF_FFFF) | ((value as u64) << 32)
1769 }
1770
1771 match Reg(offset) {
1772 Reg::VER
1774 | Reg::CAP
1775 | Reg::CAP_HI
1776 | Reg::ECAP
1777 | Reg::ECAP_HI
1778 | Reg::GSTS
1779 | Reg::IQH
1780 | Reg::IQH_HI
1781 | Reg::FRCD_DW0
1782 | Reg::FRCD_DW1
1783 | Reg::FRCD_DW2 => {}
1784
1785 Reg::GCMD => {
1786 self.process_gcmd(&mut state, value);
1787 process_queue = true;
1788 }
1789
1790 Reg::RTADDR => {
1791 state.rtaddr = RtaddrReg::from(write_lo(state.rtaddr.into_bits(), value));
1792 }
1793 Reg::RTADDR_HI => {
1794 state.rtaddr = RtaddrReg::from(write_hi(state.rtaddr.into_bits(), value));
1795 }
1796
1797 Reg::CCMD => {
1798 state.ccmd = CcmdReg::from(write_lo(state.ccmd.into_bits(), value));
1799 }
1800 Reg::CCMD_HI => {
1801 let full = write_hi(state.ccmd.into_bits(), value);
1803 self.process_ccmd(&mut state, full);
1804 }
1805
1806 Reg::FSTS => {
1807 let write_val = FstsReg::from(value);
1808 let mut fsts = state.fsts;
1809 if write_val.pfo() {
1810 fsts.set_pfo(false);
1811 }
1812 if write_val.iqe() {
1813 fsts.set_iqe(false);
1814 }
1815 if write_val.ice() {
1816 fsts.set_ice(false);
1817 }
1818 if write_val.ite() {
1819 fsts.set_ite(false);
1820 }
1821 state.fsts = fsts;
1822 self.reconcile_fault_interrupt(&mut state);
1823 process_queue = write_val.iqe() || write_val.ite();
1824 }
1825
1826 Reg::FECTL => {
1827 let new = FectlReg::from(value);
1828 let old = state.fectl;
1829 state.fectl = FectlReg::new().with_im(new.im()).with_ip(old.ip());
1830 if old.im() && !new.im() && old.ip() {
1831 state.fectl = state.fectl.with_ip(false);
1832 self.shared.deliver_fault_interrupt(&state);
1833 }
1834 }
1835
1836 Reg::FEDATA => state.fedata = value,
1837 Reg::FEADDR => state.feaddr = value,
1838 Reg::FEUADDR => state.feuaddr = value,
1839
1840 Reg::IQT => {
1841 state.iqt = IqtReg::from(write_lo(state.iqt.into_bits(), value));
1842 process_queue = true;
1843 }
1844 Reg::IQT_HI => {
1845 state.iqt = IqtReg::from(write_hi(state.iqt.into_bits(), value));
1846 process_queue = true;
1847 }
1848
1849 Reg::IQA => {
1850 if !state.gsts.qies() {
1851 state.iqa = IqaReg::from(write_lo(state.iqa.into_bits(), value));
1852 } else {
1853 tracelimit::warn_ratelimited!("vtd: write to IQA while QIE=1, ignored");
1854 }
1855 }
1856 Reg::IQA_HI => {
1857 if !state.gsts.qies() {
1858 state.iqa = IqaReg::from(write_hi(state.iqa.into_bits(), value));
1859 } else {
1860 tracelimit::warn_ratelimited!("vtd: write to IQA while QIE=1, ignored");
1861 }
1862 }
1863
1864 Reg::ICS => {
1865 let write_val = IcsReg::from(value);
1866 let mut ics = state.ics;
1867 if write_val.iwc() {
1868 ics.set_iwc(false);
1869 state.iectl.set_ip(false);
1870 }
1871 state.ics = ics;
1872 }
1873
1874 Reg::IECTL => {
1875 let new = IectlReg::from(value);
1876 let old = state.iectl;
1877 state.iectl = IectlReg::new().with_im(new.im()).with_ip(old.ip());
1878 if old.im() && !new.im() && old.ip() {
1879 state.iectl = state.iectl.with_ip(false);
1880 self.shared.deliver_invalidation_interrupt(&state);
1881 }
1882 }
1883
1884 Reg::IEDATA => state.iedata = value,
1885 Reg::IEADDR => state.ieaddr = value,
1886 Reg::IEUADDR => state.ieuaddr = value,
1887
1888 Reg::IRTA => {
1889 if !state.gsts.ires() {
1890 state.irta = IrtaReg::from(write_lo(state.irta.into_bits(), value));
1891 } else {
1892 tracelimit::warn_ratelimited!("vtd: write to IRTA while IRE=1, ignored");
1893 }
1894 }
1895 Reg::IRTA_HI => {
1896 if !state.gsts.ires() {
1897 state.irta = IrtaReg::from(write_hi(state.irta.into_bits(), value));
1898 } else {
1899 tracelimit::warn_ratelimited!("vtd: write to IRTA while IRE=1, ignored");
1900 }
1901 }
1902
1903 Reg::IVA => state.iva = write_lo(state.iva, value),
1904 Reg::IVA_HI => state.iva = write_hi(state.iva, value),
1905
1906 Reg::IOTLB => {
1907 state.iotlb = IotlbReg::from(write_lo(state.iotlb.into_bits(), value));
1908 }
1909 Reg::IOTLB_HI => {
1910 let full = write_hi(state.iotlb.into_bits(), value);
1912 self.process_iotlb_reg(&mut state, full);
1913 }
1914
1915 Reg::FRCD_DW3 => {
1916 if (value >> 31) & 1 != 0 {
1918 state.frcd_hi = state.frcd_hi.with_f(false);
1919 self.reconcile_fault_interrupt(&mut state);
1920 }
1921 }
1922
1923 _ => {} }
1925
1926 drop(state);
1927 if process_queue {
1928 self.process_invalidation_queue();
1929 }
1930 }
1931
1932 fn process_gcmd(&self, state: &mut VtdState, value: u32) {
1942 let gcmd = GcmdReg::from(value);
1943 let mut gsts = state.gsts;
1944
1945 if gcmd.srtp() {
1947 state.latched_rtaddr = state.rtaddr;
1948 gsts.set_rtps(true);
1949 }
1950
1951 if gcmd.sirtp() {
1953 state.latched_irta = state.irta;
1954 gsts.set_irtps(true);
1955 }
1956
1957 if gcmd.wbf() {
1959 gsts.set_wbfs(true);
1961 }
1962
1963 if gcmd.sfl() {
1966 gsts.set_fls(true);
1967 }
1968 if gcmd.eafl() {
1969 gsts.set_afls(true);
1970 }
1971
1972 if gcmd.qie() != gsts.qies() {
1974 if gcmd.qie() {
1975 gsts.set_qies(true);
1977 state.iqh = IqhReg::new();
1979 } else {
1980 if gsts.tes() || gsts.ires() {
1982 tracelimit::warn_ratelimited!(
1983 "vtd: cannot disable QIE while TE or IRE is enabled"
1984 );
1985 } else {
1986 gsts.set_qies(false);
1987 state.iqh = IqhReg::new();
1988 }
1989 }
1990 }
1991
1992 if gcmd.te() != gsts.tes() {
1994 if gcmd.te() {
1995 if !gsts.rtps() {
1997 tracelimit::warn_ratelimited!(
1998 "vtd: cannot enable TE without root table pointer set (RTPS=0)"
1999 );
2000 } else {
2001 gsts.set_tes(true);
2002 }
2003 } else {
2004 gsts.set_tes(false);
2005 }
2006 }
2007
2008 if gcmd.ire() != gsts.ires() {
2010 if gcmd.ire() {
2011 if !gsts.irtps() {
2013 tracelimit::warn_ratelimited!(
2014 "vtd: cannot enable IRE without IRT pointer set (IRTPS=0)"
2015 );
2016 } else {
2017 gsts.set_ires(true);
2018 }
2019 } else {
2020 gsts.set_ires(false);
2021 }
2022 }
2023
2024 if gcmd.cfi() != gsts.cfis() {
2026 gsts.set_cfis(gcmd.cfi());
2027 }
2028
2029 state.gsts = gsts;
2030 }
2031
2032 fn process_ccmd(&self, state: &mut VtdState, value: u64) {
2041 let ccmd = CcmdReg::from(value);
2042 if ccmd.icc() {
2043 state.ccmd = ccmd.with_icc(false).with_caig(ccmd.cirg());
2045 } else {
2046 state.ccmd = CcmdReg::from(value);
2047 }
2048 }
2049
2050 fn process_iotlb_reg(&self, state: &mut VtdState, value: u64) {
2054 let reg = IotlbReg::from(value);
2055 if reg.ivt() {
2056 state.iotlb = reg.with_ivt(false).with_iaig(reg.iirg());
2058 } else {
2059 state.iotlb = IotlbReg::from(value);
2060 }
2061 }
2062
2063 fn process_invalidation_queue(&mut self) {
2073 let cap = CapReg::from(CAP_VALUE);
2074 let ecap = EcapReg::from(ECAP_VALUE);
2075 let mut state = self.shared.state.write();
2076 if !state.gsts.qies() || state.fsts.iqe() || state.fsts.ite() {
2077 return;
2078 }
2079 let mut queue = match InvalidationQueue::new(&state, ecap) {
2080 Ok(queue) => queue,
2081 Err(err) => {
2082 tracelimit::warn_ratelimited!(
2083 error = &err as &dyn std::error::Error,
2084 "vtd: invalid queue"
2085 );
2086 self.invalidation_queue_error(&mut state);
2087 return;
2088 }
2089 };
2090 let mode = TranslationTableMode(state.latched_rtaddr.ttm());
2091 for _ in 0..queue.pending {
2094 let entry_addr = queue.base + queue.head;
2095 let mut desc = InvalidationDescriptor256::new_zeroed();
2096 if let Err(err) = self
2097 .shared
2098 .guest_memory
2099 .read_at(entry_addr, &mut desc.as_mut_bytes()[..queue.width.bytes()])
2100 {
2101 tracelimit::warn_ratelimited!(
2102 error = &err as &dyn std::error::Error,
2103 addr = entry_addr,
2104 "vtd: failed to read invalidation queue descriptor"
2105 );
2106 self.invalidation_queue_error(&mut state);
2107 break;
2108 }
2109 if let Err(err) = desc.validate(queue.width, mode, cap, ecap) {
2110 tracelimit::warn_ratelimited!(
2111 error = &err as &dyn std::error::Error,
2112 addr = entry_addr,
2113 "vtd: invalid invalidation descriptor"
2114 );
2115 self.invalidation_queue_error(&mut state);
2116 break;
2117 }
2118 match desc.lower.descriptor_type() {
2119 DescriptorType::CONTEXT_CACHE_INVALIDATE
2120 | DescriptorType::IOTLB_INVALIDATE
2121 | DescriptorType::PASID_CACHE_INVALIDATE
2122 | DescriptorType::PASID_IOTLB_INVALIDATE => {
2123 }
2126 DescriptorType::INTERRUPT_ENTRY_CACHE_INVALIDATE => {
2127 let desc = spec::invalidation::parse_interrupt_cache_invalidate(&desc.lower);
2128 tracing::trace!(
2129 granularity = desc.granularity(),
2130 im = desc.im(),
2131 iidx = desc.iidx(),
2132 "vtd: interrupt entry cache invalidate"
2133 );
2134 RwLockWriteGuard::unlocked(&mut state, || {
2139 self.shared.retranslate_interrupts.invalidate(None);
2140 });
2141 }
2142 DescriptorType::INVALIDATION_WAIT => {
2143 let (lo, hi) = spec::invalidation::parse_invalidation_wait(&desc.lower);
2144 if !self.process_invalidation_wait(&mut state, lo, hi) {
2145 break;
2146 }
2147 }
2148 dt => {
2149 tracelimit::warn_ratelimited!(?dt, "vtd: unknown invalidation descriptor type");
2150 self.invalidation_queue_error(&mut state);
2151 break;
2152 }
2153 }
2154
2155 queue.head = (queue.head + queue.width.bytes() as u64) % queue.size;
2157 state.iqh = IqhReg::from(queue.head);
2158 }
2159 }
2160
2161 fn invalidation_queue_error(&self, state: &mut VtdState) {
2162 state.fsts.set_iqe(true);
2163 if state.fectl.im() {
2164 state.fectl.set_ip(true);
2165 } else {
2166 self.shared.deliver_fault_interrupt(state);
2167 }
2168 }
2169
2170 fn process_invalidation_wait(
2172 &self,
2173 state: &mut VtdState,
2174 lo: InvalidationWaitDw0Dw1,
2175 hi: InvalidationWaitDw2Dw3,
2176 ) -> bool {
2177 if lo.sw() {
2178 let status_address = hi.status_address();
2179
2180 if let Err(e) = self
2181 .shared
2182 .guest_memory
2183 .write_at(status_address, &lo.status_data().to_le_bytes())
2184 {
2185 tracelimit::warn_ratelimited!(
2186 error = &e as &dyn std::error::Error,
2187 addr = status_address,
2188 "vtd: failed to write invalidation wait status"
2189 );
2190 self.invalidation_queue_error(state);
2192 return false;
2193 }
2194 }
2195
2196 if lo.iflag() && !state.ics.iwc() {
2197 let mut ics = state.ics;
2199 ics.set_iwc(true);
2200 state.ics = ics;
2201
2202 let iectl = state.iectl;
2204 if !iectl.im() {
2205 self.shared.deliver_invalidation_interrupt(state);
2206 } else {
2207 state.iectl = state.iectl.with_ip(true);
2209 }
2210 }
2211 true
2214 }
2215}
2216
2217impl ChipsetDevice for IntelVtdDevice {
2222 fn supports_mmio(&mut self) -> Option<&mut dyn MmioIntercept> {
2223 Some(self)
2224 }
2225}
2226
2227impl MmioIntercept for IntelVtdDevice {
2232 fn mmio_read(&mut self, addr: u64, data: &mut [u8]) -> IoResult {
2233 let offset = addr - self.mmio_base;
2234
2235 match data.len() {
2237 8 => {
2238 let state = self.shared.state.read();
2241 let lo = self.read_register_dword_locked(&state, offset as u16);
2242 let hi = self.read_register_dword_locked(&state, (offset + 4) as u16);
2243 let val = lo as u64 | ((hi as u64) << 32);
2244 data.copy_from_slice(&val.to_le_bytes());
2245 }
2246 4 => {
2247 let val = self.read_register_dword(offset as u16);
2248 data.copy_from_slice(&val.to_le_bytes());
2249 }
2250 _ => {
2251 tracelimit::warn_ratelimited!(
2252 addr,
2253 len = data.len(),
2254 "vtd: unsupported MMIO read size"
2255 );
2256 data.fill(0xff);
2257 return IoResult::Err(IoError::InvalidAccessSize);
2258 }
2259 }
2260
2261 IoResult::Ok
2262 }
2263
2264 fn mmio_write(&mut self, addr: u64, data: &[u8]) -> IoResult {
2265 let offset = addr - self.mmio_base;
2266
2267 match data.len() {
2268 8 => {
2269 let val = u64::from_le_bytes(data.try_into().unwrap());
2270 if offset == u64::from(Reg::IQT.0) {
2271 self.shared.state.write().iqt = IqtReg::from(val);
2273 self.process_invalidation_queue();
2274 } else {
2275 self.write_register_dword(offset as u16, val as u32);
2276 self.write_register_dword((offset + 4) as u16, (val >> 32) as u32);
2277 }
2278 }
2279 4 => {
2280 let val = u32::from_le_bytes(data.try_into().unwrap());
2281 self.write_register_dword(offset as u16, val);
2282 }
2283 _ => {
2284 tracelimit::warn_ratelimited!(
2285 addr,
2286 len = data.len(),
2287 "vtd: unsupported MMIO write size"
2288 );
2289 return IoResult::Err(IoError::InvalidAccessSize);
2290 }
2291 }
2292
2293 IoResult::Ok
2294 }
2295
2296 fn get_static_regions(&mut self) -> &[(&str, RangeInclusive<u64>)] {
2297 std::slice::from_ref(&self.mmio_region)
2298 }
2299}
2300
2301impl vmcore::device_state::ChangeDeviceState for IntelVtdDevice {
2306 fn start(&mut self) {}
2307
2308 async fn stop(&mut self) {}
2309
2310 async fn reset(&mut self) {
2311 let mut state = self.shared.state.write();
2312 *state = VtdState::new();
2313 }
2314}
2315
2316impl vmcore::save_restore::SaveRestore for IntelVtdDevice {
2321 type SavedState = vmcore::save_restore::SavedStateNotSupported;
2322
2323 fn save(&mut self) -> Result<Self::SavedState, vmcore::save_restore::SaveError> {
2324 Err(vmcore::save_restore::SaveError::NotSupported)
2325 }
2326
2327 fn restore(
2328 &mut self,
2329 state: Self::SavedState,
2330 ) -> Result<(), vmcore::save_restore::RestoreError> {
2331 match state {}
2332 }
2333}
2334
2335impl InspectMut for IntelVtdDevice {
2340 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
2341 let state = self.shared.state.read();
2342 let gsts = state.gsts;
2343 req.respond()
2344 .hex("mmio_base", self.mmio_base)
2345 .field("translation_enabled", gsts.tes())
2346 .field("ir_enabled", gsts.ires())
2347 .field("qi_enabled", gsts.qies())
2348 .field("fault_status", self.read_fsts(&state))
2349 .field("translation_table_mode", state.latched_rtaddr.ttm())
2350 .field(
2351 "queue_descriptor_bits",
2352 if state.iqa.dw() { 256u16 } else { 128 },
2353 )
2354 .hex("root_table_addr", state.latched_rtaddr.root_table_address())
2355 .hex("irt_addr", state.latched_irta.irt_base_address())
2356 .field("state", &*state);
2357 }
2358}
2359
2360#[cfg(test)]
2365mod tests {
2366 mod accessed_dirty;
2367 mod queued_invalidation;
2368 mod scalable_fixture;
2369 mod scalable_translation;
2370
2371 use super::*;
2372 use guestmem::GuestMemory;
2373 use std::sync::atomic::AtomicU32;
2374 use std::sync::atomic::Ordering;
2375 use test_with_tracing::test;
2376
2377 const TEST_MMIO_BASE: u64 = 0xFED9_0000;
2378
2379 struct TestSignalMsi;
2380 impl SignalMsi for TestSignalMsi {
2381 fn signal_msi(&self, _devid: Option<u32>, _address: u64, _data: u32) {}
2382 }
2383
2384 fn create_test_device() -> IntelVtdDevice {
2385 let gm = GuestMemory::empty();
2386 let signal_msi = Arc::new(TestSignalMsi);
2387 let (device, _shared) = IntelVtdDevice::new(
2388 gm,
2389 IntelVtdConfig {
2390 mmio_base: TEST_MMIO_BASE,
2391 },
2392 signal_msi,
2393 );
2394 device
2395 }
2396
2397 fn read32(dev: &mut IntelVtdDevice, reg_offset: u16) -> u32 {
2399 let mut data = [0u8; 4];
2400 let result = dev.mmio_read(TEST_MMIO_BASE + reg_offset as u64, &mut data);
2401 assert!(matches!(result, IoResult::Ok));
2402 u32::from_le_bytes(data)
2403 }
2404
2405 fn write32(dev: &mut IntelVtdDevice, reg_offset: u16, value: u32) {
2407 let data = value.to_le_bytes();
2408 let result = dev.mmio_write(TEST_MMIO_BASE + reg_offset as u64, &data);
2409 assert!(matches!(result, IoResult::Ok));
2410 }
2411
2412 fn read64(dev: &mut IntelVtdDevice, reg_offset: u16) -> u64 {
2414 let mut data = [0u8; 8];
2415 let result = dev.mmio_read(TEST_MMIO_BASE + reg_offset as u64, &mut data);
2416 assert!(matches!(result, IoResult::Ok));
2417 u64::from_le_bytes(data)
2418 }
2419
2420 fn write64(dev: &mut IntelVtdDevice, reg_offset: u16, value: u64) {
2422 let data = value.to_le_bytes();
2423 let result = dev.mmio_write(TEST_MMIO_BASE + reg_offset as u64, &data);
2424 assert!(matches!(result, IoResult::Ok));
2425 }
2426
2427 #[test]
2428 fn test_ver_register() {
2429 let mut dev = create_test_device();
2430 let ver = read32(&mut dev, 0x000);
2431 let ver_reg = VersionReg::from(ver);
2432 assert_eq!(ver_reg.max(), 1);
2433 assert_eq!(ver_reg.min(), 0);
2434 }
2435
2436 #[test]
2437 fn test_inspect_reports_latched_mode_not_pending_rtaddr() {
2438 let mut dev = create_test_device();
2439 let mode = |dev: &mut IntelVtdDevice| {
2440 inspect::inspect("translation_table_mode", dev)
2441 .results()
2442 .to_string()
2443 };
2444 assert_eq!(mode(&mut dev), "0");
2445 write64(&mut dev, 0x020, 0x1000 | (1 << 10));
2446 assert_eq!(mode(&mut dev), "0");
2447 write32(&mut dev, 0x018, 1 << 30);
2448 assert_eq!(mode(&mut dev), "1");
2449 write64(&mut dev, 0x020, 0x2000);
2450 assert_eq!(mode(&mut dev), "1");
2451 write32(&mut dev, 0x018, 1 << 30);
2452 assert_eq!(mode(&mut dev), "0");
2453 }
2454
2455 #[test]
2456 fn test_cap_register() {
2457 let mut dev = create_test_device();
2458 let cap = read64(&mut dev, 0x008);
2459 let cap_reg = CapReg::from(cap);
2460 assert_eq!(cap_reg.mgaw(), 47); assert_eq!(cap_reg.sagaw(), 0x6); assert_eq!(cap_reg.nfr(), 0); assert_eq!(cap_reg.fro(), 0x12); assert_eq!(cap_reg.sllps(), 0x3); assert!(cap_reg.dwd());
2466 assert!(cap_reg.drd());
2467 assert!(!cap_reg.cm());
2468 assert_eq!(cap_reg.nd(), 6);
2469 }
2470
2471 #[test]
2472 fn test_ecap_register() {
2473 let mut dev = create_test_device();
2474 let ecap = read64(&mut dev, 0x010);
2475 let ecap_reg = EcapReg::from(ecap);
2476 assert!(ecap_reg.c());
2477 assert!(ecap_reg.qi());
2478 assert!(ecap_reg.ir());
2479 assert!(ecap_reg.eim());
2480 assert_eq!(ecap_reg.iro(), 0x10); assert_eq!(ecap_reg.mhmv(), 0xF);
2482 assert!(ecap_reg.smts());
2483 assert!(ecap_reg.ssts());
2484 assert!(ecap_reg.ssads());
2485 assert!(ecap_reg.smpwcs());
2486 assert!(ecap_reg.rps());
2487 assert!(!ecap_reg.flts());
2488 assert!(!ecap_reg.eafs());
2489 assert!(!ecap_reg.nest());
2490 assert!(!ecap_reg.pasid());
2491 assert!(!ecap_reg.dt());
2492 assert!(!ecap_reg.prs());
2493 assert!(!ecap_reg.srs());
2494 assert_eq!(ecap, 0x0003_6800_00f0_10db);
2495 }
2496
2497 #[test]
2498 fn test_gcmd_read_returns_zero() {
2499 let mut dev = create_test_device();
2500 assert_eq!(read32(&mut dev, 0x018), 0);
2501 }
2502
2503 #[test]
2504 fn test_gsts_initial() {
2505 let mut dev = create_test_device();
2506 let gsts = read32(&mut dev, 0x01C);
2507 assert_eq!(gsts, 0); }
2509
2510 #[test]
2511 fn test_srtp_and_te_enable() {
2512 let mut dev = create_test_device();
2513
2514 let root_table_addr = 0x1000_0000u64;
2516 write64(&mut dev, 0x020, root_table_addr);
2517 assert_eq!(read64(&mut dev, 0x020), root_table_addr);
2518
2519 write32(&mut dev, 0x018, GcmdReg::new().with_srtp(true).into_bits());
2521 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2522 assert!(gsts.rtps());
2523
2524 write32(&mut dev, 0x018, GcmdReg::new().with_te(true).into_bits());
2526 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2527 assert!(gsts.tes());
2528 }
2529
2530 #[test]
2531 fn test_te_rejected_without_rtps() {
2532 let mut dev = create_test_device();
2533
2534 write32(&mut dev, 0x018, GcmdReg::new().with_te(true).into_bits());
2536 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2537 assert!(!gsts.tes()); }
2539
2540 #[test]
2541 fn test_ire_rejected_without_irtps() {
2542 let mut dev = create_test_device();
2543
2544 write32(&mut dev, 0x018, GcmdReg::new().with_ire(true).into_bits());
2546 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2547 assert!(!gsts.ires()); }
2549
2550 #[test]
2551 fn test_sirtp_and_ire_enable() {
2552 let mut dev = create_test_device();
2553
2554 let irt_addr = 0x2000_0000u64;
2556 write64(&mut dev, 0x0B8, irt_addr);
2557 assert_eq!(read64(&mut dev, 0x0B8), irt_addr);
2558
2559 write32(&mut dev, 0x018, GcmdReg::new().with_sirtp(true).into_bits());
2561 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2562 assert!(gsts.irtps());
2563
2564 write32(&mut dev, 0x018, GcmdReg::new().with_ire(true).into_bits());
2566 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2567 assert!(gsts.ires());
2568 }
2569
2570 #[test]
2571 fn test_wbf() {
2572 let mut dev = create_test_device();
2573
2574 write32(&mut dev, 0x018, GcmdReg::new().with_wbf(true).into_bits());
2576 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2577 assert!(gsts.wbfs());
2578 }
2579
2580 #[test]
2581 fn test_qie_enable_disable() {
2582 let mut dev = create_test_device();
2583
2584 write64(&mut dev, 0x090, 0x3000_0000u64);
2586
2587 write32(&mut dev, 0x018, GcmdReg::new().with_qie(true).into_bits());
2589 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2590 assert!(gsts.qies());
2591
2592 write32(&mut dev, 0x018, GcmdReg::new().with_qie(false).into_bits());
2594 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2595 assert!(!gsts.qies());
2596 }
2597
2598 #[test]
2599 fn test_ccmd_register_invalidation() {
2600 let mut dev = create_test_device();
2601
2602 let ccmd = CcmdReg::new().with_icc(true).with_cirg(1);
2604 write64(&mut dev, 0x028, ccmd.into_bits());
2605
2606 let result = CcmdReg::from(read64(&mut dev, 0x028));
2608 assert!(!result.icc());
2609 assert_eq!(result.caig(), 1);
2610 }
2611
2612 #[test]
2613 fn test_fsts_rw1c() {
2614 let mut dev = create_test_device();
2615
2616 {
2618 let mut state = dev.shared.state.write();
2619 state.fsts = FstsReg::new().with_pfo(true).with_iqe(true);
2620 }
2621
2622 let fsts = FstsReg::from(read32(&mut dev, 0x034));
2623 assert!(fsts.pfo());
2624 assert!(fsts.iqe());
2625
2626 write32(&mut dev, 0x034, FstsReg::new().with_pfo(true).into_bits());
2628 let fsts = FstsReg::from(read32(&mut dev, 0x034));
2629 assert!(!fsts.pfo());
2630 assert!(fsts.iqe()); }
2632
2633 #[test]
2634 fn test_ppf_dynamic_computation() {
2635 let mut dev = create_test_device();
2636
2637 let fsts = FstsReg::from(read32(&mut dev, 0x034));
2639 assert!(!fsts.ppf());
2640
2641 {
2643 let mut state = dev.shared.state.write();
2644 state.frcd_hi = FrcdHi::new().with_f(true);
2645 }
2646
2647 let fsts = FstsReg::from(read32(&mut dev, 0x034));
2649 assert!(fsts.ppf());
2650
2651 write64(&mut dev, Reg::FRCD_DW2.0, 1u64 << 63);
2653
2654 let fsts = FstsReg::from(read32(&mut dev, 0x034));
2656 assert!(!fsts.ppf());
2657 }
2658
2659 #[test]
2660 fn test_ics_rw1c() {
2661 let mut dev = create_test_device();
2662
2663 {
2665 let mut state = dev.shared.state.write();
2666 state.ics = IcsReg::new().with_iwc(true);
2667 }
2668
2669 let ics = IcsReg::from(read32(&mut dev, 0x09C));
2670 assert!(ics.iwc());
2671
2672 write32(&mut dev, 0x09C, IcsReg::new().with_iwc(true).into_bits());
2674 let ics = IcsReg::from(read32(&mut dev, 0x09C));
2675 assert!(!ics.iwc());
2676 }
2677
2678 #[test]
2679 fn test_iqa_write_guard() {
2680 let mut dev = create_test_device();
2681
2682 write64(&mut dev, 0x090, 0x5000_0000u64);
2684 assert_eq!(read64(&mut dev, 0x090), 0x5000_0000u64);
2685
2686 write32(&mut dev, 0x018, GcmdReg::new().with_qie(true).into_bits());
2688
2689 write64(&mut dev, 0x090, 0x6000_0000u64);
2691 assert_eq!(read64(&mut dev, 0x090), 0x5000_0000u64);
2692 }
2693
2694 #[test]
2695 fn test_irta_write_guard() {
2696 let mut dev = create_test_device();
2697
2698 write64(&mut dev, 0x0B8, 0x7000_0000u64);
2700 assert_eq!(read64(&mut dev, 0x0B8), 0x7000_0000u64);
2701
2702 write32(&mut dev, 0x018, GcmdReg::new().with_sirtp(true).into_bits());
2704 write32(&mut dev, 0x018, GcmdReg::new().with_ire(true).into_bits());
2705
2706 write64(&mut dev, 0x0B8, 0x8000_0000u64);
2708 assert_eq!(read64(&mut dev, 0x0B8), 0x7000_0000u64);
2709 }
2710
2711 #[test]
2712 fn test_unmapped_offset_returns_zero() {
2713 let mut dev = create_test_device();
2714 assert_eq!(read32(&mut dev, 0x050), 0);
2716 assert_eq!(read64(&mut dev, 0x060), 0);
2717 }
2718
2719 #[test]
2720 fn test_unsupported_access_size() {
2721 let mut dev = create_test_device();
2722 let mut data = [0u8; 2];
2723 let result = dev.mmio_read(TEST_MMIO_BASE, &mut data);
2724 assert!(matches!(result, IoResult::Err(IoError::InvalidAccessSize)));
2725 }
2726
2727 #[test]
2728 fn test_32bit_access_to_64bit_register() {
2729 let mut dev = create_test_device();
2730
2731 let cap_lo = read32(&mut dev, 0x008);
2733 let cap_hi = read32(&mut dev, 0x00C);
2734 let cap_full = read64(&mut dev, 0x008);
2735
2736 assert_eq!(cap_full as u32, cap_lo);
2737 assert_eq!((cap_full >> 32) as u32, cap_hi);
2738 }
2739
2740 #[test]
2741 fn test_iotlb_register_invalidation() {
2742 let mut dev = create_test_device();
2743
2744 let iotlb_val = IotlbReg::new().with_ivt(true).with_iirg(1).into_bits();
2746 write64(&mut dev, Reg::IOTLB.0, iotlb_val);
2747
2748 let result = IotlbReg::from(read64(&mut dev, Reg::IOTLB.0));
2750 assert!(!result.ivt()); assert_eq!(result.iaig(), 1); }
2753
2754 #[test]
2755 fn test_cfi_toggle() {
2756 let mut dev = create_test_device();
2757
2758 write32(&mut dev, 0x018, GcmdReg::new().with_cfi(true).into_bits());
2760 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2761 assert!(gsts.cfis());
2762
2763 write32(&mut dev, 0x018, GcmdReg::new().with_cfi(false).into_bits());
2765 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
2766 assert!(!gsts.cfis());
2767 }
2768
2769 #[test]
2770 fn test_frcd_hi_rw1c() {
2771 let mut dev = create_test_device();
2772
2773 {
2775 let mut state = dev.shared.state.write();
2776 state.frcd_hi = FrcdHi::new().with_f(true);
2777 }
2778
2779 let frcd_hi = read64(&mut dev, Reg::FRCD_DW2.0);
2781 assert_eq!((frcd_hi >> 63) & 1, 1);
2782
2783 write64(&mut dev, Reg::FRCD_DW2.0, 1u64 << 63);
2785 let frcd_hi = read64(&mut dev, Reg::FRCD_DW2.0);
2786 assert_eq!((frcd_hi >> 63) & 1, 0);
2787 }
2788
2789 use spec::pte::SlPte;
2794 use spec::root_context::AddressWidth;
2795 use spec::root_context::ContextEntry;
2796 use spec::root_context::ContextEntryHi;
2797 use spec::root_context::ContextEntryLo;
2798 use spec::root_context::RootEntry;
2799 use spec::root_context::RootEntryLo;
2800 use zerocopy::IntoBytes;
2801
2802 const ROOT_TABLE_ADDR: u64 = 0x10_0000; const CONTEXT_TABLE_ADDR: u64 = 0x11_0000;
2804 const PAGE_TABLE_L4_ADDR: u64 = 0x12_0000;
2805 const PAGE_TABLE_L3_ADDR: u64 = 0x13_0000;
2806 const PAGE_TABLE_L2_ADDR: u64 = 0x14_0000;
2807 const PAGE_TABLE_L1_ADDR: u64 = 0x15_0000;
2808 const TARGET_GPA: u64 = 0x20_0000; fn create_test_device_with_translation() -> (IntelVtdDevice, Arc<VtdSharedState>) {
2813 let gm = GuestMemory::allocate(0x40_0000);
2815 let signal_msi = Arc::new(TestSignalMsi);
2816
2817 let root_entry = RootEntry {
2819 lo: RootEntryLo::new()
2820 .with_p(true)
2821 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
2822 hi: 0,
2823 };
2824 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
2825
2826 let context_entry = ContextEntry {
2828 lo: ContextEntryLo::new()
2829 .with_p(true)
2830 .with_tt(TranslationType::UNTRANSLATED_ONLY.0)
2831 .with_ssptptr(PAGE_TABLE_L4_ADDR >> 12),
2832 hi: ContextEntryHi::new()
2833 .with_aw(AddressWidth::AW_48BIT.0)
2834 .with_did(1), };
2836 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
2837 .unwrap();
2838
2839 let pte_l4 = SlPte::new()
2842 .with_r(true)
2843 .with_w(true)
2844 .with_address(PAGE_TABLE_L3_ADDR >> 12);
2845 gm.write_at(PAGE_TABLE_L4_ADDR, pte_l4.into_bits().as_bytes())
2846 .unwrap();
2847
2848 let pte_l3 = SlPte::new()
2850 .with_r(true)
2851 .with_w(true)
2852 .with_address(PAGE_TABLE_L2_ADDR >> 12);
2853 gm.write_at(PAGE_TABLE_L3_ADDR, pte_l3.into_bits().as_bytes())
2854 .unwrap();
2855
2856 let pte_l2 = SlPte::new()
2858 .with_r(true)
2859 .with_w(true)
2860 .with_address(PAGE_TABLE_L1_ADDR >> 12);
2861 gm.write_at(PAGE_TABLE_L2_ADDR, pte_l2.into_bits().as_bytes())
2862 .unwrap();
2863
2864 let pte_l1 = SlPte::new()
2866 .with_r(true)
2867 .with_w(true)
2868 .with_address(TARGET_GPA >> 12);
2869 gm.write_at(PAGE_TABLE_L1_ADDR, pte_l1.into_bits().as_bytes())
2870 .unwrap();
2871
2872 let (dev, shared) = IntelVtdDevice::new(
2873 gm,
2874 IntelVtdConfig {
2875 mmio_base: TEST_MMIO_BASE,
2876 },
2877 signal_msi,
2878 );
2879
2880 {
2882 let mut state = shared.state.write();
2883 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
2884 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
2885 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
2886 }
2887
2888 (dev, shared)
2889 }
2890
2891 #[test]
2892 fn test_translate_4level_4kb() {
2893 let (_dev, shared) = create_test_device_with_translation();
2894 let state = shared.state.read();
2895 let gpa = shared
2896 .translate_locked(&state, 0, 0, 0x0000, false, EcapReg::from(ECAP_VALUE))
2897 .unwrap();
2898 assert_eq!(gpa, TARGET_GPA);
2899 }
2900
2901 #[test]
2902 fn test_translate_4level_4kb_with_offset() {
2903 let (_dev, shared) = create_test_device_with_translation();
2904 let state = shared.state.read();
2905 let gpa = shared
2907 .translate_locked(&state, 0, 0, 0x0123, false, EcapReg::from(ECAP_VALUE))
2908 .unwrap();
2909 assert_eq!(gpa, TARGET_GPA + 0x123);
2910 }
2911
2912 #[test]
2913 fn test_translate_disabled_is_identity() {
2914 let (_dev, shared) = create_test_device_with_translation();
2915 {
2917 let mut state = shared.state.write();
2918 state.gsts = GstsReg::new().with_rtps(true);
2919 }
2920 let state = shared.state.read();
2921 let gpa = shared
2922 .translate_locked(&state, 0, 0, 0xDEAD_BEEF, false, EcapReg::from(ECAP_VALUE))
2923 .unwrap();
2924 assert_eq!(gpa, 0xDEAD_BEEF);
2925 }
2926
2927 #[test]
2928 fn test_translate_3level() {
2929 let gm = GuestMemory::allocate(0x40_0000);
2930 let signal_msi = Arc::new(TestSignalMsi);
2931
2932 let root_entry = RootEntry {
2934 lo: RootEntryLo::new()
2935 .with_p(true)
2936 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
2937 hi: 0,
2938 };
2939 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
2940
2941 let context_entry = ContextEntry {
2942 lo: ContextEntryLo::new()
2943 .with_p(true)
2944 .with_tt(TranslationType::UNTRANSLATED_ONLY.0)
2945 .with_ssptptr(PAGE_TABLE_L3_ADDR >> 12),
2946 hi: ContextEntryHi::new()
2947 .with_aw(AddressWidth::AW_39BIT.0)
2948 .with_did(1), };
2950 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
2951 .unwrap();
2952
2953 let pte_l3 = SlPte::new()
2955 .with_r(true)
2956 .with_w(true)
2957 .with_address(PAGE_TABLE_L2_ADDR >> 12);
2958 gm.write_at(PAGE_TABLE_L3_ADDR, pte_l3.into_bits().as_bytes())
2959 .unwrap();
2960
2961 let pte_l2 = SlPte::new()
2962 .with_r(true)
2963 .with_w(true)
2964 .with_address(PAGE_TABLE_L1_ADDR >> 12);
2965 gm.write_at(PAGE_TABLE_L2_ADDR, pte_l2.into_bits().as_bytes())
2966 .unwrap();
2967
2968 let pte_l1 = SlPte::new()
2969 .with_r(true)
2970 .with_w(true)
2971 .with_address(TARGET_GPA >> 12);
2972 gm.write_at(PAGE_TABLE_L1_ADDR, pte_l1.into_bits().as_bytes())
2973 .unwrap();
2974
2975 let (_dev, shared) = IntelVtdDevice::new(
2976 gm,
2977 IntelVtdConfig {
2978 mmio_base: TEST_MMIO_BASE,
2979 },
2980 signal_msi,
2981 );
2982 {
2983 let mut state = shared.state.write();
2984 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
2985 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
2986 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
2987 }
2988
2989 let state = shared.state.read();
2990 let gpa = shared
2991 .translate_locked(&state, 0, 0, 0x0000, false, EcapReg::from(ECAP_VALUE))
2992 .unwrap();
2993 assert_eq!(gpa, TARGET_GPA);
2994 }
2995
2996 #[test]
2997 fn test_translate_2mb_large_page() {
2998 let gm = GuestMemory::allocate(0x40_0000);
2999 let signal_msi = Arc::new(TestSignalMsi);
3000
3001 let root_entry = RootEntry {
3002 lo: RootEntryLo::new()
3003 .with_p(true)
3004 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
3005 hi: 0,
3006 };
3007 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
3008
3009 let context_entry = ContextEntry {
3010 lo: ContextEntryLo::new()
3011 .with_p(true)
3012 .with_tt(TranslationType::UNTRANSLATED_ONLY.0)
3013 .with_ssptptr(PAGE_TABLE_L4_ADDR >> 12),
3014 hi: ContextEntryHi::new()
3015 .with_aw(AddressWidth::AW_48BIT.0)
3016 .with_did(1),
3017 };
3018 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
3019 .unwrap();
3020
3021 let pte_l4 = SlPte::new()
3023 .with_r(true)
3024 .with_w(true)
3025 .with_address(PAGE_TABLE_L3_ADDR >> 12);
3026 gm.write_at(PAGE_TABLE_L4_ADDR, pte_l4.into_bits().as_bytes())
3027 .unwrap();
3028
3029 let pte_l3 = SlPte::new()
3030 .with_r(true)
3031 .with_w(true)
3032 .with_address(PAGE_TABLE_L2_ADDR >> 12);
3033 gm.write_at(PAGE_TABLE_L3_ADDR, pte_l3.into_bits().as_bytes())
3034 .unwrap();
3035
3036 let pte_l2 = SlPte::new()
3038 .with_r(true)
3039 .with_w(true)
3040 .with_ps(true)
3041 .with_address(0x20_0000 >> 12); gm.write_at(PAGE_TABLE_L2_ADDR, pte_l2.into_bits().as_bytes())
3043 .unwrap();
3044
3045 let (_dev, shared) = IntelVtdDevice::new(
3046 gm,
3047 IntelVtdConfig {
3048 mmio_base: TEST_MMIO_BASE,
3049 },
3050 signal_msi,
3051 );
3052 {
3053 let mut state = shared.state.write();
3054 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3055 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3056 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
3057 }
3058
3059 let state = shared.state.read();
3060 let gpa = shared
3062 .translate_locked(&state, 0, 0, 0x1234, false, EcapReg::from(ECAP_VALUE))
3063 .unwrap();
3064 assert_eq!(gpa, 0x20_1234);
3065 }
3066
3067 #[test]
3068 fn test_translate_passthrough() {
3069 let gm = GuestMemory::allocate(0x40_0000);
3070 let signal_msi = Arc::new(TestSignalMsi);
3071
3072 let root_entry = RootEntry {
3073 lo: RootEntryLo::new()
3074 .with_p(true)
3075 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
3076 hi: 0,
3077 };
3078 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
3079
3080 let context_entry = ContextEntry {
3082 lo: ContextEntryLo::new()
3083 .with_p(true)
3084 .with_tt(TranslationType::PASS_THROUGH.0)
3085 .with_ssptptr(0),
3086 hi: ContextEntryHi::new()
3087 .with_aw(AddressWidth::AW_48BIT.0)
3088 .with_did(1),
3089 };
3090 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
3091 .unwrap();
3092
3093 let (_dev, shared) = IntelVtdDevice::new(
3094 gm,
3095 IntelVtdConfig {
3096 mmio_base: TEST_MMIO_BASE,
3097 },
3098 signal_msi,
3099 );
3100 {
3101 let mut state = shared.state.write();
3102 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3103 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3104 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
3105 }
3106
3107 let state = shared.state.read();
3108 let gpa = shared
3109 .translate_locked(&state, 0, 0, 0xABCD_0000, false, EcapReg::from(ECAP_VALUE))
3110 .unwrap();
3111 assert_eq!(gpa, 0xABCD_0000);
3112 }
3113
3114 #[test]
3115 fn test_translate_root_not_present() {
3116 let gm = GuestMemory::allocate(0x40_0000);
3117 let signal_msi = Arc::new(TestSignalMsi);
3118
3119 let root_entry = RootEntry {
3121 lo: RootEntryLo::new().with_p(false),
3122 hi: 0,
3123 };
3124 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
3125
3126 let (_dev, shared) = IntelVtdDevice::new(
3127 gm,
3128 IntelVtdConfig {
3129 mmio_base: TEST_MMIO_BASE,
3130 },
3131 signal_msi,
3132 );
3133 {
3134 let mut state = shared.state.write();
3135 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3136 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3137 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
3138 }
3139
3140 let state = shared.state.read();
3141 let err = shared
3142 .translate_locked(&state, 0, 0, 0x1000, false, EcapReg::from(ECAP_VALUE))
3143 .unwrap_err();
3144 assert!(matches!(err, VtdFault::RootNotPresent { .. }));
3145 }
3146
3147 #[test]
3148 fn test_translate_context_not_present() {
3149 let gm = GuestMemory::allocate(0x40_0000);
3150 let signal_msi = Arc::new(TestSignalMsi);
3151
3152 let root_entry = RootEntry {
3153 lo: RootEntryLo::new()
3154 .with_p(true)
3155 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
3156 hi: 0,
3157 };
3158 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
3159
3160 let context_entry = ContextEntry {
3162 lo: ContextEntryLo::new().with_p(false),
3163 hi: ContextEntryHi::new(),
3164 };
3165 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
3166 .unwrap();
3167
3168 let (_dev, shared) = IntelVtdDevice::new(
3169 gm,
3170 IntelVtdConfig {
3171 mmio_base: TEST_MMIO_BASE,
3172 },
3173 signal_msi,
3174 );
3175 {
3176 let mut state = shared.state.write();
3177 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3178 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3179 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
3180 }
3181
3182 let state = shared.state.read();
3183 let err = shared
3184 .translate_locked(&state, 0, 0, 0x1000, false, EcapReg::from(ECAP_VALUE))
3185 .unwrap_err();
3186 assert!(matches!(err, VtdFault::ContextNotPresent { .. }));
3187 }
3188
3189 #[test]
3190 fn test_translate_pte_not_present() {
3191 let (_dev, shared) = create_test_device_with_translation();
3192
3193 let pte = SlPte::new(); shared
3196 .guest_memory
3197 .write_at(PAGE_TABLE_L1_ADDR + 8, pte.into_bits().as_bytes())
3198 .unwrap();
3199
3200 let state = shared.state.read();
3201 let err = shared
3202 .translate_locked(&state, 0, 0, 0x1000, false, EcapReg::from(ECAP_VALUE))
3203 .unwrap_err();
3204 assert!(matches!(err, VtdFault::AccessDenied { write: false, .. }));
3206 }
3207
3208 #[test]
3209 fn test_translate_write_to_readonly() {
3210 let (_dev, shared) = create_test_device_with_translation();
3211
3212 let pte = SlPte::new().with_r(true).with_w(false);
3214 shared
3215 .guest_memory
3216 .write_at(PAGE_TABLE_L1_ADDR, pte.into_bits().as_bytes())
3217 .unwrap();
3218
3219 let state = shared.state.read();
3220 let gpa = shared
3222 .translate_locked(&state, 0, 0, 0x0000, false, EcapReg::from(ECAP_VALUE))
3223 .unwrap();
3224 assert_eq!(gpa, 0); let err = shared
3227 .translate_locked(&state, 0, 0, 0x0000, true, EcapReg::from(ECAP_VALUE))
3228 .unwrap_err();
3229 assert!(matches!(err, VtdFault::AccessDenied { write: true, .. }));
3230 }
3231
3232 #[test]
3233 fn test_translate_pde_permission_restricts() {
3234 let (_dev, shared) = create_test_device_with_translation();
3235
3236 let pte_l2 = SlPte::new()
3239 .with_r(true)
3240 .with_w(false) .with_address(PAGE_TABLE_L1_ADDR >> 12);
3242 shared
3243 .guest_memory
3244 .write_at(PAGE_TABLE_L2_ADDR, pte_l2.into_bits().as_bytes())
3245 .unwrap();
3246
3247 let state = shared.state.read();
3248 let err = shared
3249 .translate_locked(&state, 0, 0, 0x0000, true, EcapReg::from(ECAP_VALUE))
3250 .unwrap_err();
3251 assert!(matches!(err, VtdFault::AccessDenied { write: true, .. }));
3252 }
3253
3254 #[test]
3255 fn test_translate_fpd_suppresses_fault() {
3256 let gm = GuestMemory::allocate(0x40_0000);
3257 let signal_msi = Arc::new(TestSignalMsi);
3258
3259 let root_entry = RootEntry {
3260 lo: RootEntryLo::new()
3261 .with_p(true)
3262 .with_ctp(CONTEXT_TABLE_ADDR >> 12),
3263 hi: 0,
3264 };
3265 gm.write_at(ROOT_TABLE_ADDR, root_entry.as_bytes()).unwrap();
3266
3267 let context_entry = ContextEntry {
3269 lo: ContextEntryLo::new()
3270 .with_p(true)
3271 .with_fpd(true)
3272 .with_tt(TranslationType::UNTRANSLATED_ONLY.0)
3273 .with_ssptptr(0x30_0000 >> 12), hi: ContextEntryHi::new()
3275 .with_aw(AddressWidth::AW_48BIT.0)
3276 .with_did(1),
3277 };
3278 gm.write_at(CONTEXT_TABLE_ADDR, context_entry.as_bytes())
3279 .unwrap();
3280
3281 let (_dev, shared) = IntelVtdDevice::new(
3282 gm,
3283 IntelVtdConfig {
3284 mmio_base: TEST_MMIO_BASE,
3285 },
3286 signal_msi,
3287 );
3288 {
3289 let mut state = shared.state.write();
3290 state.rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3291 state.latched_rtaddr = RtaddrReg::from(ROOT_TABLE_ADDR);
3292 state.gsts = GstsReg::new().with_rtps(true).with_tes(true);
3293 }
3294
3295 let state = shared.state.read();
3297 let err = shared
3298 .translate_locked(&state, 0, 0, 0x0000, false, EcapReg::from(ECAP_VALUE))
3299 .unwrap_err();
3300 assert!(err.fpd()); drop(state);
3304 err.record(&shared, false); let state = shared.state.read();
3308 assert!(!state.frcd_hi.f());
3309 }
3310
3311 use spec::irte::Irte;
3316 use spec::irte::IrteHi;
3317 use spec::irte::IrteLo;
3318
3319 const IRT_BASE_ADDR: u64 = 0x18_0000;
3320
3321 #[test]
3322 fn test_extract_irte_index_no_shv() {
3323 let index = VtdSharedState::extract_irte_index(0xFEE0_0010, 0);
3326 assert_eq!(index, 0);
3327
3328 let addr = 0xFEE0_0010 | (0x7 << 5);
3331 let index = VtdSharedState::extract_irte_index(addr, 0);
3332 assert_eq!(index, 7);
3333 }
3334
3335 #[test]
3336 fn test_extract_irte_index_with_shv() {
3337 let addr = 0xFEE0_0018 | (0x5 << 5); let index = VtdSharedState::extract_irte_index(addr, 3);
3341 assert_eq!(index, 8); }
3343
3344 fn setup_ir_state(shared: &Arc<VtdSharedState>, eime: bool) {
3345 let mut state = shared.state.write();
3346 state.irta = IrtaReg::new()
3348 .with_irta(IRT_BASE_ADDR >> 12)
3349 .with_s(0xF)
3350 .with_eime(eime);
3351 state.latched_irta = state.irta;
3352 let mut gsts = state.gsts;
3354 gsts.set_ires(true);
3355 gsts.set_irtps(true);
3356 state.gsts = gsts;
3357 }
3358
3359 struct CountingRoute {
3360 device_id: u16,
3361 retranslate_count: AtomicU32,
3362 }
3363
3364 impl iommu_common::RetranslateInterrupts for CountingRoute {
3365 fn device_id(&self) -> u16 {
3366 self.device_id
3367 }
3368
3369 fn retranslate(&self) {
3370 self.retranslate_count.fetch_add(1, Ordering::SeqCst);
3371 }
3372 }
3373
3374 #[test]
3375 fn test_remap_msi_basic() {
3376 let gm = GuestMemory::allocate(0x40_0000);
3377 let signal_msi = Arc::new(TestSignalMsi);
3378 let (_dev, shared) = IntelVtdDevice::new(
3379 gm.clone(),
3380 IntelVtdConfig {
3381 mmio_base: TEST_MMIO_BASE,
3382 },
3383 signal_msi,
3384 );
3385
3386 setup_ir_state(&shared, false);
3387
3388 let irte = Irte {
3390 lo: IrteLo::new()
3391 .with_p(true)
3392 .with_vector(0x42)
3393 .with_dst(0x0300) .with_dlm(0) .with_dm(false), hi: IrteHi::new().with_svt(0), };
3398 gm.write_at(IRT_BASE_ADDR, irte.as_bytes()).unwrap();
3399
3400 let addr = 0xFEE0_0010u64;
3402 let data = 0u32;
3403 let state = shared.state.read();
3404 let (new_addr, new_data) = shared.remap_msi_locked(&state, 0x0000, addr, data).unwrap();
3405
3406 assert_eq!(new_addr & 0xFFF0_0000, 0xFEE0_0000);
3408 assert_eq!((new_addr >> 12) & 0xFF, 3); assert_eq!(new_data & 0xFF, 0x42); }
3411
3412 #[test]
3413 fn test_remap_msi_x2apic_destination() {
3414 let gm = GuestMemory::allocate(0x40_0000);
3415 let signal_msi = Arc::new(TestSignalMsi);
3416 let (_dev, shared) = IntelVtdDevice::new(
3417 gm.clone(),
3418 IntelVtdConfig {
3419 mmio_base: TEST_MMIO_BASE,
3420 },
3421 signal_msi,
3422 );
3423
3424 setup_ir_state(&shared, true);
3426
3427 let apic_id: u32 = 300;
3429 let irte = Irte {
3430 lo: IrteLo::new()
3431 .with_p(true)
3432 .with_vector(0x50)
3433 .with_dst(apic_id)
3434 .with_dlm(0)
3435 .with_dm(false),
3436 hi: IrteHi::new().with_svt(0),
3437 };
3438 gm.write_at(IRT_BASE_ADDR, irte.as_bytes()).unwrap();
3439
3440 let addr = 0xFEE0_0010u64;
3441 let state = shared.state.read();
3442 let (new_addr, new_data) = shared.remap_msi_locked(&state, 0x0000, addr, 0).unwrap();
3443
3444 let msi_addr = x86defs::msi::MsiAddress::from(new_addr as u32);
3446 assert_eq!(msi_addr.virt_destination(), apic_id as u16);
3447 assert_eq!(new_data & 0xFF, 0x50);
3448 }
3449
3450 #[test]
3451 fn test_remap_msi_ir_disabled_passthrough() {
3452 let gm = GuestMemory::allocate(0x40_0000);
3453 let signal_msi = Arc::new(TestSignalMsi);
3454 let (_dev, shared) = IntelVtdDevice::new(
3455 gm,
3456 IntelVtdConfig {
3457 mmio_base: TEST_MMIO_BASE,
3458 },
3459 signal_msi,
3460 );
3461 let state = shared.state.read();
3463 let (a, d) = shared
3464 .remap_msi_locked(&state, 0, 0xFEE0_1234, 0x42)
3465 .unwrap();
3466 assert_eq!(a, 0xFEE0_1234);
3467 assert_eq!(d, 0x42);
3468 }
3469
3470 #[test]
3471 fn test_interrupt_remapper_transitions_from_passthrough_to_remap() {
3472 let gm = GuestMemory::allocate(0x40_0000);
3473 let signal_msi = Arc::new(TestSignalMsi);
3474 let (_dev, shared) = IntelVtdDevice::new(
3475 gm.clone(),
3476 IntelVtdConfig {
3477 mmio_base: TEST_MMIO_BASE,
3478 },
3479 signal_msi,
3480 );
3481
3482 let compat_addr = 0xFEE0_0000u64;
3483 assert_eq!(
3484 iommu_common::InterruptRemapper::remap_msi(&*shared, 0x00A0, compat_addr, 0x31),
3485 Some((compat_addr, 0x31))
3486 );
3487
3488 setup_ir_state(&shared, false);
3489 let irte = Irte {
3490 lo: IrteLo::new()
3491 .with_p(true)
3492 .with_vector(0x45)
3493 .with_dst(0x0200)
3494 .with_dlm(0)
3495 .with_dm(false),
3496 hi: IrteHi::new().with_svt(0b01).with_sq(0).with_sid(0x00A0),
3497 };
3498 gm.write_at(IRT_BASE_ADDR, irte.as_bytes()).unwrap();
3499
3500 let (new_addr, new_data) =
3501 iommu_common::InterruptRemapper::remap_msi(&*shared, 0x00A0, 0xFEE0_0010, 0).unwrap();
3502 assert_eq!((new_addr >> 12) & 0xFF, 2);
3503 assert_eq!(new_data & 0xFF, 0x45);
3504 }
3505
3506 #[test]
3507 fn test_remap_msi_irte_not_present() {
3508 let gm = GuestMemory::allocate(0x40_0000);
3509 let signal_msi = Arc::new(TestSignalMsi);
3510 let (_dev, shared) = IntelVtdDevice::new(
3511 gm.clone(),
3512 IntelVtdConfig {
3513 mmio_base: TEST_MMIO_BASE,
3514 },
3515 signal_msi,
3516 );
3517
3518 setup_ir_state(&shared, false);
3519
3520 let addr = 0xFEE0_0010u64;
3522 let state = shared.state.read();
3523 let err = shared
3524 .remap_msi_locked(&state, 0x0000, addr, 0)
3525 .unwrap_err();
3526 assert!(matches!(err, VtdFault::IrteNotPresent { .. }));
3527 }
3528
3529 #[test]
3530 fn test_remap_msi_posted_irte_rejected() {
3531 let gm = GuestMemory::allocate(0x40_0000);
3532 let signal_msi = Arc::new(TestSignalMsi);
3533 let (_dev, shared) = IntelVtdDevice::new(
3534 gm.clone(),
3535 IntelVtdConfig {
3536 mmio_base: TEST_MMIO_BASE,
3537 },
3538 signal_msi,
3539 );
3540
3541 setup_ir_state(&shared, false);
3542
3543 let irte = Irte {
3544 lo: IrteLo::new().with_p(true).with_im(true).with_vector(0x40),
3545 hi: IrteHi::new().with_svt(0),
3546 };
3547 gm.write_at(IRT_BASE_ADDR, irte.as_bytes()).unwrap();
3548
3549 let state = shared.state.read();
3550 let err = shared
3551 .remap_msi_locked(&state, 0x0000, 0xFEE0_0010, 0)
3552 .unwrap_err();
3553 assert!(matches!(err, VtdFault::IrteReservedField { .. }));
3554 }
3555
3556 #[test]
3557 fn test_interrupt_entry_cache_invalidate_retranslates_routes() {
3558 const IQ_BASE: u64 = 0x20_0000;
3559
3560 let gm = GuestMemory::allocate(0x40_0000);
3561 let signal_msi = Arc::new(TestSignalMsi);
3562 let (mut dev, shared) = IntelVtdDevice::new(
3563 gm.clone(),
3564 IntelVtdConfig {
3565 mmio_base: TEST_MMIO_BASE,
3566 },
3567 signal_msi,
3568 );
3569
3570 let route = Arc::new(CountingRoute {
3571 device_id: 0x00A0,
3572 retranslate_count: AtomicU32::new(0),
3573 });
3574 let route_dyn: Arc<dyn iommu_common::RetranslateInterrupts> = route.clone();
3575 iommu_common::InterruptRemapper::register_route(&*shared, &route_dyn);
3576
3577 let iqa = IqaReg::new().with_qs(0).with_iqa(IQ_BASE >> 12);
3578 write64(&mut dev, Reg::IQA.0, iqa.into_bits());
3579 write32(
3580 &mut dev,
3581 Reg::GCMD.0,
3582 GcmdReg::new().with_qie(true).into_bits(),
3583 );
3584
3585 let desc = spec::invalidation::InvalidationDescriptor {
3586 dw0: DescriptorType::INTERRUPT_ENTRY_CACHE_INVALIDATE.0 as u32,
3587 dw1: 0,
3588 dw2: 0,
3589 dw3: 0,
3590 };
3591 gm.write_at(IQ_BASE, desc.as_bytes()).unwrap();
3592
3593 write64(&mut dev, Reg::IQT.0, IqtReg::new().with_qt(1).into_bits());
3594
3595 assert_eq!(route.retranslate_count.load(Ordering::SeqCst), 1);
3596 assert_eq!(IqhReg::from(read64(&mut dev, Reg::IQH.0)).head_offset(), 16);
3597 }
3598
3599 #[test]
3600 fn test_remap_msi_compat_format_blocked() {
3601 let gm = GuestMemory::allocate(0x40_0000);
3602 let signal_msi = Arc::new(TestSignalMsi);
3603 let (_dev, shared) = IntelVtdDevice::new(
3604 gm,
3605 IntelVtdConfig {
3606 mmio_base: TEST_MMIO_BASE,
3607 },
3608 signal_msi,
3609 );
3610
3611 setup_ir_state(&shared, false);
3612 let addr = 0xFEE0_0000u64; let state = shared.state.read();
3617 let err = shared
3618 .remap_msi_locked(&state, 0x0000, addr, 0)
3619 .unwrap_err();
3620 assert!(matches!(err, VtdFault::CompatibilityFormatBlocked { .. }));
3621 }
3622
3623 #[test]
3624 fn test_remap_msi_compat_format_passthrough_cfis() {
3625 let gm = GuestMemory::allocate(0x40_0000);
3626 let signal_msi = Arc::new(TestSignalMsi);
3627 let (_dev, shared) = IntelVtdDevice::new(
3628 gm,
3629 IntelVtdConfig {
3630 mmio_base: TEST_MMIO_BASE,
3631 },
3632 signal_msi,
3633 );
3634
3635 setup_ir_state(&shared, false);
3636
3637 {
3639 let mut state = shared.state.write();
3640 let mut gsts = state.gsts;
3641 gsts.set_cfis(true);
3642 state.gsts = gsts;
3643 }
3644
3645 let addr = 0xFEE0_0000u64; let state = shared.state.read();
3647 let (a, d) = shared.remap_msi_locked(&state, 0x0000, addr, 0x42).unwrap();
3648 assert_eq!(a, addr);
3649 assert_eq!(d, 0x42);
3650 }
3651
3652 #[test]
3653 fn test_remap_msi_source_validation_verify_sid() {
3654 let gm = GuestMemory::allocate(0x40_0000);
3655 let signal_msi = Arc::new(TestSignalMsi);
3656 let (_dev, shared) = IntelVtdDevice::new(
3657 gm.clone(),
3658 IntelVtdConfig {
3659 mmio_base: TEST_MMIO_BASE,
3660 },
3661 signal_msi,
3662 );
3663
3664 setup_ir_state(&shared, false);
3665
3666 let irte = Irte {
3668 lo: IrteLo::new()
3669 .with_p(true)
3670 .with_vector(0x30)
3671 .with_dst(0x0100)
3672 .with_dlm(0)
3673 .with_dm(false),
3674 hi: IrteHi::new().with_svt(0b01).with_sq(0b00).with_sid(0x0100),
3675 };
3676 gm.write_at(IRT_BASE_ADDR, irte.as_bytes()).unwrap();
3677
3678 let addr = 0xFEE0_0010u64;
3679 let state = shared.state.read();
3680
3681 assert!(shared.remap_msi_locked(&state, 0x0100, addr, 0).is_ok());
3683
3684 let err = shared
3686 .remap_msi_locked(&state, 0x0200, addr, 0)
3687 .unwrap_err();
3688 assert!(matches!(err, VtdFault::SourceValidationFailed { .. }));
3689 }
3690
3691 #[test]
3692 fn test_record_fault() {
3693 let gm = GuestMemory::allocate(0x40_0000);
3694 let signal_msi = Arc::new(TestSignalMsi);
3695 let (_dev, shared) = IntelVtdDevice::new(
3696 gm,
3697 IntelVtdConfig {
3698 mmio_base: TEST_MMIO_BASE,
3699 },
3700 signal_msi,
3701 );
3702
3703 let fault = VtdFault::RootNotPresent {
3704 source_id: 0x0100,
3705 iova: 0x1000,
3706 };
3707 fault.record(&shared, false); let state = shared.state.read();
3710 let frcd_hi = state.frcd_hi;
3711 assert!(frcd_hi.f());
3712 assert_eq!(frcd_hi.sid(), 0x0100);
3713 assert_eq!(frcd_hi.fr(), FaultReason::ROOT_NOT_PRESENT.0);
3714 assert!(frcd_hi.t()); let frcd_lo = state.frcd_lo;
3717 assert_eq!(frcd_lo.fault_address(), 0x1000);
3718 }
3719
3720 #[test]
3721 fn test_frcd_raw_mmio_reason_position() {
3722 let mut dev = create_test_device();
3723 for reason in 0..=u8::MAX {
3724 for is_read in [false, true] {
3725 {
3726 let mut state = dev.shared.state.write();
3727 dev.shared.record_fault_locked(
3728 &mut state,
3729 0xabcd,
3730 FaultReason(reason),
3731 0x1234_5678_abcd,
3732 is_read,
3733 false,
3734 );
3735 }
3736 let dw3 = 0x8000_0000 | ((is_read as u32) << 30) | u32::from(reason);
3739 assert_eq!(read32(&mut dev, 0x120), 0x5678_a000);
3740 assert_eq!(read32(&mut dev, 0x124), 0x1234);
3741 assert_eq!(read32(&mut dev, 0x128), 0xabcd);
3742 assert_eq!(read32(&mut dev, 0x12c), dw3);
3743 assert_eq!(read64(&mut dev, 0x128), (u64::from(dw3) << 32) | 0xabcd);
3744 write32(&mut dev, 0x12c, 1 << 31);
3746 assert_eq!(read32(&mut dev, 0x12c), dw3 & !(1 << 31));
3747 }
3748 }
3749 }
3750
3751 #[test]
3752 fn test_iqa_raw_mmio_layout() {
3753 let mut dev = create_test_device();
3754 for qs in 0..=7 {
3755 for dw in [0, 1] {
3756 let raw = 0x1234_5678_9000 | (dw << 11) | qs;
3757 write64(&mut dev, 0x090, raw);
3758 assert_eq!(read64(&mut dev, 0x090), raw);
3759 let state = dev.shared.state.read();
3760 assert_eq!(state.iqa.dw(), dw != 0);
3761 assert_eq!(state.iqa.qs(), qs as u8);
3762 assert_eq!(state.iqa.queue_size_bytes(), 4096 << qs);
3763 }
3764 }
3765 }
3766
3767 #[test]
3768 fn test_record_fault_overflow() {
3769 let gm = GuestMemory::allocate(0x40_0000);
3770 let signal_msi = Arc::new(TestSignalMsi);
3771 let (_dev, shared) = IntelVtdDevice::new(
3772 gm,
3773 IntelVtdConfig {
3774 mmio_base: TEST_MMIO_BASE,
3775 },
3776 signal_msi,
3777 );
3778
3779 let fault1 = VtdFault::RootNotPresent {
3781 source_id: 0x0100,
3782 iova: 0x1000,
3783 };
3784 fault1.record(&shared, true); let fault2 = VtdFault::ContextNotPresent {
3788 source_id: 0x0200,
3789 iova: 0x2000,
3790 fpd: false,
3791 };
3792 fault2.record(&shared, false);
3793
3794 let state = shared.state.read();
3795 let fsts = state.fsts;
3797 assert!(fsts.pfo());
3798 let frcd_hi = state.frcd_hi;
3800 assert_eq!(frcd_hi.sid(), 0x0100);
3801 }
3802
3803 #[test]
3804 fn test_vtd_translator() {
3805 let (_dev, shared) = create_test_device_with_translation();
3806 let translator = shared.translator();
3807
3808 let result = iommu_common::IommuTranslator::translate(
3810 &translator,
3811 0x0000, 0x0000, false,
3814 |gpa| gpa,
3815 )
3816 .unwrap();
3817 assert_eq!(result, TARGET_GPA);
3818 }
3819
3820 #[test]
3821 fn test_vtd_signal_msi() {
3822 use std::sync::atomic::{AtomicU64, Ordering};
3823
3824 struct RecordingMsi {
3825 last_addr: AtomicU64,
3826 }
3827 impl SignalMsi for RecordingMsi {
3828 fn signal_msi(&self, _devid: Option<u32>, address: u64, _data: u32) {
3829 self.last_addr.store(address, Ordering::SeqCst);
3830 }
3831 }
3832
3833 let gm = GuestMemory::allocate(0x40_0000);
3834 let inner_msi = Arc::new(RecordingMsi {
3835 last_addr: AtomicU64::new(0),
3836 });
3837 let signal_msi = Arc::new(TestSignalMsi);
3838
3839 let (_dev, shared) = IntelVtdDevice::new(
3840 gm.clone(),
3841 IntelVtdConfig {
3842 mmio_base: TEST_MMIO_BASE,
3843 },
3844 signal_msi,
3845 );
3846
3847 let wrapper = shared.wrap_signal_msi(inner_msi.clone());
3849 wrapper.signal_msi(Some(0x0100), 0xFEE0_1234, 0x42);
3850 assert_eq!(inner_msi.last_addr.load(Ordering::SeqCst), 0xFEE0_1234);
3851 }
3852
3853 #[test]
3854 fn test_vtd_signal_msi_no_devid_dropped() {
3855 use std::sync::atomic::{AtomicU32, Ordering};
3856
3857 struct CountingMsi {
3858 count: AtomicU32,
3859 }
3860 impl SignalMsi for CountingMsi {
3861 fn signal_msi(&self, _devid: Option<u32>, _address: u64, _data: u32) {
3862 self.count.fetch_add(1, Ordering::SeqCst);
3863 }
3864 }
3865
3866 let gm = GuestMemory::allocate(0x40_0000);
3867 let inner_msi = Arc::new(CountingMsi {
3868 count: AtomicU32::new(0),
3869 });
3870 let signal_msi = Arc::new(TestSignalMsi);
3871
3872 let (_dev, shared) = IntelVtdDevice::new(
3873 gm,
3874 IntelVtdConfig {
3875 mmio_base: TEST_MMIO_BASE,
3876 },
3877 signal_msi,
3878 );
3879
3880 let wrapper = shared.wrap_signal_msi(inner_msi.clone());
3881
3882 wrapper.signal_msi(None, 0xFEE0_1234, 0x42);
3884 assert_eq!(inner_msi.count.load(Ordering::SeqCst), 0);
3885 }
3886
3887 use spec::invalidation::InvalidationWaitDw0Dw1;
3895 use spec::invalidation::InvalidationWaitDw2Dw3;
3896
3897 const E2E_MEM_SIZE: usize = 0x80_0000;
3901 const E2E_ROOT_TABLE: u64 = 0x10_0000; const E2E_CONTEXT_TABLE: u64 = 0x11_0000; const E2E_PT_L4: u64 = 0x12_0000;
3904 const E2E_PT_L3: u64 = 0x13_0000;
3905 const E2E_PT_L2: u64 = 0x14_0000;
3906 const E2E_PT_L1: u64 = 0x15_0000;
3907 const E2E_TARGET_GPA: u64 = 0x20_0000; const E2E_IQ_BASE: u64 = 0x30_0000; const E2E_IQ_STATUS: u64 = 0x31_0000; const E2E_IRT_BASE: u64 = 0x40_0000; const E2E_TEST_BUS: u8 = 1;
3913 const E2E_TEST_DEVFN: u8 = 0x00;
3914 const E2E_TEST_RID: u16 = 0x0100;
3915
3916 #[test]
3936 fn test_end_to_end_linux_init_sequence() {
3937 for (scalable, dw) in [(false, false), (false, true), (true, true)] {
3938 linux_init_sequence(scalable, dw);
3939 }
3940 }
3941
3942 fn linux_init_sequence(scalable: bool, dw: bool) {
3943 use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
3944
3945 struct RecordingMsi {
3947 last_addr: AtomicU64,
3948 last_data: AtomicU32,
3949 count: AtomicU32,
3950 }
3951 impl RecordingMsi {
3952 fn new() -> Self {
3953 Self {
3954 last_addr: AtomicU64::new(0),
3955 last_data: AtomicU32::new(0),
3956 count: AtomicU32::new(0),
3957 }
3958 }
3959 }
3960 impl SignalMsi for RecordingMsi {
3961 fn signal_msi(&self, _devid: Option<u32>, address: u64, data: u32) {
3962 self.last_addr.store(address, Ordering::SeqCst);
3963 self.last_data.store(data, Ordering::SeqCst);
3964 self.count.fetch_add(1, Ordering::SeqCst);
3965 }
3966 }
3967
3968 let gm = GuestMemory::allocate(E2E_MEM_SIZE);
3969 let iommu_msi = Arc::new(RecordingMsi::new());
3970 let (mut dev, shared) = IntelVtdDevice::new(
3971 gm.clone(),
3972 IntelVtdConfig {
3973 mmio_base: TEST_MMIO_BASE,
3974 },
3975 iommu_msi.clone(),
3976 );
3977
3978 let ver = read32(&mut dev, 0x000);
3982 assert_eq!(VersionReg::from(ver).max(), 1);
3983 assert_eq!(VersionReg::from(ver).min(), 0);
3984
3985 let cap = read64(&mut dev, 0x008);
3986 let cap_reg = CapReg::from(cap);
3987 assert_eq!(cap_reg.mgaw(), 47); assert!(cap_reg.sagaw() & 0x4 != 0); assert!(cap_reg.sagaw() & 0x2 != 0); assert_eq!(cap_reg.nfr(), 0); let ecap = read64(&mut dev, 0x010);
3993 assert_eq!(ecap, 0x0003_6800_00f0_10db);
3994 let ecap_reg = EcapReg::from(ecap);
3995 assert!(ecap_reg.qi()); assert!(ecap_reg.ir()); assert!(ecap_reg.eim()); assert!(ecap_reg.c()); assert_eq!(read32(&mut dev, 0x01C), 0);
4002
4003 let root_entry = RootEntry {
4012 lo: RootEntryLo::new()
4013 .with_p(true)
4014 .with_ctp(E2E_CONTEXT_TABLE >> 12),
4015 hi: 0,
4016 };
4017 gm.write_at(
4018 E2E_ROOT_TABLE + (E2E_TEST_BUS as u64) * 16,
4019 root_entry.as_bytes(),
4020 )
4021 .unwrap();
4022
4023 let context_entry = ContextEntry {
4025 lo: ContextEntryLo::new()
4026 .with_p(true)
4027 .with_tt(TranslationType::UNTRANSLATED_ONLY.0)
4028 .with_ssptptr(E2E_PT_L4 >> 12),
4029 hi: ContextEntryHi::new()
4030 .with_aw(AddressWidth::AW_48BIT.0)
4031 .with_did(1), };
4033 gm.write_at(
4034 E2E_CONTEXT_TABLE + (E2E_TEST_DEVFN as u64) * 16,
4035 context_entry.as_bytes(),
4036 )
4037 .unwrap();
4038 if scalable {
4039 let directory = 0x16_0000u64;
4041 let pasid_table = 0x17_0000u64;
4042 for (address, words) in [
4043 (E2E_CONTEXT_TABLE, vec![directory | 1, 65, 0, 0]),
4044 (directory + 8, vec![pasid_table | 1]),
4045 (
4046 pasid_table + 64,
4047 vec![
4048 E2E_PT_L4 | 1 | (2 << 2) | (2 << 6) | (1 << 9),
4049 1 | (1 << 23),
4050 0,
4051 0,
4052 0,
4053 0,
4054 0,
4055 0,
4056 ],
4057 ),
4058 ] {
4059 for (index, word) in words.into_iter().enumerate() {
4060 gm.write_at(address + index as u64 * 8, &word.to_le_bytes())
4061 .unwrap();
4062 }
4063 }
4064 }
4065
4066 let pte_l4 = SlPte::new()
4068 .with_r(true)
4069 .with_w(true)
4070 .with_address(E2E_PT_L3 >> 12);
4071 gm.write_at(E2E_PT_L4, pte_l4.into_bits().as_bytes())
4072 .unwrap();
4073
4074 let pte_l3 = SlPte::new()
4075 .with_r(true)
4076 .with_w(true)
4077 .with_address(E2E_PT_L2 >> 12);
4078 gm.write_at(E2E_PT_L3, pte_l3.into_bits().as_bytes())
4079 .unwrap();
4080
4081 let pte_l2 = SlPte::new()
4082 .with_r(true)
4083 .with_w(true)
4084 .with_address(E2E_PT_L1 >> 12);
4085 gm.write_at(E2E_PT_L2, pte_l2.into_bits().as_bytes())
4086 .unwrap();
4087
4088 let pte_l1 = SlPte::new()
4089 .with_r(true)
4090 .with_w(true)
4091 .with_address(E2E_TARGET_GPA >> 12);
4092 gm.write_at(E2E_PT_L1, pte_l1.into_bits().as_bytes())
4093 .unwrap();
4094
4095 let rtaddr = E2E_ROOT_TABLE | (u64::from(scalable) << 10);
4097 write64(&mut dev, 0x020, rtaddr);
4098 assert_eq!(read64(&mut dev, 0x020), rtaddr);
4099
4100 write32(&mut dev, 0x018, GcmdReg::new().with_srtp(true).into_bits());
4102 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4103 assert!(gsts.rtps(), "RTPS must be set after SRTP");
4104
4105 if !scalable {
4110 let ccmd = CcmdReg::new().with_icc(true).with_cirg(1); write64(&mut dev, 0x028, ccmd.into_bits());
4113 let ccmd_result = CcmdReg::from(read64(&mut dev, 0x028));
4114 assert!(!ccmd_result.icc(), "ICC must be cleared after invalidation");
4115 assert_eq!(ccmd_result.caig(), 1, "CAIG must echo CIRG");
4116
4117 let iotlb_val = IotlbReg::new().with_ivt(true).with_iirg(1).into_bits();
4119 write64(&mut dev, Reg::IOTLB.0, iotlb_val);
4120 let iotlb_result = IotlbReg::from(read64(&mut dev, Reg::IOTLB.0));
4121 assert!(!iotlb_result.ivt(), "IVT must be cleared");
4122 assert_eq!(iotlb_result.iaig(), 1, "IAIG must echo IIRG");
4123 }
4124
4125 let stride = if dw { 32 } else { 16 };
4131 let iqa = IqaReg::new()
4132 .with_qs(0)
4133 .with_dw(dw)
4134 .with_iqa(E2E_IQ_BASE >> 12);
4135 write64(&mut dev, 0x090, iqa.into_bits());
4136 assert_eq!(read64(&mut dev, 0x090), iqa.into_bits());
4137
4138 write32(&mut dev, 0x018, GcmdReg::new().with_qie(true).into_bits());
4140 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4141 assert!(gsts.qies(), "QIES must be set after QIE");
4142
4143 assert_eq!(read64(&mut dev, 0x080), 0, "IQH must start at 0");
4145
4146 write32(
4154 &mut dev,
4155 0x018,
4156 GcmdReg::new().with_te(true).with_qie(true).into_bits(),
4157 );
4158 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4159 assert!(gsts.tes(), "TES must be set after TE");
4160 assert!(gsts.qies(), "QIES must remain set");
4161
4162 let desc0 = spec::invalidation::InvalidationDescriptor {
4171 dw0: DescriptorType::CONTEXT_CACHE_INVALIDATE.0 as u32 | (1u32 << 4), dw1: 0,
4173 dw2: 0,
4174 dw3: 0,
4175 };
4176 gm.write_at(E2E_IQ_BASE, desc0.as_bytes()).unwrap();
4177
4178 let desc1 = spec::invalidation::InvalidationDescriptor {
4180 dw0: DescriptorType::IOTLB_INVALIDATE.0 as u32 | (1u32 << 4), dw1: 0,
4182 dw2: 0,
4183 dw3: 0,
4184 };
4185 gm.write_at(E2E_IQ_BASE + stride, desc1.as_bytes()).unwrap();
4186
4187 let iw_lo = InvalidationWaitDw0Dw1::new()
4189 .with_desc_type(DescriptorType::INVALIDATION_WAIT.0)
4190 .with_sw(true)
4191 .with_status_data(0xDEAD_BEEF);
4192 let iw_hi = InvalidationWaitDw2Dw3::new().with_sal(E2E_IQ_STATUS >> 2);
4193 let desc2 = spec::invalidation::InvalidationDescriptor {
4194 dw0: iw_lo.into_bits() as u32,
4195 dw1: (iw_lo.into_bits() >> 32) as u32,
4196 dw2: iw_hi.into_bits() as u32,
4197 dw3: (iw_hi.into_bits() >> 32) as u32,
4198 };
4199 gm.write_at(E2E_IQ_BASE + 2 * stride, desc2.as_bytes())
4200 .unwrap();
4201
4202 gm.write_at(E2E_IQ_STATUS, &0u32.to_le_bytes()).unwrap();
4204
4205 write64(&mut dev, 0x088, 3 * stride);
4206
4207 let iqh = IqhReg::from(read64(&mut dev, 0x080));
4209 assert_eq!(
4210 iqh.head_offset(),
4211 3 * stride,
4212 "IQH must advance to tail after processing"
4213 );
4214
4215 let status: u32 = gm.read_plain(E2E_IQ_STATUS).unwrap();
4217 assert_eq!(
4218 status, 0xDEAD_BEEF,
4219 "INVALIDATION_WAIT must write status data"
4220 );
4221
4222 let translator = shared.translator();
4226
4227 let gpa = iommu_common::IommuTranslator::translate(
4229 &translator,
4230 E2E_TEST_RID,
4231 0x0000,
4232 false, |gpa| {
4234 assert_eq!(gm.read_plain::<[u8; 2]>(gpa).unwrap(), [0, 0]);
4235 gpa
4236 },
4237 )
4238 .unwrap();
4239 assert_eq!(gpa, E2E_TARGET_GPA, "IOVA 0x0 must map to target GPA");
4240 assert_eq!(
4241 u64::from_le(gm.read_plain::<u64>(E2E_PT_L1).unwrap()),
4242 pte_l1.into_bits() | if scalable { 1 << 8 } else { 0 },
4243 );
4244
4245 let gpa = iommu_common::IommuTranslator::translate(
4247 &translator,
4248 E2E_TEST_RID,
4249 0x0000,
4250 true, |gpa| {
4252 gm.write_at(gpa, &[0x5a, 0xa5]).unwrap();
4253 gpa
4254 },
4255 )
4256 .unwrap();
4257 assert_eq!(gpa, E2E_TARGET_GPA, "IOVA 0x0 write must map to target GPA");
4258 let payload =
4259 iommu_common::IommuTranslator::translate(&translator, E2E_TEST_RID, 0, false, |gpa| {
4260 gm.read_plain::<[u8; 2]>(gpa).unwrap()
4261 })
4262 .unwrap();
4263 assert_eq!(payload, [0x5a, 0xa5]);
4264 for (address, original, leaf) in [
4265 (E2E_PT_L4, pte_l4, false),
4266 (E2E_PT_L3, pte_l3, false),
4267 (E2E_PT_L2, pte_l2, false),
4268 (E2E_PT_L1, pte_l1, true),
4269 ] {
4270 assert_eq!(
4271 u64::from_le(gm.read_plain::<u64>(address).unwrap()),
4272 original.into_bits()
4273 | if scalable {
4274 (1 << 8) | if leaf { 1 << 9 } else { 0 }
4275 } else {
4276 0
4277 },
4278 );
4279 }
4280
4281 let gpa = iommu_common::IommuTranslator::translate(
4283 &translator,
4284 E2E_TEST_RID,
4285 0x0ABC,
4286 false,
4287 |gpa| gpa,
4288 )
4289 .unwrap();
4290 assert_eq!(
4291 gpa,
4292 E2E_TARGET_GPA + 0xABC,
4293 "IOVA page offset must be preserved"
4294 );
4295
4296 let irte = Irte {
4302 lo: IrteLo::new()
4303 .with_p(true)
4304 .with_vector(0x42)
4305 .with_dst(0x0500) .with_dlm(0) .with_dm(false), hi: IrteHi::new()
4309 .with_svt(0b01) .with_sq(0b00) .with_sid(E2E_TEST_RID),
4312 };
4313 gm.write_at(E2E_IRT_BASE, irte.as_bytes()).unwrap();
4314
4315 let irta = IrtaReg::new()
4317 .with_irta(E2E_IRT_BASE >> 12)
4318 .with_s(0) .with_eime(false);
4320 write64(&mut dev, 0x0B8, irta.into_bits());
4321
4322 write32(
4324 &mut dev,
4325 0x018,
4326 GcmdReg::new()
4327 .with_sirtp(true)
4328 .with_te(true)
4329 .with_qie(true)
4330 .into_bits(),
4331 );
4332 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4333 assert!(gsts.irtps(), "IRTPS must be set after SIRTP");
4334
4335 write32(
4337 &mut dev,
4338 0x018,
4339 GcmdReg::new()
4340 .with_ire(true)
4341 .with_te(true)
4342 .with_qie(true)
4343 .into_bits(),
4344 );
4345 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4346 assert!(gsts.ires(), "IRES must be set after IRE");
4347
4348 let inner_msi = Arc::new(RecordingMsi::new());
4352 let wrapper = shared.wrap_signal_msi(inner_msi.clone());
4353
4354 let msi_addr = 0xFEE0_0010u64;
4356 let msi_data = 0u32;
4357 wrapper.signal_msi(Some(E2E_TEST_RID as u32), msi_addr, msi_data);
4358
4359 assert_eq!(
4361 inner_msi.count.load(Ordering::SeqCst),
4362 1,
4363 "Remapped MSI must be delivered"
4364 );
4365 let delivered_addr = inner_msi.last_addr.load(Ordering::SeqCst);
4366 let delivered_data = inner_msi.last_data.load(Ordering::SeqCst);
4367 assert_eq!(
4369 (delivered_addr >> 12) & 0xFF,
4370 5,
4371 "Remapped MSI dest must be APIC ID 5"
4372 );
4373 assert_eq!(
4375 delivered_data & 0xFF,
4376 0x42,
4377 "Remapped MSI vector must be 0x42"
4378 );
4379
4380 let fault_result = iommu_common::IommuTranslator::translate(
4386 &translator,
4387 E2E_TEST_RID,
4388 0x1000,
4389 false,
4390 |gpa| gpa,
4391 );
4392 assert!(
4393 fault_result.is_err(),
4394 "Unmapped IOVA must produce a translation fault"
4395 );
4396
4397 let frcd_hi = read64(&mut dev, Reg::FRCD_DW2.0);
4399 let frcd = FrcdHi::from(frcd_hi);
4400 assert!(frcd.f(), "Fault must be recorded (F=1)");
4401 assert_eq!(
4402 frcd.sid(),
4403 E2E_TEST_RID,
4404 "Fault source ID must match test device"
4405 );
4406
4407 let fsts = FstsReg::from(read32(&mut dev, 0x034));
4409 assert!(fsts.ppf(), "PPF must be set when fault is pending");
4410
4411 write64(&mut dev, Reg::FRCD_DW2.0, 1u64 << 63);
4413 let fsts = FstsReg::from(read32(&mut dev, 0x034));
4414 assert!(!fsts.ppf(), "PPF must clear when F is cleared");
4415
4416 let wrong_rid_wrapper = shared.wrap_signal_msi(inner_msi.clone());
4420 let pre_count = inner_msi.count.load(Ordering::SeqCst);
4421 wrong_rid_wrapper.signal_msi(Some(0x0200), msi_addr, msi_data); assert_eq!(
4423 inner_msi.count.load(Ordering::SeqCst),
4424 pre_count,
4425 "MSI with wrong source ID must be dropped"
4426 );
4427
4428 write32(
4433 &mut dev,
4434 0x018,
4435 GcmdReg::new()
4436 .with_te(false)
4437 .with_qie(true)
4438 .with_ire(true)
4439 .into_bits(),
4440 );
4441 let gsts = GstsReg::from(read32(&mut dev, 0x01C));
4442 assert!(!gsts.tes(), "TES must clear when TE=0");
4443 assert!(gsts.qies(), "QIES must remain set");
4444 assert!(gsts.ires(), "IRES must remain set");
4445
4446 let gpa = iommu_common::IommuTranslator::translate(
4448 &translator,
4449 E2E_TEST_RID,
4450 0xDEAD_0000,
4451 false,
4452 |gpa| gpa,
4453 )
4454 .unwrap();
4455 assert_eq!(
4456 gpa, 0xDEAD_0000,
4457 "Disabled translation must return identity mapping"
4458 );
4459 }
4460}