Skip to content

Commit 8a46c85

Browse files
committed
Add ioapic gsi remapping support
1 parent 5383af2 commit 8a46c85

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

mythril/src/ioapic.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
//! by converting a previously obtained I/O APIC Interrupt Controller
1313
//! Structure entry in the Multiple APIC Descriptor Table.
1414
15-
use crate::acpi::madt::Ics;
15+
use crate::acpi::madt::{Ics, MADT};
1616
use crate::error::{Error, Result};
1717
use core::convert::TryFrom;
1818
use core::fmt;
1919
use core::ptr;
2020

21+
use arrayvec::ArrayVec;
2122
use spin::Mutex;
2223

2324
const IOREDTBL_KNOWN_BITS_MASK: u64 = 0xff000000_0001ffff;
@@ -37,6 +38,74 @@ mod reg {
3738
pub const IOREDTBL_OFFSET: u8 = 0x10;
3839
}
3940

41+
const MAX_IOAPIC_COUNT: usize = 16;
42+
43+
// Interactions with individual IoApics are thread-safe, and this
44+
// vector is only initialized by the BSP, so no mutex is needed.
45+
// TODO(alschwalm): Remove the Option once ArrayVec::new is a const fn
46+
static mut IOAPICS: Option<ArrayVec<[IoApic; MAX_IOAPIC_COUNT]>> = None;
47+
48+
// Get the IoApic and redirection table entry index corresponding to a given GSI.
49+
// Returns None if there is no such IoApic
50+
// TODO(alschwalm): Support InterruptSourceOverride
51+
fn ioapic_for_gsi(gsi: u32) -> Option<(&'static mut IoApic, u8)> {
52+
for ioapic in unsafe { IOAPICS.as_mut().unwrap() }.iter_mut() {
53+
let entries = ioapic.max_redirection_entry() as u32;
54+
let base = ioapic.gsi_base;
55+
if gsi > base && gsi < base + entries {
56+
return Some((ioapic, (gsi - base) as u8));
57+
}
58+
}
59+
None
60+
}
61+
62+
/// Map a given GSI to an interrupt vector on the core with the associated apic_id
63+
pub fn map_gsi_vector(gsi: u32, vector: u8, apic_id: u8) -> Result<()> {
64+
match ioapic_for_gsi(gsi) {
65+
Some((ioapic, entry)) => {
66+
debug!(
67+
"Mapping gsi=0x{:x} to vector 0x{:x} on apic id = 0x{:x}",
68+
gsi, vector, apic_id
69+
);
70+
ioapic.write_ioredtbl(
71+
entry,
72+
IoRedTblEntry::new(
73+
vector,
74+
DeliveryMode::Fixed,
75+
DestinationMode::Physical,
76+
PinPolarity::ActiveHigh,
77+
TriggerMode::Edge,
78+
false,
79+
apic_id,
80+
)?,
81+
)?;
82+
Ok(())
83+
}
84+
None => Err(Error::NotFound),
85+
}
86+
}
87+
88+
/// Initialize the system I/O APICS
89+
///
90+
/// This function should only be called by the BSP
91+
pub unsafe fn init_ioapics(madt: &MADT) -> Result<()> {
92+
let mut ioapics = ArrayVec::new();
93+
for ioapic in madt.structures().filter_map(|ics| match ics {
94+
Ok(ioapic @ Ics::IoApic { .. }) => match IoApic::try_from(ioapic) {
95+
Ok(ioapic) => Some(ioapic),
96+
Err(e) => {
97+
warn!("Invalid IOAPIC in MADT: {:?}", e);
98+
None
99+
}
100+
},
101+
_ => None,
102+
}) {
103+
ioapics.push(ioapic);
104+
}
105+
IOAPICS = Some(ioapics);
106+
Ok(())
107+
}
108+
40109
/// The raw interface for the I/O APIC.
41110
pub struct IoApic {
42111
/// 32-bit physical address to access this I/O APIC.

0 commit comments

Comments
 (0)