diff --git a/ostd/src/arch/x86/iommu/dma_remapping/mod.rs b/ostd/src/arch/x86/iommu/dma_remapping/mod.rs index 0a9511db..2235fab0 100644 --- a/ostd/src/arch/x86/iommu/dma_remapping/mod.rs +++ b/ostd/src/arch/x86/iommu/dma_remapping/mod.rs @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MPL-2.0 pub use context_table::RootTable; -use log::info; +use log::{info, warn}; use second_stage::{DeviceMode, PageTableEntry, PagingConsts}; use spin::Once; use super::IommuError; use crate::{ - arch::iommu::registers::IOMMU_REGS, + arch::iommu::registers::{CapabilitySagaw, IOMMU_REGS}, bus::pci::PciDeviceLocation, mm::{Daddr, PageTable}, prelude::Paddr, @@ -59,16 +59,28 @@ pub fn unmap(daddr: Daddr) -> Result<(), IommuError> { } pub fn init() { - // Create Root Table instance + if !IOMMU_REGS + .get() + .unwrap() + .lock() + .read_capability() + .supported_adjusted_guest_address_widths() + .contains(CapabilitySagaw::AGAW_39BIT_3LP) + { + warn!("[IOMMU] 3-level page tables not supported, disabling DMA remapping"); + return; + } + + // Create a Root Table instance. let mut root_table = RootTable::new(); - // For all PCI Device, use the same page table. + // For all PCI devices, use the same page table. let page_table = PageTable::::empty(); for table in PciDeviceLocation::all() { root_table.specify_device_page_table(table, unsafe { page_table.shallow_copy() }) } PAGE_TABLE.call_once(|| SpinLock::new(root_table)); - // Enable DMA remapping + // Enable DMA remapping. let mut iommu_regs = IOMMU_REGS.get().unwrap().lock(); iommu_regs.enable_dma_remapping(PAGE_TABLE.get().unwrap()); info!("[IOMMU] DMA remapping enabled"); diff --git a/ostd/src/arch/x86/iommu/registers/capability.rs b/ostd/src/arch/x86/iommu/registers/capability.rs index 391a9bed..011b9495 100644 --- a/ostd/src/arch/x86/iommu/registers/capability.rs +++ b/ostd/src/arch/x86/iommu/registers/capability.rs @@ -38,7 +38,7 @@ impl Capability { /// Number of domain support. /// - /// ```norun + /// ```text /// 0 => 4-bit domain-ids with support for up to 16 domains. /// 1 => 6-bit domain-ids with support for up to 64 domains. /// 2 => 8-bit domain-ids with support for up to 256 domains. @@ -54,15 +54,8 @@ impl Capability { } /// Supported Adjusted Guest Address Widths. - /// ```norun - /// 0/4 => Reserved - /// 1 => 39-bit AGAW (3-level page-table) - /// 2 => 48-bit AGAW (4-level page-table) - /// 3 => 57-bit AGAW (5-level page-table) - /// ``` - pub const fn supported_adjusted_guest_address_widths(&self) -> u64 { - const SAGAW_MASK: u64 = 0x1F << 8; - (self.0 & SAGAW_MASK) >> 8 + pub const fn supported_adjusted_guest_address_widths(&self) -> CapabilitySagaw { + CapabilitySagaw::from_bits_truncate(self.0 >> 8) } /// Fault-recording Register offset, specifies the offset of the first fault recording @@ -74,15 +67,10 @@ impl Capability { const FRO_MASK: u64 = 0x3FF << 24; (self.0 & FRO_MASK) >> 24 } + /// Second Stage Large Page Support. - /// ```norun - /// 2/3 => Reserved - /// 0 => 21-bit offset to page frame(2MB) - /// 1 => 30-bit offset to page frame(1GB) - /// ``` - pub const fn second_stage_large_page_support(&self) -> u64 { - const SSLPS_MASK: u64 = 0xF << 34; - (self.0 & SSLPS_MASK) >> 34 + pub const fn second_stage_large_page_support(&self) -> CapabilitySslps { + CapabilitySslps::from_bits_truncate(self.0 >> 34) } /// Maximum Guest Address Width. The maximum guest physical address width supported @@ -127,7 +115,7 @@ impl Debug for Capability { bitflags! { /// Capability flags in IOMMU. - pub struct CapabilityFlags: u64{ + pub struct CapabilityFlags: u64 { /// Required Write-Buffer Flushing. const RWBF = 1 << 4; /// Protected Low-Memory Region @@ -160,3 +148,27 @@ bitflags! { const ESRTPS = 1 << 63; } } + +bitflags! { + /// Supported Adjusted Guest Address Widths (SAGAW) in IOMMU. + pub struct CapabilitySagaw: u64 { + /// 39-bit AGAW (3-level page-table). + const AGAW_39BIT_3LP = 1 << 1; + /// 48-bit AGAW (4-level page-table). + const AGAW_48BIT_4LP = 1 << 2; + /// 57-bit AGAW (5-level page-table). + const AGAW_57BIT_5LP = 1 << 3; + // 0th and 4th bits are reserved. + } +} + +bitflags! { + /// Second Stage Large Page Support (SSLPS) in IOMMU. + pub struct CapabilitySslps: u64 { + /// 21-bit offset to page frame (2MB). + const PAGE_21BIT_2MB = 1 << 0; + /// 30-bit offset to page frame (1GB). + const PAGE_30BIT_1GB = 1 << 1; + // 2nd and 3rd bits are reserved. + } +} diff --git a/ostd/src/arch/x86/iommu/registers/mod.rs b/ostd/src/arch/x86/iommu/registers/mod.rs index 514cf7dc..faac7f35 100644 --- a/ostd/src/arch/x86/iommu/registers/mod.rs +++ b/ostd/src/arch/x86/iommu/registers/mod.rs @@ -11,7 +11,7 @@ mod status; use core::ptr::NonNull; use bit_field::BitField; -pub use capability::Capability; +pub use capability::{Capability, CapabilitySagaw}; use command::GlobalCommand; use extended_cap::ExtendedCapability; pub use extended_cap::ExtendedCapabilityFlags;