diff --git a/aml/src/pci_routing.rs b/aml/src/pci_routing.rs index 7acf9264..75538122 100644 --- a/aml/src/pci_routing.rs +++ b/aml/src/pci_routing.rs @@ -1,6 +1,6 @@ use crate::{ namespace::AmlName, - resource::{self, InterruptPolarity, InterruptTrigger, Resource}, + resource::{self, InterruptPolarity, InterruptTrigger, Irq, Resource}, value::Args, AmlContext, AmlError, @@ -169,7 +169,7 @@ impl PciRoutingTable { polarity: InterruptPolarity::ActiveLow, is_shared: true, is_wake_capable: false, - irq: gsi, + irq: Irq::Single(gsi), }), PciRouteType::LinkObject(ref name) => { let path = AmlName::from_str("_CRS").unwrap().resolve(name)?; diff --git a/aml/src/resource.rs b/aml/src/resource.rs index abe907ae..11b5e824 100644 --- a/aml/src/resource.rs +++ b/aml/src/resource.rs @@ -317,6 +317,12 @@ fn address_space_descriptor(bytes: &[u8]) -> Result { })) } +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Irq { + Single(u32), + Multiple(Vec) +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct IrqDescriptor { pub is_consumer: bool, @@ -324,11 +330,7 @@ pub struct IrqDescriptor { pub polarity: InterruptPolarity, pub is_shared: bool, pub is_wake_capable: bool, - /* - * NOTE: We currently only support the cases where a descriptor only contains a single interrupt - * number. - */ - pub irq: u32, + pub irq: Irq, } fn irq_format_descriptor(bytes: &[u8]) -> Result { @@ -369,7 +371,7 @@ fn irq_format_descriptor(bytes: &[u8]) -> Result { let irq = LittleEndian::read_u16(&bytes[1..=2]); Ok(Resource::Irq(IrqDescriptor { - irq: irq as u32, + irq: Irq::Single(irq as u32), is_wake_capable: false, is_shared: false, polarity: InterruptPolarity::ActiveHigh, @@ -395,7 +397,7 @@ fn irq_format_descriptor(bytes: &[u8]) -> Result { }; Ok(Resource::Irq(IrqDescriptor { - irq: irq as u32, + irq: Irq::Single(irq as u32), is_wake_capable, is_shared, polarity, @@ -551,8 +553,25 @@ fn extended_interrupt_descriptor(bytes: &[u8]) -> Result { } let number_of_interrupts = bytes[4] as usize; - assert_eq!(number_of_interrupts, 1); - let irq = LittleEndian::read_u32(&[bytes[5], bytes[6], bytes[7], bytes[8]]); + + let irq = if number_of_interrupts == 1 { + let irq = LittleEndian::read_u32( &bytes[5..9]); + + Irq::Single(irq) + } else { + let mut irqs = Vec::with_capacity(number_of_interrupts); + + for i in 0..number_of_interrupts { + let start = 5 + i * size_of::(); + let end = start + 4; + + let irq = LittleEndian::read_u32(&bytes[start..end]); + + irqs.push(irq); + } + + Irq::Multiple(irqs) + }; Ok(Resource::Irq(IrqDescriptor { is_consumer: bytes[3].get_bit(0), @@ -625,7 +644,7 @@ mod tests { polarity: InterruptPolarity::ActiveHigh, is_shared: false, is_wake_capable: false, - irq: (1 << 1) + irq: Irq::Single(1 << 1) }) ]) ); @@ -836,7 +855,7 @@ mod tests { polarity: InterruptPolarity::ActiveHigh, is_shared: false, is_wake_capable: false, - irq: (1 << 6) + irq: Irq::Single(1 << 6) }), Resource::Dma(DMADescriptor { channel_mask: 1 << 2,