mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 03:56:42 +00:00
Support IOMMU page fault reporting
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
1bfd6ea2f8
commit
054f13e32f
@ -137,7 +137,7 @@ impl RootTable {
|
|||||||
}
|
}
|
||||||
let address = page_table.root_paddr();
|
let address = page_table.root_paddr();
|
||||||
context_table.page_tables.insert(address, page_table);
|
context_table.page_tables.insert(address, page_table);
|
||||||
let entry = ContextEntry(address as u128 | 3 | 0x1_0000_0000_0000_0000);
|
let entry = ContextEntry(address as u128 | 1 | 0x1_0000_0000_0000_0000);
|
||||||
context_table
|
context_table
|
||||||
.entries_frame
|
.entries_frame
|
||||||
.write_val::<ContextEntry>(
|
.write_val::<ContextEntry>(
|
||||||
|
206
framework/jinux-frame/src/arch/x86/iommu/fault.rs
Normal file
206
framework/jinux-frame/src/arch/x86/iommu/fault.rs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use log::info;
|
||||||
|
use spin::Once;
|
||||||
|
use trapframe::TrapFrame;
|
||||||
|
use volatile::{access::ReadWrite, Volatile};
|
||||||
|
|
||||||
|
use crate::{trap::IrqAllocateHandle, vm::Vaddr};
|
||||||
|
|
||||||
|
use super::remapping::Capability;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FaultEventRegisters {
|
||||||
|
status: Volatile<&'static mut u32, ReadWrite>,
|
||||||
|
/// bit31: Interrupt Mask; bit30: Interrupt Pending.
|
||||||
|
control: Volatile<&'static mut u32, ReadWrite>,
|
||||||
|
data: Volatile<&'static mut u32, ReadWrite>,
|
||||||
|
address: Volatile<&'static mut u32, ReadWrite>,
|
||||||
|
upper_address: Volatile<&'static mut u32, ReadWrite>,
|
||||||
|
recordings: Vec<Volatile<&'static mut u128, ReadWrite>>,
|
||||||
|
|
||||||
|
fault_irq: IrqAllocateHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FaultEventRegisters {
|
||||||
|
pub fn status(&self) -> FaultStatus {
|
||||||
|
FaultStatus::from_bits_truncate(self.status.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// User must ensure the base_register_vaddr is read from DRHD
|
||||||
|
unsafe fn new(base_register_vaddr: Vaddr) -> Self {
|
||||||
|
let capability = Volatile::new_read_only(&*((base_register_vaddr + 0x08) as *const u64));
|
||||||
|
let length = ((capability.read() & Capability::NFR.bits()) >> 40) + 1;
|
||||||
|
let mut recordings = Vec::with_capacity(length as usize);
|
||||||
|
let offset = (capability.read() & 0x3_ff00_0000) >> 24;
|
||||||
|
for i in 0..length {
|
||||||
|
recordings.push(Volatile::new(
|
||||||
|
&mut *((base_register_vaddr + 16 * (offset + i) as usize) as *mut u128),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
let status = Volatile::new(&mut *((base_register_vaddr + 0x34) as *mut u32));
|
||||||
|
let mut control = Volatile::new(&mut *((base_register_vaddr + 0x38) as *mut u32));
|
||||||
|
let mut data = Volatile::new(&mut *((base_register_vaddr + 0x3c) as *mut u32));
|
||||||
|
let mut address = Volatile::new(&mut *((base_register_vaddr + 0x40) as *mut u32));
|
||||||
|
let upper_address = Volatile::new(&mut *((base_register_vaddr + 0x44) as *mut u32));
|
||||||
|
let mut fault_irq = crate::trap::allocate_irq().unwrap();
|
||||||
|
|
||||||
|
// Set page fault interrupt vector and address
|
||||||
|
data.write(fault_irq.num() as u32);
|
||||||
|
address.write(0xFEE0_0000);
|
||||||
|
control.write(0);
|
||||||
|
fault_irq.on_active(iommu_page_fault_handler);
|
||||||
|
FaultEventRegisters {
|
||||||
|
status,
|
||||||
|
control,
|
||||||
|
data,
|
||||||
|
address,
|
||||||
|
upper_address,
|
||||||
|
recordings,
|
||||||
|
fault_irq,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FaultRecording(u128);
|
||||||
|
|
||||||
|
impl FaultRecording {
|
||||||
|
pub fn fault(&self) -> bool {
|
||||||
|
self.0 & (1 << 127) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_type(&self) -> FaultRequestType {
|
||||||
|
// bit 126 and bit 92
|
||||||
|
let t1 = ((self.0 & (1 << 126)) >> 125) as u8;
|
||||||
|
let t2 = ((self.0 & (1 << 92)) >> 92) as u8;
|
||||||
|
let typ = t1 + t2;
|
||||||
|
match typ {
|
||||||
|
0 => FaultRequestType::Write,
|
||||||
|
1 => FaultRequestType::Page,
|
||||||
|
2 => FaultRequestType::Read,
|
||||||
|
3 => FaultRequestType::AtomicOp,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn address_type(&self) -> FaultAddressType {
|
||||||
|
match self.0 & (3 << 124) {
|
||||||
|
0 => FaultAddressType::UntranslatedRequest,
|
||||||
|
1 => FaultAddressType::TranslationRequest,
|
||||||
|
2 => FaultAddressType::TranslatedRequest,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_identifier(&self) -> u16 {
|
||||||
|
// bit 79:64
|
||||||
|
((self.0 & 0xFFFF_0000_0000_0000_0000) >> 64) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If fault reason is one of the address translation fault conditions, this field contains bits 63:12
|
||||||
|
/// of the page address in the faulted request.
|
||||||
|
///
|
||||||
|
/// If fault reason is interrupt-remapping fault conditions other than fault reash 0x25, bits 63:48
|
||||||
|
/// indicate the interrupt index computed for the faulted interrupt request, and bits 47:12 are cleared.
|
||||||
|
///
|
||||||
|
/// If fault reason is interrupt-remapping fault conditions of blocked compatibility mode interrupt (fault reason 0x25),
|
||||||
|
/// this field is undefined.
|
||||||
|
pub fn fault_info(&self) -> u64 {
|
||||||
|
// bit 63:12
|
||||||
|
((self.0 & 0xFFFF_FFFF_FFFF_F000) >> 12) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pasid_value(&self) -> u32 {
|
||||||
|
// bit 123:104
|
||||||
|
((self.0 & 0xF_FFFF0_0000_0000_0000_0000_0000_0000) >> 104) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fault_reason(&self) -> u8 {
|
||||||
|
// bit 103:96
|
||||||
|
((self.0 & 0xF_0000_0000_0000_0000_0000_0000) >> 96) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pasid_present(&self) -> bool {
|
||||||
|
// bit 95
|
||||||
|
(self.0 & 0x8000_0000_0000_0000_0000_0000) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_permission_request(&self) -> bool {
|
||||||
|
// bit 94
|
||||||
|
(self.0 & 0x4000_0000_0000_0000_0000_0000) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn privilege_mode_request(&self) -> bool {
|
||||||
|
// bit 93
|
||||||
|
(self.0 & 0x2000_0000_0000_0000_0000_0000) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for FaultRecording {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("FaultRecording")
|
||||||
|
.field("Fault", &self.fault())
|
||||||
|
.field("Request type", &self.request_type())
|
||||||
|
.field("Address type", &self.address_type())
|
||||||
|
.field("Source identifier", &self.source_identifier())
|
||||||
|
.field("Fault Reson", &self.fault_reason())
|
||||||
|
.field("Fault info", &self.fault_info())
|
||||||
|
.field("Raw", &self.0)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum FaultRequestType {
|
||||||
|
Write = 0,
|
||||||
|
Page = 1,
|
||||||
|
Read = 2,
|
||||||
|
AtomicOp = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum FaultAddressType {
|
||||||
|
UntranslatedRequest = 0,
|
||||||
|
TranslationRequest = 1,
|
||||||
|
TranslatedRequest = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct FaultStatus : u32{
|
||||||
|
/// Primary Fault Overflow, indicates overflow of the fault recording registers.
|
||||||
|
const PFO = 1 << 0;
|
||||||
|
/// Primary Pending Fault, indicates there are one or more pending faults logged in the fault recording registers.
|
||||||
|
const PPF = 1 << 1;
|
||||||
|
/// Invalidation Queue Error.
|
||||||
|
const IQE = 1 << 4;
|
||||||
|
/// Invalidation Completion Error. Hardware received an unexpected or invalid Device-TLB invalidation completion.
|
||||||
|
const ICE = 1 << 5;
|
||||||
|
/// Invalidation Time-out Error. Hardware detected a Device-TLB invalidation completion time-out.
|
||||||
|
const ITE = 1 << 6;
|
||||||
|
/// Fault Record Index, valid only when PPF field is set. This field indicates the index (from base) of the fault recording register
|
||||||
|
/// to which the first pending fault was recorded when the PPF field was Set by hardware.
|
||||||
|
const FRI = (0xFF) << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) static FAULT_EVENT_REGS: Once<FaultEventRegisters> = Once::new();
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// User must ensure the base_register_vaddr is read from DRHD
|
||||||
|
pub(super) unsafe fn init(base_register_vaddr: Vaddr) {
|
||||||
|
FAULT_EVENT_REGS.call_once(|| FaultEventRegisters::new(base_register_vaddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iommu_page_fault_handler(frame: &TrapFrame) {
|
||||||
|
let fault_event = FAULT_EVENT_REGS.get().unwrap();
|
||||||
|
let index = (fault_event.status().bits & FaultStatus::FRI.bits) >> 8;
|
||||||
|
let recording = FaultRecording(*(&fault_event.recordings[index as usize].read()));
|
||||||
|
info!("Catch iommu page fault, recording:{:x?}", recording)
|
||||||
|
}
|
@ -1,30 +1,20 @@
|
|||||||
mod context_table;
|
mod context_table;
|
||||||
|
mod fault;
|
||||||
|
mod remapping;
|
||||||
mod second_stage;
|
mod second_stage;
|
||||||
|
|
||||||
use log::debug;
|
use log::info;
|
||||||
use spin::{Mutex, Once};
|
use spin::{Mutex, Once};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::iommu::{context_table::RootTable, second_stage::PageTableEntry},
|
||||||
iommu::{context_table::RootTable, second_stage::PageTableEntry},
|
|
||||||
x86::kernel::acpi::{
|
|
||||||
dmar::{Dmar, Remapping},
|
|
||||||
ACPI_TABLES,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
bus::pci::PciDeviceLocation,
|
bus::pci::PciDeviceLocation,
|
||||||
vm::{
|
vm::{
|
||||||
paddr_to_vaddr,
|
|
||||||
page_table::{PageTableConfig, PageTableError},
|
page_table::{PageTableConfig, PageTableError},
|
||||||
Paddr, PageTable, Vaddr,
|
Paddr, PageTable, Vaddr,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use volatile::{
|
|
||||||
access::{ReadOnly, ReadWrite, WriteOnly},
|
|
||||||
Volatile,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum IommuError {
|
pub enum IommuError {
|
||||||
NoIommu,
|
NoIommu,
|
||||||
@ -83,11 +73,8 @@ pub(crate) fn unmap(vaddr: Vaddr) -> Result<(), IommuError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() -> Result<(), IommuError> {
|
pub(crate) fn init() -> Result<(), IommuError> {
|
||||||
let mut remapping_reg = RemappingRegisters::new().ok_or(IommuError::NoIommu)?;
|
|
||||||
|
|
||||||
let mut root_table = RootTable::new();
|
let mut root_table = RootTable::new();
|
||||||
|
|
||||||
// For all PCI Device, use the same page table.
|
// For all PCI Device, use the same page table.
|
||||||
let page_table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
let page_table: PageTable<PageTableEntry> = PageTable::new(PageTableConfig {
|
||||||
address_width: crate::vm::page_table::AddressWidth::Level3PageTable,
|
address_width: crate::vm::page_table::AddressWidth::Level3PageTable,
|
||||||
@ -95,79 +82,10 @@ pub fn init() -> Result<(), IommuError> {
|
|||||||
for table in PciDeviceLocation::all() {
|
for table in PciDeviceLocation::all() {
|
||||||
root_table.specify_device_page_table(table, page_table.clone())
|
root_table.specify_device_page_table(table, page_table.clone())
|
||||||
}
|
}
|
||||||
|
remapping::init(&root_table)?;
|
||||||
let paddr = root_table.paddr();
|
|
||||||
|
|
||||||
// write remapping register
|
|
||||||
remapping_reg.root_table_address.write(paddr as u64);
|
|
||||||
// start writing
|
|
||||||
remapping_reg.global_command.write(0x4000_0000);
|
|
||||||
// wait until complete
|
|
||||||
while remapping_reg.global_status.read() & 0x4000_0000 == 0 {}
|
|
||||||
|
|
||||||
// enable iommu
|
|
||||||
remapping_reg.global_command.write(0x8000_0000);
|
|
||||||
|
|
||||||
debug!("IOMMU registers:{:#x?}", remapping_reg);
|
|
||||||
|
|
||||||
PAGE_TABLE.call_once(|| Mutex::new(root_table));
|
PAGE_TABLE.call_once(|| Mutex::new(root_table));
|
||||||
|
info!("IOMMU enabled");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct RemappingRegisters {
|
|
||||||
version: Volatile<&'static u32, ReadOnly>,
|
|
||||||
capability: Volatile<&'static u64, ReadOnly>,
|
|
||||||
extended_capability: Volatile<&'static u64, ReadOnly>,
|
|
||||||
global_command: Volatile<&'static mut u32, WriteOnly>,
|
|
||||||
global_status: Volatile<&'static u32, ReadOnly>,
|
|
||||||
root_table_address: Volatile<&'static mut u64, ReadWrite>,
|
|
||||||
context_command: Volatile<&'static mut u64, ReadWrite>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RemappingRegisters {
|
|
||||||
/// Create a instance from base address
|
|
||||||
fn new() -> Option<Self> {
|
|
||||||
let dmar = Dmar::new()?;
|
|
||||||
let acpi_table_lock = ACPI_TABLES.get().unwrap().lock();
|
|
||||||
|
|
||||||
debug!("DMAR:{:#x?}", dmar);
|
|
||||||
let base_address = {
|
|
||||||
let mut addr = 0;
|
|
||||||
for remapping in dmar.remapping_iter() {
|
|
||||||
match remapping {
|
|
||||||
Remapping::Drhd(drhd) => addr = drhd.register_base_addr(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if addr == 0 {
|
|
||||||
panic!("There should be a DRHD structure in the DMAR table");
|
|
||||||
}
|
|
||||||
addr
|
|
||||||
};
|
|
||||||
|
|
||||||
let vaddr = paddr_to_vaddr(base_address as usize);
|
|
||||||
// Safety: All offsets and sizes are strictly adhered to in the manual, and the base address is obtained from Drhd.
|
|
||||||
unsafe {
|
|
||||||
let version = Volatile::new_read_only(&*(vaddr as *const u32));
|
|
||||||
let capability = Volatile::new_read_only(&*((vaddr + 0x08) as *const u64));
|
|
||||||
let extended_capability = Volatile::new_read_only(&*((vaddr + 0x10) as *const u64));
|
|
||||||
let global_command = Volatile::new_write_only(&mut *((vaddr + 0x18) as *mut u32));
|
|
||||||
let global_status = Volatile::new_read_only(&*((vaddr + 0x1C) as *const u32));
|
|
||||||
let root_table_address = Volatile::new(&mut *((vaddr + 0x20) as *mut u64));
|
|
||||||
let context_command = Volatile::new(&mut *((vaddr + 0x28) as *mut u64));
|
|
||||||
Some(Self {
|
|
||||||
version,
|
|
||||||
capability,
|
|
||||||
extended_capability,
|
|
||||||
global_command,
|
|
||||||
global_status,
|
|
||||||
root_table_address,
|
|
||||||
context_command,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PAGE_TABLE: Once<Mutex<RootTable>> = Once::new();
|
static PAGE_TABLE: Once<Mutex<RootTable>> = Once::new();
|
||||||
|
184
framework/jinux-frame/src/arch/x86/iommu/remapping.rs
Normal file
184
framework/jinux-frame/src/arch/x86/iommu/remapping.rs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
use bitflags::bitflags;
|
||||||
|
use log::debug;
|
||||||
|
use spin::Once;
|
||||||
|
use volatile::{
|
||||||
|
access::{ReadOnly, ReadWrite, WriteOnly},
|
||||||
|
Volatile,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::{
|
||||||
|
iommu::fault,
|
||||||
|
x86::kernel::acpi::{
|
||||||
|
dmar::{Dmar, Remapping},
|
||||||
|
ACPI_TABLES,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vm::paddr_to_vaddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{context_table::RootTable, IommuError};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RemappingRegisters {
|
||||||
|
version: Volatile<&'static u32, ReadOnly>,
|
||||||
|
capability: Volatile<&'static u64, ReadOnly>,
|
||||||
|
extended_capability: Volatile<&'static u64, ReadOnly>,
|
||||||
|
global_command: Volatile<&'static mut u32, WriteOnly>,
|
||||||
|
global_status: Volatile<&'static u32, ReadOnly>,
|
||||||
|
root_table_address: Volatile<&'static mut u64, ReadWrite>,
|
||||||
|
context_command: Volatile<&'static mut u64, ReadWrite>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemappingRegisters {
|
||||||
|
pub fn capability(&self) -> Capability {
|
||||||
|
Capability::from_bits_truncate(self.capability.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a instance from base address
|
||||||
|
fn new(root_table: &RootTable) -> Option<Self> {
|
||||||
|
let dmar = Dmar::new()?;
|
||||||
|
let acpi_table_lock = ACPI_TABLES.get().unwrap().lock();
|
||||||
|
|
||||||
|
debug!("DMAR:{:#x?}", dmar);
|
||||||
|
let base_address = {
|
||||||
|
let mut addr = 0;
|
||||||
|
for remapping in dmar.remapping_iter() {
|
||||||
|
match remapping {
|
||||||
|
Remapping::Drhd(drhd) => addr = drhd.register_base_addr(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if addr == 0 {
|
||||||
|
panic!("There should be a DRHD structure in the DMAR table");
|
||||||
|
}
|
||||||
|
addr
|
||||||
|
};
|
||||||
|
|
||||||
|
let vaddr: usize = paddr_to_vaddr(base_address as usize);
|
||||||
|
// Safety: All offsets and sizes are strictly adhered to in the manual, and the base address is obtained from Drhd.
|
||||||
|
let mut remapping_reg = unsafe {
|
||||||
|
fault::init(vaddr);
|
||||||
|
let version = Volatile::new_read_only(&*(vaddr as *const u32));
|
||||||
|
let capability = Volatile::new_read_only(&*((vaddr + 0x08) as *const u64));
|
||||||
|
let extended_capability: Volatile<&u64, ReadOnly> =
|
||||||
|
Volatile::new_read_only(&*((vaddr + 0x10) as *const u64));
|
||||||
|
let global_command = Volatile::new_write_only(&mut *((vaddr + 0x18) as *mut u32));
|
||||||
|
let global_status = Volatile::new_read_only(&*((vaddr + 0x1C) as *const u32));
|
||||||
|
let root_table_address = Volatile::new(&mut *((vaddr + 0x20) as *mut u64));
|
||||||
|
let context_command = Volatile::new(&mut *((vaddr + 0x28) as *mut u64));
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
capability,
|
||||||
|
extended_capability,
|
||||||
|
global_command,
|
||||||
|
global_status,
|
||||||
|
root_table_address,
|
||||||
|
context_command,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// write remapping register
|
||||||
|
remapping_reg
|
||||||
|
.root_table_address
|
||||||
|
.write(root_table.paddr() as u64);
|
||||||
|
// start writing
|
||||||
|
remapping_reg.global_command.write(0x4000_0000);
|
||||||
|
// wait until complete
|
||||||
|
while remapping_reg.global_status.read() & 0x4000_0000 == 0 {}
|
||||||
|
|
||||||
|
// enable iommu
|
||||||
|
remapping_reg.global_command.write(0x8000_0000);
|
||||||
|
|
||||||
|
debug!("IOMMU registers:{:#x?}", remapping_reg);
|
||||||
|
|
||||||
|
Some(remapping_reg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct Capability : u64{
|
||||||
|
/// Number of domain support.
|
||||||
|
///
|
||||||
|
/// ```norun
|
||||||
|
/// 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.
|
||||||
|
/// 3 => 10-bit domain-ids with support for up to 1024 domains.
|
||||||
|
/// 4 => 12-bit domain-ids with support for up to 4K domains.
|
||||||
|
/// 5 => 14-bit domain-ids with support for up to 16K domains.
|
||||||
|
/// 6 => 16-bit domain-ids with support for up to 64K domains.
|
||||||
|
/// 7 => Reserved.
|
||||||
|
/// ```
|
||||||
|
const ND = 0x7 << 0;
|
||||||
|
/// Required Write-Buffer Flushing.
|
||||||
|
const RWBF = 1 << 4;
|
||||||
|
/// Protected Low-Memory Region
|
||||||
|
const PLMR = 1 << 5;
|
||||||
|
/// Protected High-Memory Region
|
||||||
|
const PHMR = 1 << 6;
|
||||||
|
/// Caching Mode
|
||||||
|
const CM = 1 << 7;
|
||||||
|
/// 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)
|
||||||
|
/// ```
|
||||||
|
const SAGAW = 0x1F << 8;
|
||||||
|
/// Maximum Guest Address Width.
|
||||||
|
/// The maximum guest physical address width supported by second-stage translation in remapping hardware.
|
||||||
|
/// MGAW is computed as (N+1), where N is the valued reported in this field.
|
||||||
|
const MGAW = 0x3F << 16;
|
||||||
|
/// Zero Length Read. Whether the remapping hardware unit supports zero length
|
||||||
|
/// DMA read requests to write-only pages.
|
||||||
|
const ZLR = 1 << 22;
|
||||||
|
/// Fault-recording Register offset, specifies the offset of the first fault recording register
|
||||||
|
/// relative to the register base address of this remapping hardware unit.
|
||||||
|
///
|
||||||
|
/// If the register base address is X, and the value reported in this field
|
||||||
|
/// is Y, the address for the first fault recording register is calculated as X+(16*Y).
|
||||||
|
const FRO = 0x3FF << 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)
|
||||||
|
/// ```
|
||||||
|
const SSLPS = 0xF << 34;
|
||||||
|
/// Page Selective Invalidation. Whether hardware supports page-selective invalidation for IOTLB.
|
||||||
|
const PSI = 1 << 39;
|
||||||
|
/// Number of Fault-recording Registers. Number of fault recording registers is computed as N+1.
|
||||||
|
const NFR = 0xFF << 40;
|
||||||
|
/// Maximum Address Mask Value, indicates the maximum supported value for the
|
||||||
|
/// Address Mask (AM) field in the Invalidation Address register
|
||||||
|
/// (IVA_REG), and IOTLB Invalidation Descriptor (iotlb_inv_dsc) used
|
||||||
|
/// for invalidations of second-stage translation.
|
||||||
|
const MAMV = 0x3F << 48;
|
||||||
|
/// Write Draining.
|
||||||
|
const DWD = 1 << 54;
|
||||||
|
/// Read Draining.
|
||||||
|
const DRD = 1 << 55;
|
||||||
|
/// First Stage 1-GByte Page Support.
|
||||||
|
const FS1GP = 1 << 56;
|
||||||
|
/// Posted Interrupts Support.
|
||||||
|
const PI = 1 << 59;
|
||||||
|
/// First Stage 5-level Paging Support.
|
||||||
|
const FS5LP = 1 << 60;
|
||||||
|
/// Enhanced Command Support.
|
||||||
|
const ECMDS = 1 << 61;
|
||||||
|
/// Enhanced Set Interrupt Remap Table Pointer Support.
|
||||||
|
const ESIRTPS = 1 << 62;
|
||||||
|
/// Enhanced Set Root Table Pointer Support.
|
||||||
|
const ESRTPS = 1 << 63;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static REMAPPING_REGS: Once<RemappingRegisters> = Once::new();
|
||||||
|
|
||||||
|
pub(super) fn init(root_table: &RootTable) -> Result<(), IommuError> {
|
||||||
|
let remapping_regs = RemappingRegisters::new(root_table).ok_or(IommuError::NoIommu)?;
|
||||||
|
REMAPPING_REGS.call_once(|| remapping_regs);
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -33,11 +33,11 @@ pub(crate) fn after_all_init() {
|
|||||||
kernel::pic::enable();
|
kernel::pic::enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
timer::init();
|
||||||
match iommu::init() {
|
match iommu::init() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => warn!("IOMMU initialization error:{:?}", err),
|
Err(err) => warn!("IOMMU initialization error:{:?}", err),
|
||||||
}
|
}
|
||||||
timer::init();
|
|
||||||
// Some driver like serial may use PIC
|
// Some driver like serial may use PIC
|
||||||
kernel::pic::init();
|
kernel::pic::init();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user