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 } ;
1616use crate :: error:: { Error , Result } ;
1717use core:: convert:: TryFrom ;
1818use core:: fmt;
1919use core:: ptr;
2020
21+ use arrayvec:: ArrayVec ;
2122use spin:: Mutex ;
2223
2324const 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.
41110pub struct IoApic {
42111 /// 32-bit physical address to access this I/O APIC.
0 commit comments