mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Avoid Rust references of IRT entries
This commit is contained in:
parent
189daa2e09
commit
d4afe3a035
@ -2,23 +2,17 @@
|
|||||||
|
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use core::fmt::Debug;
|
||||||
use core::{fmt::Debug, mem::size_of};
|
|
||||||
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
pub(super) use table::IntRemappingTable;
|
pub(super) use table::IntRemappingTable;
|
||||||
use table::IrtEntry;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::arch::iommu::registers::{ExtendedCapabilityFlags, IOMMU_REGS};
|
||||||
arch::iommu::registers::{ExtendedCapabilityFlags, IOMMU_REGS},
|
|
||||||
prelude::Vaddr,
|
|
||||||
sync::{LocalIrqDisabled, SpinLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct IrtEntryHandle {
|
pub struct IrtEntryHandle {
|
||||||
index: u16,
|
index: u16,
|
||||||
entry_ref: Option<&'static mut IrtEntry>,
|
table: &'static IntRemappingTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrtEntryHandle {
|
impl IrtEntryHandle {
|
||||||
@ -26,32 +20,9 @@ impl IrtEntryHandle {
|
|||||||
self.index
|
self.index
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(unused)]
|
pub fn enable(&self, vector: u32) {
|
||||||
pub fn irt_entry(&self) -> Option<&IrtEntry> {
|
self.table
|
||||||
self.entry_ref.as_deref()
|
.set_entry(self.index, table::IrtEntry::new_enabled(vector));
|
||||||
}
|
|
||||||
|
|
||||||
pub fn irt_entry_mut(&mut self) -> Option<&mut IrtEntry> {
|
|
||||||
self.entry_ref.as_deref_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set entry reference to None.
|
|
||||||
pub(self) fn set_none(&mut self) {
|
|
||||||
self.entry_ref = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a handle based on index and the interrupt remapping table base virtual address.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// User must ensure the target address is **always** valid and point to `IrtEntry`.
|
|
||||||
pub(self) unsafe fn new(table_vaddr: Vaddr, index: u16) -> Self {
|
|
||||||
Self {
|
|
||||||
index,
|
|
||||||
entry_ref: Some(
|
|
||||||
&mut *((table_vaddr + index as usize * size_of::<IrtEntry>()) as *mut IrtEntry),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +30,7 @@ impl Debug for IrtEntryHandle {
|
|||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("IrtEntryHandle")
|
f.debug_struct("IrtEntryHandle")
|
||||||
.field("index", &self.index)
|
.field("index", &self.index)
|
||||||
.field("entry_ref", &self.entry_ref)
|
.finish_non_exhaustive()
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +38,7 @@ pub fn has_interrupt_remapping() -> bool {
|
|||||||
REMAPPING_TABLE.get().is_some()
|
REMAPPING_TABLE.get().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc_irt_entry() -> Option<Arc<SpinLock<IrtEntryHandle, LocalIrqDisabled>>> {
|
pub fn alloc_irt_entry() -> Option<IrtEntryHandle> {
|
||||||
let page_table = REMAPPING_TABLE.get()?;
|
let page_table = REMAPPING_TABLE.get()?;
|
||||||
page_table.alloc()
|
page_table.alloc()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
|
||||||
use core::{fmt::Debug, mem::size_of};
|
use core::{fmt::Debug, mem::size_of};
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
@ -9,7 +8,7 @@ use int_to_c_enum::TryFromInt;
|
|||||||
|
|
||||||
use super::IrtEntryHandle;
|
use super::IrtEntryHandle;
|
||||||
use crate::{
|
use crate::{
|
||||||
mm::{paddr_to_vaddr, FrameAllocOptions, Segment, PAGE_SIZE},
|
mm::{FrameAllocOptions, Segment, UntypedMem, PAGE_SIZE},
|
||||||
sync::{LocalIrqDisabled, SpinLock},
|
sync::{LocalIrqDisabled, SpinLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,80 +19,97 @@ enum ExtendedInterruptMode {
|
|||||||
X2Apic,
|
X2Apic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct IntRemappingMeta;
|
||||||
|
crate::impl_untyped_frame_meta_for!(IntRemappingMeta);
|
||||||
|
|
||||||
pub struct IntRemappingTable {
|
pub struct IntRemappingTable {
|
||||||
size: u16,
|
num_entries: u16,
|
||||||
extended_interrupt_mode: ExtendedInterruptMode,
|
extended_interrupt_mode: ExtendedInterruptMode,
|
||||||
frames: Segment<()>,
|
segment: Segment<IntRemappingMeta>,
|
||||||
/// The global allocator for Interrupt remapping entry.
|
/// A lock that prevents concurrent modification of entries.
|
||||||
|
modification_lock: SpinLock<(), LocalIrqDisabled>,
|
||||||
|
/// An allocator that allocates indexes to unused entries.
|
||||||
allocator: SpinLock<IdAlloc, LocalIrqDisabled>,
|
allocator: SpinLock<IdAlloc, LocalIrqDisabled>,
|
||||||
handles: Vec<Arc<SpinLock<IrtEntryHandle, LocalIrqDisabled>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntRemappingTable {
|
impl IntRemappingTable {
|
||||||
pub fn alloc(&self) -> Option<Arc<SpinLock<IrtEntryHandle, LocalIrqDisabled>>> {
|
pub fn alloc(&'static self) -> Option<IrtEntryHandle> {
|
||||||
let id = self.allocator.lock().alloc()?;
|
let index = self.allocator.lock().alloc()?;
|
||||||
Some(self.handles.get(id).unwrap().clone())
|
Some(IrtEntryHandle {
|
||||||
|
index: index as u16,
|
||||||
|
table: self,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an Interrupt Remapping Table with one `Segment` (default).
|
/// Creates an Interrupt Remapping Table with one page.
|
||||||
pub(super) fn new() -> Self {
|
pub(super) fn new() -> Self {
|
||||||
const DEFAULT_PAGES: usize = 1;
|
const NUM_PAGES: usize = 1;
|
||||||
let segment = FrameAllocOptions::new()
|
|
||||||
.alloc_segment(DEFAULT_PAGES)
|
|
||||||
.unwrap();
|
|
||||||
let entry_number = (DEFAULT_PAGES * PAGE_SIZE / size_of::<u128>()) as u16;
|
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let segment = FrameAllocOptions::new()
|
||||||
let base_vaddr = paddr_to_vaddr(segment.start_paddr());
|
.alloc_segment_with(NUM_PAGES, |_| IntRemappingMeta)
|
||||||
for index in 0..entry_number {
|
.unwrap();
|
||||||
// SAFETY: The IrtEntry reference will always valid and will disabled when IntRemappingTable is dropped.
|
let num_entries = (NUM_PAGES * PAGE_SIZE / size_of::<u128>())
|
||||||
let handle = unsafe { IrtEntryHandle::new(base_vaddr, index) };
|
.try_into()
|
||||||
handles.push(Arc::new(SpinLock::new(handle)));
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
size: entry_number,
|
num_entries,
|
||||||
extended_interrupt_mode: ExtendedInterruptMode::X2Apic,
|
extended_interrupt_mode: ExtendedInterruptMode::X2Apic,
|
||||||
frames: segment,
|
segment,
|
||||||
allocator: SpinLock::new(IdAlloc::with_capacity(entry_number as usize)),
|
modification_lock: SpinLock::new(()),
|
||||||
handles,
|
allocator: SpinLock::new(IdAlloc::with_capacity(num_entries as usize)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the entry in the Interrupt Remapping Table.
|
||||||
|
pub(super) fn set_entry(&self, index: u16, entry: IrtEntry) {
|
||||||
|
let _guard = self.modification_lock.lock();
|
||||||
|
|
||||||
|
let [lower, upper] = entry.as_raw_u64();
|
||||||
|
|
||||||
|
let offset = (index as usize) * size_of::<u128>();
|
||||||
|
// Write a zero as the lower bits first to clear the present bit.
|
||||||
|
self.segment
|
||||||
|
.writer()
|
||||||
|
.skip(offset)
|
||||||
|
.write_once(&0u64)
|
||||||
|
.unwrap();
|
||||||
|
// Write the upper bits first (which keeps the present bit unset)
|
||||||
|
self.segment
|
||||||
|
.writer()
|
||||||
|
.skip(offset + size_of::<u64>())
|
||||||
|
.write_once(&upper)
|
||||||
|
.unwrap();
|
||||||
|
self.segment
|
||||||
|
.writer()
|
||||||
|
.skip(offset)
|
||||||
|
.write_once(&lower)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/// Encodes the value written into the Interrupt Remapping Table Register.
|
/// Encodes the value written into the Interrupt Remapping Table Register.
|
||||||
pub(crate) fn encode(&self) -> u64 {
|
pub(crate) fn encode(&self) -> u64 {
|
||||||
let mut encoded = self.frames.start_paddr() as u64;
|
let mut encoded = self.segment.start_paddr() as u64;
|
||||||
|
|
||||||
match self.extended_interrupt_mode {
|
// Bit Range 11 - Extended Interrupt Mode Enable (EIME)
|
||||||
ExtendedInterruptMode::XApic => {}
|
encoded |= match self.extended_interrupt_mode {
|
||||||
ExtendedInterruptMode::X2Apic => encoded |= 1 << 11,
|
ExtendedInterruptMode::XApic => 0,
|
||||||
}
|
ExtendedInterruptMode::X2Apic => 1 << 11,
|
||||||
|
};
|
||||||
|
|
||||||
// entry_number = 2^(size+1)
|
// Bit Range 3:0 - Size (S)
|
||||||
if self.size == 1 {
|
encoded |= {
|
||||||
panic!("Wrong entry number");
|
assert!(self.num_entries.is_power_of_two());
|
||||||
}
|
// num_entries = 2^(size+1)
|
||||||
let mut size = 0;
|
let size = self.num_entries.trailing_zeros().checked_sub(1).unwrap();
|
||||||
let mut tmp = self.size >> 1;
|
assert!(size <= 15);
|
||||||
while (tmp & 0b1) == 0 {
|
size as u64
|
||||||
tmp >>= 1;
|
};
|
||||||
size += 1;
|
|
||||||
}
|
|
||||||
encoded += size;
|
|
||||||
|
|
||||||
encoded
|
encoded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for IntRemappingTable {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
for handle in self.handles.iter_mut() {
|
|
||||||
let mut handle = handle.lock();
|
|
||||||
handle.set_none();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type of validation that must be performed by the interrupt-remapping hardware.
|
/// The type of validation that must be performed by the interrupt-remapping hardware.
|
||||||
#[derive(Debug, TryFromInt)]
|
#[derive(Debug, TryFromInt)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
@ -146,20 +162,15 @@ enum DeliveryMode {
|
|||||||
pub struct IrtEntry(u128);
|
pub struct IrtEntry(u128);
|
||||||
|
|
||||||
impl IrtEntry {
|
impl IrtEntry {
|
||||||
#[expect(unused)]
|
/// Creates an enabled entry with no validation,
|
||||||
pub const fn new(value: u128) -> Self {
|
///
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[expect(unused)]
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0 = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables this entry with no validation,
|
|
||||||
/// DST = 0, IM = 0, DLM = 0, TM = 0, RH = 0, DM = 0, FPD = 1, P = 1
|
/// DST = 0, IM = 0, DLM = 0, TM = 0, RH = 0, DM = 0, FPD = 1, P = 1
|
||||||
pub fn enable_default(&mut self, vector: u32) {
|
pub(super) fn new_enabled(vector: u32) -> Self {
|
||||||
self.0 = 0b11 | ((vector as u128) << 16);
|
Self(0b11 | ((vector as u128) << 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_raw_u64(&self) -> [u64; 2] {
|
||||||
|
[self.0 as u64, (self.0 >> 64) as u64]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_validation_type(&self) -> SourceValidationType {
|
pub fn source_validation_type(&self) -> SourceValidationType {
|
||||||
|
@ -13,7 +13,7 @@ use x86_64::registers::rflags::{self, RFlags};
|
|||||||
use super::iommu::{alloc_irt_entry, has_interrupt_remapping, IrtEntryHandle};
|
use super::iommu::{alloc_irt_entry, has_interrupt_remapping, IrtEntryHandle};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::PinCurrentCpu,
|
cpu::PinCurrentCpu,
|
||||||
sync::{LocalIrqDisabled, Mutex, PreemptDisabled, RwLock, RwLockReadGuard, SpinLock},
|
sync::{Mutex, PreemptDisabled, RwLock, RwLockReadGuard, SpinLock},
|
||||||
trap::TrapFrame,
|
trap::TrapFrame,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ impl Debug for CallbackElement {
|
|||||||
pub(crate) struct IrqLine {
|
pub(crate) struct IrqLine {
|
||||||
pub(crate) irq_num: u8,
|
pub(crate) irq_num: u8,
|
||||||
pub(crate) callback_list: RwLock<Vec<CallbackElement>>,
|
pub(crate) callback_list: RwLock<Vec<CallbackElement>>,
|
||||||
bind_remapping_entry: Once<Arc<SpinLock<IrtEntryHandle, LocalIrqDisabled>>>,
|
bind_remapping_entry: Once<IrtEntryHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqLine {
|
impl IrqLine {
|
||||||
@ -105,11 +105,7 @@ impl IrqLine {
|
|||||||
let handle = alloc_irt_entry();
|
let handle = alloc_irt_entry();
|
||||||
if let Some(handle) = handle {
|
if let Some(handle) = handle {
|
||||||
// Enable the IRT entry
|
// Enable the IRT entry
|
||||||
handle
|
handle.enable(irq_num as u32);
|
||||||
.lock()
|
|
||||||
.irt_entry_mut()
|
|
||||||
.unwrap()
|
|
||||||
.enable_default(irq_num as u32);
|
|
||||||
irq.bind_remapping_entry.call_once(|| handle);
|
irq.bind_remapping_entry.call_once(|| handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +117,7 @@ impl IrqLine {
|
|||||||
/// This method will return `None` if interrupt remapping is disabled or
|
/// This method will return `None` if interrupt remapping is disabled or
|
||||||
/// not supported by the architecture.
|
/// not supported by the architecture.
|
||||||
pub fn remapping_index(&self) -> Option<u16> {
|
pub fn remapping_index(&self) -> Option<u16> {
|
||||||
Some(self.bind_remapping_entry.get()?.lock().index())
|
Some(self.bind_remapping_entry.get()?.index())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the IRQ number.
|
/// Gets the IRQ number.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user