Skip to main content

rdrive/probe/
acpi.rs

1use alloc::{
2    collections::{BTreeMap, BTreeSet},
3    format,
4    rc::Rc,
5    string::{String, ToString},
6    vec::Vec,
7};
8use core::{ptr::NonNull, str::FromStr};
9
10use acpi::{
11    AcpiError, AcpiTables, Handler, PhysicalMapping,
12    address::{AddressSpace, GenericAddress},
13    aml::{
14        AmlError, Interpreter,
15        namespace::{AmlName, NamespaceLevelKind},
16        object::{FieldUnit, FieldUnitKind, FieldUpdateRule, Object, ObjectType},
17        op_region::{OpRegion, RegionSpace},
18        pci_routing::{IrqDescriptor, PciRoutingTable, Pin},
19        resource::{
20            AddressSpaceResourceType, InterruptPolarity, InterruptTrigger, Resource,
21            resource_descriptor_list,
22        },
23    },
24    platform::{
25        AcpiPlatform,
26        interrupt::{InterruptModel, Polarity, TriggerMode},
27        pci::PciConfigRegions,
28    },
29    sdt::spcr::{Spcr, SpcrInterfaceType},
30};
31use ax_kspin::SpinNoPreempt as Mutex;
32pub use rdif_base::irq::{AcpiGsiController, AcpiGsiRoute, AcpiIrqPolarity, AcpiIrqTrigger};
33use spin::Once;
34
35use crate::{
36    DeviceId, PlatformDevice,
37    error::DriverError,
38    probe::{
39        OnProbeError, ProbeError,
40        pci::{PciAddress, PciInfo, PciIntxRoute},
41    },
42    register::{DriverRegister, ProbeKind},
43};
44
45pub const PCI_INTX_VECTOR_BASE: usize = 0x30;
46const LOONGARCH_PCH_PIC_GSI_COUNT: u16 = 256;
47const PCI_ROOT_FALLBACK_PATHS: &[&str] = &["\\_SB.PCI0", "\\_SB.PCI1", "\\_SB.PC00", "\\_SB.PC01"];
48
49static SYSTEM: Once<System> = Once::new();
50static NULL_LOCK: Mutex<()> = Mutex::new(());
51
52#[derive(Clone, Copy)]
53pub struct AcpiRoot {
54    pub rsdp: usize,
55    pub phys_to_virt: fn(usize) -> *mut u8,
56}
57
58impl core::fmt::Debug for AcpiRoot {
59    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60        f.debug_struct("AcpiRoot")
61            .field("rsdp", &self.rsdp)
62            .finish_non_exhaustive()
63    }
64}
65
66impl AcpiRoot {
67    pub const fn new(rsdp: usize, phys_to_virt: fn(usize) -> *mut u8) -> Self {
68        Self { rsdp, phys_to_virt }
69    }
70
71    pub const fn identity(rsdp: usize) -> Self {
72        Self::new(rsdp, identity_phys_to_virt)
73    }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct AcpiId {
78    pub hid: &'static str,
79    pub cids: &'static [&'static str],
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub struct AcpiPciEcam {
84    pub segment_group: u16,
85    pub bus_start: u8,
86    pub bus_end: u8,
87    pub base_address: u64,
88}
89
90impl AcpiPciEcam {
91    pub fn size(&self) -> usize {
92        let buses = usize::from(self.bus_end.saturating_sub(self.bus_start)) + 1;
93        buses << 20
94    }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct AcpiIoApic {
99    pub id: u8,
100    pub address: u32,
101    pub gsi_base: u32,
102    pub redirection_entries: u8,
103}
104
105impl AcpiIoApic {
106    fn gsi_source(self) -> AcpiGsiSource {
107        AcpiGsiSource {
108            controller: AcpiGsiController::IoApic,
109            controller_id: u16::from(self.id),
110            controller_address: u64::from(self.address),
111            gsi_base: self.gsi_base,
112            gsi_count: u16::from(self.redirection_entries),
113        }
114    }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct AcpiPchPic {
119    pub id: u16,
120    pub address: u64,
121    pub mmio_size: u16,
122    pub gsi_count: u16,
123    pub gsi_base: u32,
124}
125
126impl AcpiPchPic {
127    fn gsi_source(self) -> AcpiGsiSource {
128        AcpiGsiSource {
129            controller: AcpiGsiController::PchPic,
130            controller_id: self.id,
131            controller_address: self.address,
132            gsi_base: self.gsi_base,
133            gsi_count: self.gsi_count,
134        }
135    }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139struct AcpiGsiSource {
140    controller: AcpiGsiController,
141    controller_id: u16,
142    controller_address: u64,
143    gsi_base: u32,
144    gsi_count: u16,
145}
146
147impl AcpiGsiSource {
148    fn contains_gsi(self, gsi: u32) -> bool {
149        let start = self.gsi_base;
150        let end = start.saturating_add(u32::from(self.gsi_count));
151        (start..end).contains(&gsi)
152    }
153
154    fn route(
155        self,
156        gsi: u32,
157        trigger: AcpiIrqTrigger,
158        polarity: AcpiIrqPolarity,
159    ) -> Option<AcpiGsiRoute> {
160        let controller_input = u8::try_from(gsi.checked_sub(self.gsi_base)?).ok()?;
161        Some(AcpiGsiRoute {
162            gsi,
163            vector: PCI_INTX_VECTOR_BASE + gsi as usize,
164            controller: self.controller,
165            controller_id: self.controller_id,
166            controller_address: self.controller_address,
167            controller_input,
168            trigger,
169            polarity,
170        })
171    }
172}
173
174#[derive(Debug, Clone)]
175pub struct AcpiRouting {
176    io_apics: Vec<AcpiIoApic>,
177    pch_pics: Vec<AcpiPchPic>,
178    isa_overrides: Vec<AcpiIsaIrqOverride>,
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub struct AcpiIsaIrqOverride {
183    pub source: u8,
184    pub gsi: u32,
185    pub trigger: AcpiIrqTrigger,
186    pub polarity: AcpiIrqPolarity,
187}
188
189impl AcpiRouting {
190    pub const fn new() -> Self {
191        Self {
192            io_apics: Vec::new(),
193            pch_pics: Vec::new(),
194            isa_overrides: Vec::new(),
195        }
196    }
197
198    pub fn add_io_apic(&mut self, io_apic: AcpiIoApic) {
199        self.io_apics.push(io_apic);
200    }
201
202    pub fn io_apics(&self) -> &[AcpiIoApic] {
203        &self.io_apics
204    }
205
206    pub fn add_pch_pic(&mut self, pch_pic: AcpiPchPic) {
207        self.pch_pics.push(pch_pic);
208    }
209
210    pub fn pch_pics(&self) -> &[AcpiPchPic] {
211        &self.pch_pics
212    }
213
214    pub fn add_isa_irq_override(&mut self, irq_override: AcpiIsaIrqOverride) {
215        self.isa_overrides.push(irq_override);
216    }
217
218    pub fn resolve_gsi(&self, gsi: u32) -> Option<AcpiGsiRoute> {
219        self.gsi_sources()
220            .find(|source| source.contains_gsi(gsi))?
221            .route(gsi, self.default_trigger(gsi), self.default_polarity(gsi))
222    }
223
224    fn gsi_sources(&self) -> impl Iterator<Item = AcpiGsiSource> + '_ {
225        self.io_apics
226            .iter()
227            .copied()
228            .map(AcpiIoApic::gsi_source)
229            .chain(self.pch_pics.iter().copied().map(AcpiPchPic::gsi_source))
230    }
231
232    pub fn resolve_vector(&self, vector: usize) -> Option<AcpiGsiRoute> {
233        let gsi = vector.checked_sub(PCI_INTX_VECTOR_BASE)?;
234        self.resolve_gsi(gsi as u32)
235    }
236
237    fn default_trigger(&self, gsi: u32) -> AcpiIrqTrigger {
238        self.isa_overrides
239            .iter()
240            .find(|irq_override| irq_override.gsi == gsi)
241            .map(|irq_override| irq_override.trigger)
242            .unwrap_or(if gsi < 16 {
243                AcpiIrqTrigger::Edge
244            } else {
245                AcpiIrqTrigger::Level
246            })
247    }
248
249    fn default_polarity(&self, gsi: u32) -> AcpiIrqPolarity {
250        self.isa_overrides
251            .iter()
252            .find(|irq_override| irq_override.gsi == gsi)
253            .map(|irq_override| irq_override.polarity)
254            .unwrap_or(if gsi < 16 {
255                AcpiIrqPolarity::ActiveHigh
256            } else {
257                AcpiIrqPolarity::ActiveLow
258            })
259    }
260}
261
262impl Default for AcpiRouting {
263    fn default() -> Self {
264        Self::new()
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use alloc::{
271        string::{String, ToString},
272        sync::Arc,
273        vec::Vec,
274    };
275    use core::str::FromStr;
276
277    use acpi::{
278        address::{AddressSpace, GenericAddress},
279        aml::{
280            Interpreter,
281            namespace::{AmlName, NamespaceLevelKind},
282            object::Object,
283            pci_routing::IrqDescriptor,
284            resource::{InterruptPolarity, InterruptTrigger},
285        },
286        registers::{FixedRegisters, Pm1ControlRegisterBlock, Pm1EventRegisterBlock},
287    };
288
289    use super::{
290        AcpiGsiController, AcpiHandler, AcpiId, AcpiIoApic, AcpiIrqPolarity, AcpiIrqTrigger,
291        AcpiIsaIrqOverride, AcpiPchPic, AcpiResourceRange, AcpiRoot, AcpiRouting, LinkIrqResource,
292        LinkIrqResourceKind, Mutex, PciLinkAllocator, System, irq_descriptor_gsi,
293        is_buffer_field_to_field_unit_store_gap, pci_irq_descriptor_gsi,
294        pci_link_irq_field_candidates, route_with_irq_descriptor_flags, select_pci_link_irq,
295    };
296    use crate::register::{DriverRegister, ProbeKind, ProbeLevel, ProbePriority};
297
298    fn test_fixed_registers(handler: &AcpiHandler) -> Arc<FixedRegisters<AcpiHandler>> {
299        let event_gas = GenericAddress {
300            address_space: AddressSpace::SystemIo,
301            bit_width: 32,
302            bit_offset: 0,
303            access_size: 3,
304            address: 0x1000,
305        };
306        let control_gas = GenericAddress {
307            address_space: AddressSpace::SystemIo,
308            bit_width: 16,
309            bit_offset: 0,
310            access_size: 2,
311            address: 0x1004,
312        };
313        Arc::new(FixedRegisters {
314            pm1_event_registers: Pm1EventRegisterBlock {
315                pm1_event_length: 4,
316                pm1a: unsafe { acpi::address::MappedGas::map_gas(event_gas, handler).unwrap() },
317                pm1b: None,
318            },
319            pm1_control_registers: Pm1ControlRegisterBlock {
320                pm1a: unsafe { acpi::address::MappedGas::map_gas(control_gas, handler).unwrap() },
321                pm1b: None,
322            },
323        })
324    }
325
326    fn interpreter_with_devices(handler: AcpiHandler) -> Interpreter<AcpiHandler> {
327        let interpreter =
328            Interpreter::new(handler.clone(), 2, test_fixed_registers(&handler), None);
329        {
330            let mut namespace = interpreter.namespace.lock();
331            let pnp = AmlName::from_str("\\_SB.RTC0").unwrap();
332            namespace
333                .add_level(pnp.clone(), NamespaceLevelKind::Device)
334                .unwrap();
335            namespace
336                .insert(
337                    AmlName::from_str("_HID").unwrap().resolve(&pnp).unwrap(),
338                    Object::Integer(0x000b_d041).wrap(),
339                )
340                .unwrap();
341            namespace
342                .insert(
343                    AmlName::from_str("_CRS").unwrap().resolve(&pnp).unwrap(),
344                    Object::Buffer(Vec::from([
345                        0x47, 0x01, 0x70, 0x00, 0x70, 0x00, 0x01, 0x08, 0x22, 0x00, 0x01, 0x79,
346                        0x00,
347                    ]))
348                    .wrap(),
349                )
350                .unwrap();
351
352            let loon = AmlName::from_str("\\_SB.LRTC").unwrap();
353            namespace
354                .add_level(loon.clone(), NamespaceLevelKind::Device)
355                .unwrap();
356            namespace
357                .insert(
358                    AmlName::from_str("_HID").unwrap().resolve(&loon).unwrap(),
359                    Object::String(String::from("LOON0001")).wrap(),
360                )
361                .unwrap();
362            namespace
363                .insert(
364                    AmlName::from_str("_CRS").unwrap().resolve(&loon).unwrap(),
365                    Object::Buffer(Vec::from([
366                        0x86, 0x09, 0x00, 0x01, 0x00, 0x01, 0x0d, 0x10, 0x00, 0x01, 0x00, 0x00,
367                        0x79, 0x00,
368                    ]))
369                    .wrap(),
370                )
371                .unwrap();
372        }
373        interpreter
374    }
375
376    fn test_system() -> System {
377        let handler = AcpiHandler::new(AcpiRoot::identity(0x1000), Vec::new());
378        let mut routing = AcpiRouting::new();
379        routing.add_io_apic(AcpiIoApic {
380            id: 0,
381            address: 0xfec0_0000,
382            gsi_base: 0,
383            redirection_entries: 24,
384        });
385        System {
386            ecam_regions: Vec::new(),
387            routing,
388            interpreter: interpreter_with_devices(handler.clone()),
389            handler,
390            pci: None,
391            probed_names: Mutex::new(alloc::collections::BTreeSet::new()),
392            populated_paths: Mutex::new(alloc::collections::BTreeMap::new()),
393            populated_resources: Mutex::new(alloc::collections::BTreeMap::new()),
394        }
395    }
396
397    static LAST_PATH: Mutex<Option<String>> = Mutex::new(None);
398
399    fn probe_rtc(probe: super::ProbeAcpi<'_>) -> Result<(), crate::probe::OnProbeError> {
400        let info = probe.info();
401        assert_eq!(info.hid(), Some("PNP0B00"));
402        assert_eq!(
403            info.io_ranges(),
404            &[AcpiResourceRange {
405                base: 0x70,
406                size: 8,
407            }]
408        );
409        assert_eq!(
410            info.irq_routes()
411                .iter()
412                .map(|route| route.gsi)
413                .collect::<Vec<_>>(),
414            Vec::from([8])
415        );
416        *LAST_PATH.lock() = Some(info.path.to_string());
417        Ok(())
418    }
419
420    static RTC_REGISTER: DriverRegister = DriverRegister {
421        name: "test acpi rtc",
422        level: ProbeLevel::PostKernel,
423        priority: ProbePriority::DEFAULT,
424        probe_kinds: &[ProbeKind::Acpi {
425            ids: &[AcpiId {
426                hid: "PNP0B00",
427                cids: &[],
428            }],
429            on_probe: probe_rtc,
430        }],
431    };
432
433    #[test]
434    fn acpi_probe_matches_namespace_device_and_exposes_io_and_irq_resources() {
435        let system = test_system();
436
437        let results = system.probe_register(&RTC_REGISTER).unwrap();
438
439        assert_eq!(results.len(), 1);
440        assert!(results.into_iter().all(|result| result.is_ok()));
441        assert_eq!(LAST_PATH.lock().as_deref(), Some("\\_SB_.RTC0"));
442    }
443
444    #[test]
445    fn acpi_info_exposes_loongson_memory_resource() {
446        let system = test_system();
447        let info = system
448            .device_infos_for_ids(&[AcpiId {
449                hid: "LOON0001",
450                cids: &[],
451            }])
452            .unwrap()
453            .into_iter()
454            .next()
455            .expect("LOON0001 device should be discovered");
456
457        assert_eq!(info.hid.as_deref(), Some("LOON0001"));
458        assert_eq!(
459            info.memory_ranges.as_slice(),
460            &[AcpiResourceRange {
461                base: 0x100d_0100,
462                size: 0x100,
463            }]
464        );
465    }
466
467    #[test]
468    fn acpi_eisa_integer_ids_decode_to_hid_strings() {
469        assert_eq!(
470            super::decode_eisa_id(0x000b_d041).as_deref(),
471            Some("PNP0B00")
472        );
473        assert_eq!(
474            super::decode_eisa_id(0x030a_d041).as_deref(),
475            Some("PNP0A03")
476        );
477        assert_eq!(
478            super::decode_eisa_id(0x080a_d041).as_deref(),
479            Some("PNP0A08")
480        );
481    }
482
483    #[test]
484    fn ioapic_routes_map_gsi_to_stable_vector() {
485        let mut routing = AcpiRouting::new();
486        routing.add_io_apic(AcpiIoApic {
487            id: 0,
488            address: 0xfec0_0000,
489            gsi_base: 0,
490            redirection_entries: 24,
491        });
492
493        let legacy_irq = routing
494            .resolve_gsi(4)
495            .expect("legacy ISA GSI 4 should be handled by the IOAPIC");
496        assert_eq!(legacy_irq.vector, 0x34);
497        assert_eq!(legacy_irq.controller_input, 4);
498        assert_eq!(legacy_irq.trigger, AcpiIrqTrigger::Edge);
499        assert_eq!(legacy_irq.polarity, AcpiIrqPolarity::ActiveHigh);
500
501        let irq = routing
502            .resolve_gsi(16)
503            .expect("gsi 16 should be handled by the IOAPIC");
504        assert_eq!(irq.gsi, 16);
505        assert_eq!(irq.controller, AcpiGsiController::IoApic);
506        assert_eq!(irq.controller_id, 0);
507        assert_eq!(irq.controller_address, 0xfec0_0000);
508        assert_eq!(irq.controller_input, 16);
509        assert_eq!(irq.vector, 0x40);
510        assert_eq!(irq.trigger, AcpiIrqTrigger::Level);
511        assert_eq!(irq.polarity, AcpiIrqPolarity::ActiveLow);
512        assert!(routing.resolve_gsi(24).is_none());
513    }
514
515    #[test]
516    fn pci_link_irq_can_route_to_legacy_ioapic_gsi() {
517        let mut routing = AcpiRouting::new();
518        routing.add_io_apic(AcpiIoApic {
519            id: 0,
520            address: 0xfec0_0000,
521            gsi_base: 0,
522            redirection_entries: 24,
523        });
524
525        let descriptor = IrqDescriptor {
526            is_consumer: false,
527            trigger: InterruptTrigger::Level,
528            polarity: InterruptPolarity::ActiveLow,
529            is_shared: true,
530            is_wake_capable: false,
531            irq: 1 << 10,
532        };
533        let gsi = irq_descriptor_gsi(&descriptor).unwrap();
534
535        assert_eq!(gsi, 10);
536        let route = routing
537            .resolve_gsi(gsi)
538            .expect("IOAPIC routes the legacy GSI from the ACPI PCI link");
539        assert_eq!(route.gsi, 10);
540        assert_eq!(route.controller_input, 10);
541    }
542
543    #[test]
544    fn pci_link_descriptor_reports_selected_power_of_two_gsi_directly() {
545        let resource = LinkIrqResource {
546            kind: LinkIrqResourceKind::SmallIrq,
547            descriptor: IrqDescriptor {
548                is_consumer: false,
549                trigger: InterruptTrigger::Level,
550                polarity: InterruptPolarity::ActiveLow,
551                is_shared: true,
552                is_wake_capable: false,
553                irq: 1 << 4,
554            },
555            irqs: alloc::vec![4],
556        };
557
558        let descriptor = resource.descriptor_for_irq(4);
559        assert_eq!(descriptor.irq, 4);
560        assert_eq!(pci_irq_descriptor_gsi(&descriptor), Some(4));
561    }
562
563    #[test]
564    fn pch_pic_routes_map_acpi_gsi_to_controller_input() {
565        let mut routing = AcpiRouting::new();
566        routing.add_pch_pic(AcpiPchPic {
567            id: 1,
568            address: 0x1000_0000,
569            mmio_size: 0x1000,
570            gsi_count: 64,
571            gsi_base: 64,
572        });
573
574        let route = routing
575            .resolve_gsi(82)
576            .expect("GSI 82 should be covered by the PCH-PIC");
577        assert_eq!(route.controller, AcpiGsiController::PchPic);
578        assert_eq!(route.controller_id, 1);
579        assert_eq!(route.controller_address, 0x1000_0000);
580        assert_eq!(route.controller_input, 18);
581        assert_eq!(route.vector, 0x30 + 82);
582        assert!(routing.resolve_gsi(128).is_none());
583    }
584
585    #[test]
586    fn ioapic_routes_apply_isa_interrupt_source_overrides() {
587        let mut routing = AcpiRouting::new();
588        routing.add_io_apic(AcpiIoApic {
589            id: 0,
590            address: 0xfec0_0000,
591            gsi_base: 0,
592            redirection_entries: 24,
593        });
594        routing.add_isa_irq_override(AcpiIsaIrqOverride {
595            source: 0,
596            gsi: 2,
597            trigger: AcpiIrqTrigger::Level,
598            polarity: AcpiIrqPolarity::ActiveLow,
599        });
600
601        let route = routing
602            .resolve_gsi(2)
603            .expect("overridden ISA GSI should still route through the IOAPIC");
604        assert_eq!(route.vector, 0x32);
605        assert_eq!(route.controller_input, 2);
606        assert_eq!(route.trigger, AcpiIrqTrigger::Level);
607        assert_eq!(route.polarity, AcpiIrqPolarity::ActiveLow);
608    }
609
610    #[test]
611    fn pci_link_irq_selects_prs_when_crs_is_unassigned() {
612        let current = LinkIrqResource {
613            kind: LinkIrqResourceKind::ExtendedIrq,
614            descriptor: IrqDescriptor {
615                is_consumer: true,
616                trigger: InterruptTrigger::Level,
617                polarity: InterruptPolarity::ActiveHigh,
618                is_shared: true,
619                is_wake_capable: false,
620                irq: 0,
621            },
622            irqs: alloc::vec![0],
623        };
624        let possible = LinkIrqResource {
625            kind: LinkIrqResourceKind::ExtendedIrq,
626            descriptor: IrqDescriptor {
627                is_consumer: true,
628                trigger: InterruptTrigger::Level,
629                polarity: InterruptPolarity::ActiveHigh,
630                is_shared: true,
631                is_wake_capable: false,
632                irq: 5,
633            },
634            irqs: alloc::vec![5, 10, 11],
635        };
636
637        let link = "\\_SB.LNKA".parse().unwrap();
638        let allocator = PciLinkAllocator::default();
639        let selection = select_pci_link_irq(&link, Some(&current), Some(&possible), &allocator)
640            .expect("possible IRQs should allocate a PCI link");
641
642        assert_eq!(selection.irq, 10);
643        assert!(selection.needs_programming);
644        assert_eq!(selection.resource.irqs, alloc::vec![5, 10, 11]);
645    }
646
647    #[test]
648    fn pci_link_irq_allocator_spreads_unassigned_links() {
649        let possible = LinkIrqResource {
650            kind: LinkIrqResourceKind::ExtendedIrq,
651            descriptor: IrqDescriptor {
652                is_consumer: true,
653                trigger: InterruptTrigger::Level,
654                polarity: InterruptPolarity::ActiveHigh,
655                is_shared: true,
656                is_wake_capable: false,
657                irq: 5,
658            },
659            irqs: alloc::vec![5, 10, 11],
660        };
661        let first = "\\_SB.LNKA".parse().unwrap();
662        let second = "\\_SB.LNKB".parse().unwrap();
663        let mut allocator = PciLinkAllocator::default();
664
665        let first_selection = select_pci_link_irq(&first, None, Some(&possible), &allocator)
666            .expect("first link should allocate");
667        assert_eq!(first_selection.irq, 10);
668        allocator.commit(&first, first_selection.irq);
669
670        let second_selection = select_pci_link_irq(&second, None, Some(&possible), &allocator)
671            .expect("second link should allocate");
672        assert_eq!(second_selection.irq, 11);
673    }
674
675    #[test]
676    fn pci_link_srs_gap_detection_is_narrow() {
677        let gap = acpi::aml::AmlError::ObjectNotOfExpectedType {
678            expected: acpi::aml::object::ObjectType::Integer,
679            got: acpi::aml::object::ObjectType::BufferField,
680        };
681        let other = acpi::aml::AmlError::ObjectNotOfExpectedType {
682            expected: acpi::aml::object::ObjectType::Buffer,
683            got: acpi::aml::object::ObjectType::BufferField,
684        };
685
686        assert!(is_buffer_field_to_field_unit_store_gap(&gap));
687        assert!(!is_buffer_field_to_field_unit_store_gap(&other));
688    }
689
690    #[test]
691    fn qemu_pci_link_names_map_to_pirq_fields() {
692        assert_eq!(
693            pci_link_irq_field_candidates(&"\\_SB.LNKB".parse().unwrap()),
694            ["\\_SB.PRQB", "\\_SB.PRQ1"]
695        );
696        assert_eq!(
697            pci_link_irq_field_candidates(&"\\_SB.LNKG".parse().unwrap()),
698            ["\\_SB.PRQG"]
699        );
700        assert!(pci_link_irq_field_candidates(&"\\_SB.LNKS".parse().unwrap()).is_empty());
701    }
702
703    #[test]
704    fn pci_irq_route_preserves_descriptor_trigger_and_polarity() {
705        let mut routing = AcpiRouting::new();
706        routing.add_io_apic(AcpiIoApic {
707            id: 0,
708            address: 0xfec0_0000,
709            gsi_base: 0,
710            redirection_entries: 24,
711        });
712        let route = routing.resolve_gsi(16).unwrap();
713        let descriptor = IrqDescriptor {
714            is_consumer: true,
715            trigger: InterruptTrigger::Edge,
716            polarity: InterruptPolarity::ActiveHigh,
717            is_shared: false,
718            is_wake_capable: false,
719            irq: 16,
720        };
721
722        let route = route_with_irq_descriptor_flags(route, &descriptor);
723
724        assert_eq!(route.trigger, AcpiIrqTrigger::Edge);
725        assert_eq!(route.polarity, AcpiIrqPolarity::ActiveHigh);
726    }
727}
728
729#[derive(Debug, Clone, Copy, PartialEq, Eq)]
730pub struct AcpiPciIrqRoute {
731    pub address: PciAddress,
732    pub interrupt_pin: u8,
733    pub intx_route: PciIntxRoute,
734    pub gsi: AcpiGsiRoute,
735}
736
737#[derive(Debug, Clone, Copy, PartialEq, Eq)]
738pub struct AcpiResourceRange {
739    pub base: u64,
740    pub size: u64,
741}
742
743#[derive(Debug, Clone, PartialEq, Eq)]
744pub struct AcpiResourceDevice {
745    pub path: String,
746    pub hid: Option<String>,
747    pub cids: Vec<String>,
748    pub memory_ranges: Vec<AcpiResourceRange>,
749    pub io_ranges: Vec<AcpiResourceRange>,
750    pub irq_routes: Vec<AcpiGsiRoute>,
751}
752
753#[derive(Debug, Clone)]
754struct AcpiDeviceInfo {
755    path: String,
756    hid: Option<String>,
757    cids: Vec<String>,
758    memory_ranges: Vec<AcpiResourceRange>,
759    io_ranges: Vec<AcpiResourceRange>,
760    irq_routes: Vec<AcpiGsiRoute>,
761}
762
763#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
764pub enum AcpiResourceAddressSpace {
765    Memory,
766    Io,
767}
768
769#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
770pub struct AcpiResourceAddress {
771    pub space: AcpiResourceAddressSpace,
772    pub base: u64,
773}
774
775impl AcpiResourceAddress {
776    pub const fn memory(base: u64) -> Self {
777        Self {
778            space: AcpiResourceAddressSpace::Memory,
779            base,
780        }
781    }
782
783    pub const fn io(base: u64) -> Self {
784        Self {
785            space: AcpiResourceAddressSpace::Io,
786            base,
787        }
788    }
789
790    pub fn from_generic_address(address: GenericAddress) -> Option<Self> {
791        match address.address_space {
792            AddressSpace::SystemMemory => Some(Self::memory(address.address)),
793            AddressSpace::SystemIo => Some(Self::io(address.address)),
794            _ => None,
795        }
796    }
797}
798
799pub struct AcpiInfo<'a> {
800    pub root: &'a System,
801    pub path: &'a str,
802    pub irq_route: Option<AcpiGsiRoute>,
803    device: Option<&'a AcpiDeviceInfo>,
804}
805
806impl AcpiInfo<'_> {
807    pub const fn irq_route(&self) -> Option<AcpiGsiRoute> {
808        self.irq_route
809    }
810
811    pub fn hid(&self) -> Option<&str> {
812        self.device
813            .as_ref()
814            .and_then(|device| device.hid.as_deref())
815    }
816
817    pub fn cids(&self) -> &[String] {
818        self.device
819            .as_ref()
820            .map(|device| device.cids.as_slice())
821            .unwrap_or_default()
822    }
823
824    pub fn memory_ranges(&self) -> &[AcpiResourceRange] {
825        self.device
826            .as_ref()
827            .map(|device| device.memory_ranges.as_slice())
828            .unwrap_or_default()
829    }
830
831    pub fn io_ranges(&self) -> &[AcpiResourceRange] {
832        self.device
833            .as_ref()
834            .map(|device| device.io_ranges.as_slice())
835            .unwrap_or_default()
836    }
837
838    pub fn irq_routes(&self) -> &[AcpiGsiRoute] {
839        self.device
840            .as_ref()
841            .map(|device| device.irq_routes.as_slice())
842            .unwrap_or_default()
843    }
844}
845
846impl From<AcpiDeviceInfo> for AcpiResourceDevice {
847    fn from(value: AcpiDeviceInfo) -> Self {
848        Self {
849            path: value.path,
850            hid: value.hid,
851            cids: value.cids,
852            memory_ranges: value.memory_ranges,
853            io_ranges: value.io_ranges,
854            irq_routes: value.irq_routes,
855        }
856    }
857}
858
859pub struct ProbeAcpi<'a> {
860    info: AcpiInfo<'a>,
861    platform: PlatformDevice,
862}
863
864impl<'a> ProbeAcpi<'a> {
865    #[allow(dead_code)]
866    pub(crate) fn new(info: AcpiInfo<'a>, platform: PlatformDevice) -> Self {
867        Self { info, platform }
868    }
869
870    pub const fn info(&self) -> &AcpiInfo<'a> {
871        &self.info
872    }
873
874    pub fn into_platform_device(self) -> PlatformDevice {
875        self.platform
876    }
877
878    pub fn into_parts(self) -> (AcpiInfo<'a>, PlatformDevice) {
879        (self.info, self.platform)
880    }
881}
882
883pub type FnOnProbe = for<'a> fn(ProbeAcpi<'a>) -> Result<(), OnProbeError>;
884
885pub fn check_root(root: AcpiRoot) -> Result<(), DriverError> {
886    if root.rsdp == 0 {
887        return Err(acpi_error(AcpiError::NoValidRsdp));
888    }
889    root.tables().map(|_| ()).map_err(acpi_error)
890}
891
892pub fn init(root: AcpiRoot) -> Result<(), DriverError> {
893    let system = System::new(root)?;
894    info!(
895        "ACPI initialized: {} PCI ECAM region(s), {} IOAPIC(s), {} PCH-PIC(s)",
896        system.pci_ecam_regions().len(),
897        system.routing().io_apics().len(),
898        system.routing().pch_pics().len()
899    );
900    SYSTEM.call_once(|| system);
901    Ok(())
902}
903
904pub(crate) fn try_probe_register(
905    register: &DriverRegister,
906) -> Option<Result<alloc::vec::Vec<Result<(), OnProbeError>>, ProbeError>> {
907    SYSTEM.get().map(|system| system.probe_register(register))
908}
909
910pub(crate) fn try_system() -> Option<&'static System> {
911    SYSTEM.get()
912}
913
914pub fn with_acpi<T>(f: impl FnOnce(&System) -> T) -> Option<T> {
915    try_system().map(f)
916}
917
918pub fn spcr_console_device_id() -> Option<DeviceId> {
919    try_system().and_then(System::spcr_console_device_id)
920}
921
922fn acpi_error(err: AcpiError) -> DriverError {
923    DriverError::Unknown(format!("{err:?}"))
924}
925
926fn on_probe_error(err: impl core::fmt::Debug) -> OnProbeError {
927    OnProbeError::other(format!("{err:?}"))
928}
929
930fn identity_phys_to_virt(paddr: usize) -> *mut u8 {
931    paddr as *mut u8
932}
933
934#[derive(Clone)]
935struct AcpiHandler {
936    root: AcpiRoot,
937    pci_ecam_regions: Rc<Vec<AcpiPciEcam>>,
938}
939
940impl AcpiHandler {
941    fn new(root: AcpiRoot, pci_ecam_regions: Vec<AcpiPciEcam>) -> Self {
942        Self {
943            root,
944            pci_ecam_regions: Rc::new(pci_ecam_regions),
945        }
946    }
947
948    fn virt_addr(&self, physical_address: usize) -> usize {
949        (self.root.phys_to_virt)(physical_address) as usize
950    }
951
952    fn pci_config_ptr(
953        &self,
954        address: acpi::PciAddress,
955        offset: u16,
956        width: usize,
957    ) -> Option<*mut u8> {
958        let offset = usize::from(offset);
959        if offset.checked_add(width)? > 4096 {
960            return None;
961        }
962
963        let bus = address.bus();
964        let region = self.pci_ecam_regions.iter().find(|region| {
965            address.segment() == region.segment_group
966                && bus >= region.bus_start
967                && bus <= region.bus_end
968        })?;
969        let bus_offset = usize::from(bus - region.bus_start) << 20;
970        let device_offset = usize::from(address.device()) << 15;
971        let function_offset = usize::from(address.function()) << 12;
972        let physical_address =
973            region.base_address as usize + bus_offset + device_offset + function_offset + offset;
974
975        Some((self.root.phys_to_virt)(physical_address))
976    }
977}
978
979impl Handler for AcpiHandler {
980    unsafe fn map_physical_region<T>(
981        &self,
982        physical_address: usize,
983        size: usize,
984    ) -> PhysicalMapping<Self, T> {
985        PhysicalMapping {
986            physical_start: physical_address,
987            virtual_start: NonNull::new(self.virt_addr(physical_address) as *mut T)
988                .expect("ACPI physical mapping must not be null"),
989            region_length: size,
990            mapped_length: size,
991            handler: self.clone(),
992        }
993    }
994
995    fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
996
997    fn read_u8(&self, address: usize) -> u8 {
998        unsafe { (self.virt_addr(address) as *const u8).read_volatile() }
999    }
1000
1001    fn read_u16(&self, address: usize) -> u16 {
1002        unsafe { (self.virt_addr(address) as *const u16).read_volatile() }
1003    }
1004
1005    fn read_u32(&self, address: usize) -> u32 {
1006        unsafe { (self.virt_addr(address) as *const u32).read_volatile() }
1007    }
1008
1009    fn read_u64(&self, address: usize) -> u64 {
1010        unsafe { (self.virt_addr(address) as *const u64).read_volatile() }
1011    }
1012
1013    fn write_u8(&self, address: usize, value: u8) {
1014        unsafe { (self.virt_addr(address) as *mut u8).write_volatile(value) }
1015    }
1016
1017    fn write_u16(&self, address: usize, value: u16) {
1018        unsafe { (self.virt_addr(address) as *mut u16).write_volatile(value) }
1019    }
1020
1021    fn write_u32(&self, address: usize, value: u32) {
1022        unsafe { (self.virt_addr(address) as *mut u32).write_volatile(value) }
1023    }
1024
1025    fn write_u64(&self, address: usize, value: u64) {
1026        unsafe { (self.virt_addr(address) as *mut u64).write_volatile(value) }
1027    }
1028
1029    fn read_io_u8(&self, port: u16) -> u8 {
1030        read_io_u8(port)
1031    }
1032
1033    fn read_io_u16(&self, port: u16) -> u16 {
1034        read_io_u16(port)
1035    }
1036
1037    fn read_io_u32(&self, port: u16) -> u32 {
1038        read_io_u32(port)
1039    }
1040
1041    fn write_io_u8(&self, port: u16, value: u8) {
1042        write_io_u8(port, value);
1043    }
1044
1045    fn write_io_u16(&self, port: u16, value: u16) {
1046        write_io_u16(port, value);
1047    }
1048
1049    fn write_io_u32(&self, port: u16, value: u32) {
1050        write_io_u32(port, value);
1051    }
1052
1053    fn read_pci_u8(&self, address: acpi::PciAddress, offset: u16) -> u8 {
1054        if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
1055            return unsafe { ptr.read_volatile() };
1056        }
1057        pci_legacy_read_u8(address, offset).unwrap_or(u8::MAX)
1058    }
1059
1060    fn read_pci_u16(&self, address: acpi::PciAddress, offset: u16) -> u16 {
1061        let lo = u16::from(self.read_pci_u8(address, offset));
1062        let hi = u16::from(self.read_pci_u8(address, offset.saturating_add(1)));
1063        lo | (hi << 8)
1064    }
1065
1066    fn read_pci_u32(&self, address: acpi::PciAddress, offset: u16) -> u32 {
1067        let b0 = u32::from(self.read_pci_u8(address, offset));
1068        let b1 = u32::from(self.read_pci_u8(address, offset.saturating_add(1)));
1069        let b2 = u32::from(self.read_pci_u8(address, offset.saturating_add(2)));
1070        let b3 = u32::from(self.read_pci_u8(address, offset.saturating_add(3)));
1071        b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
1072    }
1073
1074    fn write_pci_u8(&self, address: acpi::PciAddress, offset: u16, value: u8) {
1075        if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
1076            unsafe { ptr.write_volatile(value) };
1077            return;
1078        }
1079        pci_legacy_write_u8(address, offset, value);
1080    }
1081
1082    fn write_pci_u16(&self, address: acpi::PciAddress, offset: u16, value: u16) {
1083        self.write_pci_u8(address, offset, value as u8);
1084        self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
1085    }
1086
1087    fn write_pci_u32(&self, address: acpi::PciAddress, offset: u16, value: u32) {
1088        self.write_pci_u8(address, offset, value as u8);
1089        self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
1090        self.write_pci_u8(address, offset.saturating_add(2), (value >> 16) as u8);
1091        self.write_pci_u8(address, offset.saturating_add(3), (value >> 24) as u8);
1092    }
1093
1094    fn nanos_since_boot(&self) -> u64 {
1095        0
1096    }
1097
1098    fn stall(&self, microseconds: u64) {
1099        for _ in 0..microseconds.saturating_mul(100) {
1100            core::hint::spin_loop();
1101        }
1102    }
1103
1104    fn sleep(&self, milliseconds: u64) {
1105        self.stall(milliseconds.saturating_mul(1000));
1106    }
1107
1108    fn create_mutex(&self) -> acpi::Handle {
1109        acpi::Handle(0)
1110    }
1111
1112    fn acquire(&self, _mutex: acpi::Handle, _timeout: u16) -> Result<(), acpi::aml::AmlError> {
1113        let _guard = NULL_LOCK.lock();
1114        Ok(())
1115    }
1116
1117    fn release(&self, _mutex: acpi::Handle) {}
1118}
1119
1120impl AcpiRoot {
1121    fn handler(self) -> AcpiHandler {
1122        AcpiHandler::new(self, Vec::new())
1123    }
1124
1125    fn handler_with_pci_ecam(self, pci_ecam_regions: Vec<AcpiPciEcam>) -> AcpiHandler {
1126        AcpiHandler::new(self, pci_ecam_regions)
1127    }
1128
1129    fn tables(self) -> Result<AcpiTables<AcpiHandler>, AcpiError> {
1130        unsafe { AcpiTables::from_rsdp(self.handler(), self.rsdp) }
1131    }
1132}
1133
1134pub struct System {
1135    ecam_regions: Vec<AcpiPciEcam>,
1136    routing: AcpiRouting,
1137    interpreter: Interpreter<AcpiHandler>,
1138    handler: AcpiHandler,
1139    pci: Option<AcpiPciNamespace>,
1140    probed_names: Mutex<BTreeSet<&'static str>>,
1141    populated_paths: Mutex<BTreeMap<String, DeviceId>>,
1142    populated_resources: Mutex<BTreeMap<AcpiResourceAddress, DeviceId>>,
1143}
1144
1145unsafe impl Send for System {}
1146unsafe impl Sync for System {}
1147
1148struct AcpiPciNamespace {
1149    link_allocator: Mutex<PciLinkAllocator>,
1150    roots: Vec<AcpiPciRoot>,
1151}
1152
1153struct AcpiPciRoot {
1154    segment: u16,
1155    bus: u8,
1156    path: String,
1157    prt: Option<PciRoutingTable>,
1158    link_prt: Option<PciLinkRoutingTable>,
1159}
1160
1161impl System {
1162    pub fn new(root: AcpiRoot) -> Result<Self, DriverError> {
1163        let handler = root.handler();
1164        let tables =
1165            unsafe { AcpiTables::from_rsdp(handler.clone(), root.rsdp) }.map_err(acpi_error)?;
1166        let ecam_regions = read_pci_ecam_regions(&tables)?;
1167        let routing = read_interrupt_routing(&tables)?;
1168        let namespace_handler = root.handler_with_pci_ecam(ecam_regions.clone());
1169        let platform = AcpiPlatform::new(tables, namespace_handler.clone()).map_err(acpi_error)?;
1170        let interpreter = Interpreter::new_from_platform(&platform).map_err(acpi_error)?;
1171        interpreter.initialize_namespace();
1172        let pci = match read_pci_namespace(&interpreter) {
1173            Ok(pci) => Some(pci),
1174            Err(err) => {
1175                warn!("failed to discover ACPI PCI namespace: {err:?}");
1176                None
1177            }
1178        };
1179
1180        Ok(Self {
1181            ecam_regions,
1182            routing,
1183            interpreter,
1184            handler: namespace_handler,
1185            pci,
1186            probed_names: Mutex::new(BTreeSet::new()),
1187            populated_paths: Mutex::new(BTreeMap::new()),
1188            populated_resources: Mutex::new(BTreeMap::new()),
1189        })
1190    }
1191
1192    pub fn pci_ecam_regions(&self) -> &[AcpiPciEcam] {
1193        &self.ecam_regions
1194    }
1195
1196    pub fn routing(&self) -> &AcpiRouting {
1197        &self.routing
1198    }
1199
1200    pub fn path_to_device_id(&self, path: &str) -> Option<DeviceId> {
1201        self.populated_paths.lock().get(path).copied()
1202    }
1203
1204    pub fn resource_address_to_device_id(&self, address: AcpiResourceAddress) -> Option<DeviceId> {
1205        self.populated_resources.lock().get(&address).copied()
1206    }
1207
1208    pub fn spcr_console_device_id(&self) -> Option<DeviceId> {
1209        let tables = unsafe { AcpiTables::from_rsdp(self.handler.clone(), self.handler.root.rsdp) }
1210            .map_err(acpi_error)
1211            .ok()?;
1212        tables
1213            .find_tables::<Spcr>()
1214            .filter(|spcr| is_supported_spcr_interface(spcr.interface_type()))
1215            .find_map(|spcr| {
1216                spcr_namespace_device_id(self, &spcr)
1217                    .or_else(|| spcr_resource_device_id(self, &spcr))
1218            })
1219    }
1220
1221    pub fn resource_devices(&self) -> Result<Vec<AcpiResourceDevice>, ProbeError> {
1222        self.device_infos().map(|devices| {
1223            devices
1224                .into_iter()
1225                .map(AcpiResourceDevice::from)
1226                .collect::<Vec<_>>()
1227        })
1228    }
1229
1230    pub fn serial_console_memory_range(&self) -> Option<AcpiResourceRange> {
1231        let tables = self.handler.root.tables().ok()?;
1232        let spcr = tables.find_table::<acpi::sdt::spcr::Spcr>()?;
1233        let address = spcr.base_address()?.ok()?;
1234        if address.address_space != acpi::address::AddressSpace::SystemMemory {
1235            return None;
1236        }
1237
1238        Some(AcpiResourceRange {
1239            base: address.address,
1240            size: spcr_uart_register_size(address.access_size),
1241        })
1242    }
1243
1244    pub fn pci_irq_for_endpoint(
1245        &self,
1246        info: PciInfo,
1247    ) -> Result<Option<AcpiPciIrqRoute>, OnProbeError> {
1248        let Some(intx_route) = info.intx_route else {
1249            return Ok(None);
1250        };
1251        let Some(irq) = self.resolve_endpoint_gsi(info.address, intx_route)? else {
1252            return Ok(None);
1253        };
1254        let Some(gsi) = pci_irq_descriptor_gsi(&irq) else {
1255            return Err(OnProbeError::other(format!(
1256                "ACPI PCI endpoint {} pin {} returned an invalid IRQ descriptor: {:?}",
1257                info.address, intx_route.root_pin, irq
1258            )));
1259        };
1260        if gsi == 0 {
1261            return Ok(None);
1262        }
1263
1264        let Some(route) = self.routing.resolve_gsi(gsi) else {
1265            return Err(OnProbeError::other(format!(
1266                "ACPI GSI {} for PCI endpoint {} is not covered by a registered GSI controller",
1267                gsi, info.address
1268            )));
1269        };
1270        let route = route_with_irq_descriptor_flags(route, &irq);
1271
1272        Ok(Some(AcpiPciIrqRoute {
1273            address: info.address,
1274            interrupt_pin: intx_route.root_pin,
1275            intx_route,
1276            gsi: route,
1277        }))
1278    }
1279
1280    fn resolve_endpoint_gsi(
1281        &self,
1282        address: PciAddress,
1283        route: PciIntxRoute,
1284    ) -> Result<Option<IrqDescriptor>, OnProbeError> {
1285        let pin = acpi_pin(route.root_pin)?;
1286        let Some(pci) = &self.pci else {
1287            return Ok(None);
1288        };
1289        let roots = self.pci_root_candidates(address, pci);
1290        if roots.is_empty() {
1291            return Ok(None);
1292        }
1293
1294        for root in roots {
1295            let Some(prt) = &root.prt else {
1296                continue;
1297            };
1298
1299            if let Some(link_prt) = &root.link_prt
1300                && let Some(route) = link_prt
1301                    .route(
1302                        u16::from(route.root_device),
1303                        u16::from(route.root_function),
1304                        pin,
1305                        &self.interpreter,
1306                        &self.handler,
1307                        &mut pci.link_allocator.lock(),
1308                    )
1309                    .map_err(on_probe_error)?
1310            {
1311                return Ok(Some(route));
1312            }
1313
1314            match prt.route(
1315                u16::from(route.root_device),
1316                u16::from(route.root_function),
1317                pin,
1318                &self.interpreter,
1319            ) {
1320                Ok(route) => return Ok(Some(route)),
1321                Err(AmlError::PrtNoEntry) => {}
1322                Err(err) => return Err(on_probe_error(err)),
1323            }
1324        }
1325
1326        Ok(None)
1327    }
1328
1329    fn pci_root_candidates<'a>(
1330        &self,
1331        address: PciAddress,
1332        pci: &'a AcpiPciNamespace,
1333    ) -> Vec<&'a AcpiPciRoot> {
1334        let mut roots = Vec::new();
1335        if let Some(root) = pci
1336            .roots
1337            .iter()
1338            .find(|root| root.segment == address.segment() && root.bus == address.bus())
1339            .or_else(|| {
1340                pci.roots
1341                    .iter()
1342                    .find(|root| root.segment == address.segment() && root.bus == 0)
1343            })
1344        {
1345            roots.push(root);
1346        }
1347        for path in PCI_ROOT_FALLBACK_PATHS {
1348            if let Some(root) = pci.roots.iter().find(|root| root.path == *path)
1349                && !roots.iter().any(|candidate| candidate.path == root.path)
1350            {
1351                roots.push(root);
1352            }
1353        }
1354        roots
1355    }
1356
1357    fn device_infos_for_ids(&self, ids: &[AcpiId]) -> Result<Vec<AcpiDeviceInfo>, ProbeError> {
1358        let mut devices = Vec::new();
1359        let mut namespace = self.interpreter.namespace.lock().clone();
1360        namespace
1361            .traverse(|path, level| {
1362                if level.kind != NamespaceLevelKind::Device {
1363                    return Ok(true);
1364                }
1365                let Some((hid, cids)) = acpi_device_ids(&self.interpreter, path)? else {
1366                    return Ok(true);
1367                };
1368                if !acpi_ids_match(&hid, &cids, ids) {
1369                    return Ok(true);
1370                }
1371                let resources = read_device_resources(&self.interpreter, path, &self.routing)?;
1372                devices.push(AcpiDeviceInfo {
1373                    path: path.as_string(),
1374                    hid: Some(hid),
1375                    cids,
1376                    memory_ranges: resources.memory_ranges,
1377                    io_ranges: resources.io_ranges,
1378                    irq_routes: resources.irq_routes,
1379                });
1380                Ok(true)
1381            })
1382            .map_err(|err| ProbeError::OnProbe(OnProbeError::other(format!("{err:?}"))))?;
1383        Ok(devices)
1384    }
1385
1386    fn device_infos(&self) -> Result<Vec<AcpiDeviceInfo>, ProbeError> {
1387        let mut devices = Vec::new();
1388        let mut namespace = self.interpreter.namespace.lock().clone();
1389        namespace
1390            .traverse(|path, level| {
1391                if level.kind != NamespaceLevelKind::Device {
1392                    return Ok(true);
1393                }
1394                let Some((hid, cids)) = acpi_device_ids(&self.interpreter, path)? else {
1395                    return Ok(true);
1396                };
1397                let resources = read_device_resources(&self.interpreter, path, &self.routing)?;
1398                devices.push(AcpiDeviceInfo {
1399                    path: path.as_string(),
1400                    hid: Some(hid),
1401                    cids,
1402                    memory_ranges: resources.memory_ranges,
1403                    io_ranges: resources.io_ranges,
1404                    irq_routes: resources.irq_routes,
1405                });
1406                Ok(true)
1407            })
1408            .map_err(|err| ProbeError::OnProbe(OnProbeError::other(format!("{err:?}"))))?;
1409        Ok(devices)
1410    }
1411
1412    fn probe_register(
1413        &self,
1414        register: &DriverRegister,
1415    ) -> Result<Vec<Result<(), OnProbeError>>, ProbeError> {
1416        let mut out = Vec::new();
1417        for probe in register.probe_kinds {
1418            let ProbeKind::Acpi { ids, on_probe } = probe else {
1419                continue;
1420            };
1421            if self.probed_names.lock().contains(register.name) {
1422                continue;
1423            }
1424
1425            if !ids.is_empty() && !is_root_acpi_id_list(ids) {
1426                for device in self.device_infos_for_ids(ids)? {
1427                    if self.probed_names.lock().contains(register.name) {
1428                        continue;
1429                    }
1430                    let desc = crate::Descriptor {
1431                        name: register.name,
1432                        device_id: DeviceId::new(),
1433                        irq_parent: None,
1434                    };
1435                    let device_id = desc.device_id();
1436                    let info = AcpiInfo {
1437                        root: self,
1438                        path: &device.path,
1439                        irq_route: device.irq_routes.first().copied(),
1440                        device: Some(&device),
1441                    };
1442                    let res = on_probe(ProbeAcpi::new(info, PlatformDevice::new(desc)));
1443                    if res.is_ok() {
1444                        self.probed_names.lock().insert(register.name);
1445                        self.note_populated_device(device_id, &device);
1446                    }
1447                    out.push(res);
1448                }
1449                continue;
1450            }
1451
1452            let desc = crate::Descriptor {
1453                name: register.name,
1454                device_id: DeviceId::new(),
1455                irq_parent: None,
1456            };
1457            let info = AcpiInfo {
1458                root: self,
1459                path: "\\",
1460                irq_route: None,
1461                device: None,
1462            };
1463            let res = on_probe(ProbeAcpi::new(info, PlatformDevice::new(desc)));
1464            if res.is_ok() {
1465                self.probed_names.lock().insert(register.name);
1466            }
1467            out.push(res);
1468        }
1469        Ok(out)
1470    }
1471
1472    fn note_populated_device(&self, device_id: DeviceId, device: &AcpiDeviceInfo) {
1473        self.populated_paths
1474            .lock()
1475            .insert(device.path.clone(), device_id);
1476
1477        let mut resources = self.populated_resources.lock();
1478        for range in &device.memory_ranges {
1479            resources.insert(AcpiResourceAddress::memory(range.base), device_id);
1480        }
1481        for range in &device.io_ranges {
1482            resources.insert(AcpiResourceAddress::io(range.base), device_id);
1483        }
1484    }
1485}
1486
1487fn is_supported_spcr_interface(interface: SpcrInterfaceType) -> bool {
1488    matches!(
1489        interface,
1490        SpcrInterfaceType::Full16550
1491            | SpcrInterfaceType::Full16450
1492            | SpcrInterfaceType::Generic16550
1493            | SpcrInterfaceType::ArmPL011
1494            | SpcrInterfaceType::ArmSBSAGeneric32bit
1495            | SpcrInterfaceType::ArmSBSAGeneric
1496    )
1497}
1498
1499fn spcr_namespace_device_id(system: &System, spcr: &Spcr) -> Option<DeviceId> {
1500    let namespace = spcr.namespace_string().ok()?.trim_end_matches('\0');
1501    if namespace.is_empty() || namespace == "." {
1502        return None;
1503    }
1504    system.path_to_device_id(namespace)
1505}
1506
1507fn spcr_resource_device_id(system: &System, spcr: &Spcr) -> Option<DeviceId> {
1508    let address = spcr.base_address()?.ok()?;
1509    let address = AcpiResourceAddress::from_generic_address(address)?;
1510    system.resource_address_to_device_id(address)
1511}
1512
1513fn read_pci_ecam_regions(
1514    tables: &AcpiTables<AcpiHandler>,
1515) -> Result<Vec<AcpiPciEcam>, DriverError> {
1516    let regions = PciConfigRegions::new(tables).map_err(acpi_error)?;
1517    Ok(regions
1518        .regions
1519        .iter()
1520        .map(|region| AcpiPciEcam {
1521            segment_group: region.pci_segment_group,
1522            bus_start: region.bus_number_start,
1523            bus_end: region.bus_number_end,
1524            base_address: region.base_address,
1525        })
1526        .collect())
1527}
1528
1529fn read_interrupt_routing(tables: &AcpiTables<AcpiHandler>) -> Result<AcpiRouting, DriverError> {
1530    let (model, _) = InterruptModel::new(tables).map_err(acpi_error)?;
1531    let mut routing = AcpiRouting::new();
1532    if let InterruptModel::Apic(apic) = model {
1533        for io_apic in &apic.io_apics {
1534            routing.add_io_apic(AcpiIoApic {
1535                id: io_apic.id,
1536                address: io_apic.address,
1537                gsi_base: io_apic.global_system_interrupt_base,
1538                redirection_entries: 24,
1539            });
1540        }
1541        for irq_override in &apic.interrupt_source_overrides {
1542            routing.add_isa_irq_override(AcpiIsaIrqOverride {
1543                source: irq_override.isa_source,
1544                gsi: irq_override.global_system_interrupt,
1545                trigger: match irq_override.trigger_mode {
1546                    TriggerMode::Edge => AcpiIrqTrigger::Edge,
1547                    TriggerMode::Level => AcpiIrqTrigger::Level,
1548                    _ => AcpiIrqTrigger::Edge,
1549                },
1550                polarity: match irq_override.polarity {
1551                    Polarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
1552                    Polarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
1553                    _ => AcpiIrqPolarity::ActiveHigh,
1554                },
1555            });
1556        }
1557    }
1558    read_loongarch_pch_pic_routing(tables, &mut routing);
1559    Ok(routing)
1560}
1561
1562#[repr(C, packed)]
1563#[derive(Clone, Copy)]
1564struct RawMadtEntryHeader {
1565    entry_type: u8,
1566    length: u8,
1567}
1568
1569#[repr(C, packed)]
1570#[derive(Clone, Copy)]
1571struct RawMadtBioPic {
1572    header: RawMadtEntryHeader,
1573    version: u8,
1574    address: u64,
1575    size: u16,
1576    id: u16,
1577    gsi_base: u16,
1578}
1579
1580const ACPI_MADT_TYPE_BIO_PIC: u8 = 22;
1581const RAW_MADT_HEADER_LEN: usize = core::mem::size_of::<acpi::sdt::SdtHeader>() + 8;
1582
1583fn read_loongarch_pch_pic_routing(tables: &AcpiTables<AcpiHandler>, routing: &mut AcpiRouting) {
1584    let Some(madt) = tables.find_table::<acpi::sdt::madt::Madt>() else {
1585        return;
1586    };
1587
1588    let base = madt.virtual_start.as_ptr() as *const u8;
1589    let length = madt.region_length;
1590    if length < RAW_MADT_HEADER_LEN {
1591        return;
1592    }
1593
1594    let mut offset = RAW_MADT_HEADER_LEN;
1595    while offset + core::mem::size_of::<RawMadtEntryHeader>() <= length {
1596        let header = unsafe { (base.add(offset) as *const RawMadtEntryHeader).read_unaligned() };
1597        let entry_len = usize::from(header.length);
1598        if entry_len < core::mem::size_of::<RawMadtEntryHeader>() || offset + entry_len > length {
1599            break;
1600        }
1601
1602        if header.entry_type == ACPI_MADT_TYPE_BIO_PIC {
1603            read_loongarch_bio_pic_entry(base, offset, entry_len, routing);
1604        }
1605
1606        offset += entry_len;
1607    }
1608}
1609
1610fn read_loongarch_bio_pic_entry(
1611    base: *const u8,
1612    offset: usize,
1613    entry_len: usize,
1614    routing: &mut AcpiRouting,
1615) {
1616    if entry_len < core::mem::size_of::<RawMadtBioPic>() {
1617        warn!("ignore short LoongArch BIO_PIC MADT entry: {entry_len} bytes");
1618        return;
1619    }
1620
1621    let entry = unsafe { (base.add(offset) as *const RawMadtBioPic).read_unaligned() };
1622
1623    routing.add_pch_pic(AcpiPchPic {
1624        id: entry.id,
1625        address: entry.address,
1626        mmio_size: entry.size,
1627        gsi_count: LOONGARCH_PCH_PIC_GSI_COUNT,
1628        gsi_base: u32::from(entry.gsi_base),
1629    });
1630}
1631
1632fn spcr_uart_register_size(access_size: u8) -> u64 {
1633    let access_bytes = match access_size {
1634        1 => 1,
1635        2 => 2,
1636        3 => 4,
1637        4 => 8,
1638        _ => 1,
1639    };
1640    access_bytes * 8
1641}
1642
1643#[derive(Default)]
1644struct AcpiDeviceResources {
1645    memory_ranges: Vec<AcpiResourceRange>,
1646    io_ranges: Vec<AcpiResourceRange>,
1647    irq_routes: Vec<AcpiGsiRoute>,
1648}
1649
1650fn is_root_acpi_id_list(ids: &[AcpiId]) -> bool {
1651    ids.iter().any(|id| id.hid == "ACPIIOAP")
1652}
1653
1654fn acpi_ids_match(hid: &str, cids: &[String], ids: &[AcpiId]) -> bool {
1655    ids.iter().any(|id| {
1656        id.hid == hid
1657            || id.cids.contains(&hid)
1658            || cids
1659                .iter()
1660                .any(|cid| id.hid == cid || id.cids.contains(&cid.as_str()))
1661    })
1662}
1663
1664fn acpi_device_ids(
1665    interpreter: &Interpreter<AcpiHandler>,
1666    path: &AmlName,
1667) -> Result<Option<(String, Vec<String>)>, AmlError> {
1668    let Some(hid_object) = eval_child(interpreter, path, "_HID")? else {
1669        return Ok(None);
1670    };
1671    let Some(hid) = acpi_id_from_object(&hid_object) else {
1672        return Ok(None);
1673    };
1674    let cids = match eval_child(interpreter, path, "_CID")? {
1675        Some(value) => acpi_ids_from_object(&value),
1676        None => Vec::new(),
1677    };
1678    Ok(Some((hid, cids)))
1679}
1680
1681fn acpi_id_from_object(value: &Object) -> Option<String> {
1682    match value {
1683        Object::String(id) => Some(id.clone()),
1684        Object::Integer(id) => decode_eisa_id(*id as u32),
1685        _ => None,
1686    }
1687}
1688
1689fn acpi_ids_from_object(value: &Object) -> Vec<String> {
1690    match value {
1691        Object::Package(values) => values
1692            .iter()
1693            .filter_map(|value| acpi_id_from_object(value))
1694            .collect(),
1695        _ => acpi_id_from_object(value).into_iter().collect(),
1696    }
1697}
1698
1699fn read_device_resources(
1700    interpreter: &Interpreter<AcpiHandler>,
1701    path: &AmlName,
1702    routing: &AcpiRouting,
1703) -> Result<AcpiDeviceResources, AmlError> {
1704    let Some(value) = eval_wrapped_child(interpreter, path, "_CRS")? else {
1705        return Ok(AcpiDeviceResources::default());
1706    };
1707    let resources = resource_descriptor_list(value)?;
1708    let mut out = AcpiDeviceResources::default();
1709    for resource in resources {
1710        match resource {
1711            Resource::MemoryRange(memory) => match memory {
1712                acpi::aml::resource::MemoryRangeDescriptor::FixedLocation {
1713                    base_address,
1714                    range_length,
1715                    ..
1716                } => out.memory_ranges.push(AcpiResourceRange {
1717                    base: u64::from(base_address),
1718                    size: u64::from(range_length),
1719                }),
1720            },
1721            Resource::AddressSpace(address) => {
1722                let range = AcpiResourceRange {
1723                    base: address.address_range.0,
1724                    size: address.length,
1725                };
1726                match address.resource_type {
1727                    AddressSpaceResourceType::MemoryRange => out.memory_ranges.push(range),
1728                    AddressSpaceResourceType::IORange => out.io_ranges.push(range),
1729                    AddressSpaceResourceType::BusNumberRange => {}
1730                }
1731            }
1732            Resource::IOPort(io) => out.io_ranges.push(AcpiResourceRange {
1733                base: u64::from(io.memory_range.0),
1734                size: u64::from(io.range_length),
1735            }),
1736            Resource::Irq(irq) => {
1737                if let Some(gsi) = irq_descriptor_gsi(&irq)
1738                    && let Some(route) = routing.resolve_gsi(gsi)
1739                {
1740                    out.irq_routes
1741                        .push(route_with_irq_descriptor_flags(route, &irq));
1742                }
1743            }
1744            Resource::Dma(_) => {}
1745        }
1746    }
1747    Ok(out)
1748}
1749
1750fn read_pci_namespace(
1751    interpreter: &Interpreter<AcpiHandler>,
1752) -> Result<AcpiPciNamespace, AcpiError> {
1753    let mut roots = Vec::new();
1754    {
1755        let mut namespace = interpreter.namespace.lock().clone();
1756        namespace
1757            .traverse(|path, level| {
1758                if level.kind == NamespaceLevelKind::Device && is_pci_root(interpreter, path) {
1759                    let segment =
1760                        eval_integer_child(interpreter, path, "_SEG")?.unwrap_or(0) as u16;
1761                    let bus = eval_integer_child(interpreter, path, "_BBN")?.unwrap_or(0) as u8;
1762                    roots.push(AcpiPciRoot {
1763                        segment,
1764                        bus,
1765                        path: path.as_string(),
1766                        prt: None,
1767                        link_prt: None,
1768                    });
1769                }
1770                Ok(true)
1771            })
1772            .map_err(AcpiError::Aml)?;
1773    }
1774
1775    for root in &mut roots {
1776        root.prt = read_pci_routing_table(interpreter, &root.path)?;
1777        root.link_prt = read_pci_link_routing_table(interpreter, &root.path)?;
1778    }
1779    for path in PCI_ROOT_FALLBACK_PATHS {
1780        if roots.iter().any(|root| root.path == *path) {
1781            continue;
1782        }
1783        let Some(prt) = read_pci_routing_table(interpreter, path)? else {
1784            continue;
1785        };
1786        let link_prt = read_pci_link_routing_table(interpreter, path)?;
1787        roots.push(AcpiPciRoot {
1788            segment: 0,
1789            bus: 0,
1790            path: path.to_string(),
1791            prt: Some(prt),
1792            link_prt,
1793        });
1794    }
1795
1796    Ok(AcpiPciNamespace {
1797        link_allocator: Mutex::new(PciLinkAllocator::default()),
1798        roots,
1799    })
1800}
1801
1802fn read_pci_routing_table(
1803    interpreter: &Interpreter<AcpiHandler>,
1804    root_path: &str,
1805) -> Result<Option<PciRoutingTable>, AcpiError> {
1806    let prt_path = AmlName::from_str(&format!("{root_path}._PRT")).map_err(AcpiError::Aml)?;
1807    match PciRoutingTable::from_prt_path(prt_path, interpreter) {
1808        Ok(prt) => Ok(Some(prt)),
1809        Err(AmlError::ObjectDoesNotExist(_)) | Err(AmlError::LevelDoesNotExist(_)) => Ok(None),
1810        Err(err) => Err(AcpiError::Aml(err)),
1811    }
1812}
1813
1814fn read_pci_link_routing_table(
1815    interpreter: &Interpreter<AcpiHandler>,
1816    root_path: &str,
1817) -> Result<Option<PciLinkRoutingTable>, AcpiError> {
1818    let prt_path = AmlName::from_str(&format!("{root_path}._PRT")).map_err(AcpiError::Aml)?;
1819    match PciLinkRoutingTable::from_prt_path(prt_path, interpreter) {
1820        Ok(prt) => Ok(Some(prt)),
1821        Err(AmlError::ObjectDoesNotExist(_)) | Err(AmlError::LevelDoesNotExist(_)) => Ok(None),
1822        Err(err) => Err(AcpiError::Aml(err)),
1823    }
1824}
1825
1826fn is_pci_root(interpreter: &Interpreter<AcpiHandler>, path: &AmlName) -> bool {
1827    has_pci_root_id(interpreter, path, "_HID") || has_pci_root_id(interpreter, path, "_CID")
1828}
1829
1830fn has_pci_root_id(interpreter: &Interpreter<AcpiHandler>, path: &AmlName, name: &str) -> bool {
1831    let Ok(Some(value)) = eval_child(interpreter, path, name) else {
1832        return false;
1833    };
1834    object_matches_pci_root_id(&value)
1835}
1836
1837fn object_matches_pci_root_id(value: &Object) -> bool {
1838    match value {
1839        Object::String(id) => matches!(id.as_str(), "PNP0A03" | "PNP0A08"),
1840        Object::Integer(id) => {
1841            let id = decode_eisa_id(*id as u32);
1842            matches!(id.as_deref(), Some("PNP0A03" | "PNP0A08"))
1843        }
1844        Object::Package(values) => values.iter().any(|value| object_matches_pci_root_id(value)),
1845        _ => false,
1846    }
1847}
1848
1849fn eval_integer_child(
1850    interpreter: &Interpreter<AcpiHandler>,
1851    path: &AmlName,
1852    name: &str,
1853) -> Result<Option<u64>, AmlError> {
1854    eval_child(interpreter, path, name)?
1855        .map(|value| value.as_integer())
1856        .transpose()
1857}
1858
1859fn eval_child(
1860    interpreter: &Interpreter<AcpiHandler>,
1861    path: &AmlName,
1862    name: &str,
1863) -> Result<Option<Rc<Object>>, AmlError> {
1864    match eval_wrapped_child(interpreter, path, name)? {
1865        Some(value) => Ok(Some(Rc::new((*value).clone()))),
1866        None => Ok(None),
1867    }
1868}
1869
1870fn eval_wrapped_child(
1871    interpreter: &Interpreter<AcpiHandler>,
1872    path: &AmlName,
1873    name: &str,
1874) -> Result<Option<acpi::aml::object::WrappedObject>, AmlError> {
1875    let child = AmlName::from_str(name)?.resolve(path)?;
1876    interpreter.evaluate_if_present(child, Vec::new())
1877}
1878
1879fn decode_eisa_id(raw: u32) -> Option<String> {
1880    if raw == 0 {
1881        return None;
1882    }
1883    let bytes = raw.to_le_bytes();
1884    let chars = [
1885        ((bytes[0] >> 2) & 0x1f).wrapping_add(b'@'),
1886        (((bytes[0] & 0x03) << 3) | (bytes[1] >> 5)).wrapping_add(b'@'),
1887        (bytes[1] & 0x1f).wrapping_add(b'@'),
1888    ];
1889    if !chars.iter().all(u8::is_ascii_uppercase) {
1890        return None;
1891    }
1892    Some(format!(
1893        "{}{}{}{:02X}{:02X}",
1894        chars[0] as char, chars[1] as char, chars[2] as char, bytes[2], bytes[3]
1895    ))
1896}
1897
1898#[derive(Debug)]
1899struct PciLinkRoutingTable {
1900    entries: Vec<PciLinkRoute>,
1901}
1902
1903#[derive(Debug)]
1904struct PciLinkRoute {
1905    device: u16,
1906    function: u16,
1907    pin: Pin,
1908    link: AmlName,
1909    source_index: usize,
1910}
1911
1912impl PciLinkRoutingTable {
1913    fn from_prt_path(
1914        prt_path: AmlName,
1915        interpreter: &Interpreter<AcpiHandler>,
1916    ) -> Result<Self, AmlError> {
1917        let prt = interpreter.evaluate(prt_path.clone(), Vec::new())?;
1918        let Object::Package(ref entries) = *prt else {
1919            return Err(AmlError::InvalidOperationOnObject {
1920                op: acpi::aml::Operation::DecodePrt,
1921                typ: prt.typ(),
1922            });
1923        };
1924
1925        let mut routes = Vec::new();
1926        for entry in entries {
1927            let Object::Package(ref package) = **entry else {
1928                return Err(AmlError::InvalidOperationOnObject {
1929                    op: acpi::aml::Operation::DecodePrt,
1930                    typ: entry.typ(),
1931                });
1932            };
1933            if package.len() != 4 {
1934                return Err(AmlError::UnexpectedResourceType);
1935            }
1936
1937            let Object::Integer(address) = *package[0] else {
1938                return Err(AmlError::PrtInvalidAddress);
1939            };
1940            let entry_device =
1941                u16::try_from((address >> 16) & 0xffff).map_err(|_| AmlError::PrtInvalidAddress)?;
1942            let entry_function =
1943                u16::try_from(address & 0xffff).map_err(|_| AmlError::PrtInvalidAddress)?;
1944            let entry_pin = match *package[1] {
1945                Object::Integer(0) => Pin::IntA,
1946                Object::Integer(1) => Pin::IntB,
1947                Object::Integer(2) => Pin::IntC,
1948                Object::Integer(3) => Pin::IntD,
1949                _ => return Err(AmlError::PrtInvalidPin),
1950            };
1951            let Object::String(ref source) = *package[2] else {
1952                continue;
1953            };
1954            let Object::Integer(source_index) = *package[3] else {
1955                return Err(AmlError::PrtInvalidSource);
1956            };
1957            let source_index =
1958                usize::try_from(source_index).map_err(|_| AmlError::PrtInvalidSource)?;
1959            let link = interpreter
1960                .namespace
1961                .lock()
1962                .search_for_level(&AmlName::from_str(source)?, &prt_path)?;
1963            routes.push(PciLinkRoute {
1964                device: entry_device,
1965                function: entry_function,
1966                pin: entry_pin,
1967                link,
1968                source_index,
1969            });
1970        }
1971
1972        Ok(Self { entries: routes })
1973    }
1974
1975    fn route(
1976        &self,
1977        device: u16,
1978        function: u16,
1979        pin: Pin,
1980        interpreter: &Interpreter<AcpiHandler>,
1981        handler: &AcpiHandler,
1982        allocator: &mut PciLinkAllocator,
1983    ) -> Result<Option<IrqDescriptor>, AmlError> {
1984        let Some(route) = self.entries.iter().find(|entry| {
1985            entry.device == device
1986                && (entry.function == 0xffff || entry.function == function)
1987                && entry.pin == pin
1988        }) else {
1989            return Ok(None);
1990        };
1991
1992        resolve_pci_link_irq(
1993            interpreter,
1994            handler,
1995            allocator,
1996            &route.link,
1997            route.source_index,
1998        )
1999    }
2000}
2001
2002#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2003enum LinkIrqResourceKind {
2004    SmallIrq,
2005    ExtendedIrq,
2006}
2007
2008#[derive(Clone, Debug)]
2009struct LinkIrqResource {
2010    kind: LinkIrqResourceKind,
2011    descriptor: IrqDescriptor,
2012    irqs: Vec<u32>,
2013}
2014
2015struct LinkIrqSelection<'a> {
2016    resource: &'a LinkIrqResource,
2017    irq: u32,
2018    needs_programming: bool,
2019}
2020
2021#[derive(Default)]
2022struct PciLinkAllocator {
2023    assigned: BTreeMap<String, u32>,
2024    irq_use_count: BTreeMap<u32, usize>,
2025}
2026
2027impl PciLinkAllocator {
2028    fn assigned_irq(&self, link: &AmlName) -> Option<u32> {
2029        self.assigned.get(&link.as_string()).copied()
2030    }
2031
2032    fn commit(&mut self, link: &AmlName, irq: u32) {
2033        let key = link.as_string();
2034        match self.assigned.insert(key, irq) {
2035            Some(old_irq) if old_irq == irq => return,
2036            Some(old_irq) => {
2037                if let Some(count) = self.irq_use_count.get_mut(&old_irq) {
2038                    *count = count.saturating_sub(1);
2039                }
2040            }
2041            None => {}
2042        }
2043        *self.irq_use_count.entry(irq).or_default() += 1;
2044    }
2045
2046    fn penalty(&self, irq: u32) -> usize {
2047        let isa_penalty = match irq {
2048            0..=2 => usize::MAX / 2,
2049            3..=8 => 16 * 16 * 16 * 16,
2050            9..=11 => 0,
2051            12..=15 => 16 * 16 * 16 * 16 * 16,
2052            _ => 0,
2053        };
2054        isa_penalty + self.irq_use_count.get(&irq).copied().unwrap_or(0) * 16 * 16 * 16
2055    }
2056}
2057
2058fn resolve_pci_link_irq(
2059    interpreter: &Interpreter<AcpiHandler>,
2060    handler: &AcpiHandler,
2061    allocator: &mut PciLinkAllocator,
2062    link: &AmlName,
2063    source_index: usize,
2064) -> Result<Option<IrqDescriptor>, AmlError> {
2065    let current = evaluate_link_irq_resource(interpreter, link, "_CRS", source_index)?;
2066    let possible = evaluate_link_irq_resource(interpreter, link, "_PRS", source_index)?;
2067    let Some(selection) = select_pci_link_irq(link, current.as_ref(), possible.as_ref(), allocator)
2068    else {
2069        return Ok(None);
2070    };
2071
2072    if selection.needs_programming {
2073        let srs = build_link_srs_buffer(selection.resource, selection.irq)?;
2074        let srs_path = AmlName::from_str("_SRS")?.resolve(link)?;
2075        if let Err(err) = interpreter.evaluate(srs_path.clone(), vec![Object::Buffer(srs).wrap()]) {
2076            if is_buffer_field_to_field_unit_store_gap(&err) {
2077                let _ = interpreter.namespace.lock().remove_level(srs_path);
2078                // Current acpi's AML Store path cannot coerce a BufferField into a FieldUnit.
2079                // SeaBIOS PIRQ link _SRS methods use that exact pattern; program the already
2080                // decoded link field directly so PCI link allocation still follows _PRS/_SRS.
2081                program_known_pci_link_field(interpreter, handler, link, selection.irq)?;
2082            } else {
2083                let _ = interpreter.namespace.lock().remove_level(srs_path);
2084                return Err(err);
2085            }
2086        }
2087    }
2088
2089    allocator.commit(link, selection.irq);
2090    Ok(Some(selection.resource.descriptor_for_irq(selection.irq)))
2091}
2092
2093fn evaluate_link_irq_resource(
2094    interpreter: &Interpreter<AcpiHandler>,
2095    link: &AmlName,
2096    method: &str,
2097    source_index: usize,
2098) -> Result<Option<LinkIrqResource>, AmlError> {
2099    let path = AmlName::from_str(method)?.resolve(link)?;
2100    let value = match interpreter.evaluate_if_present(path.clone(), Vec::new()) {
2101        Ok(Some(value)) => value,
2102        Ok(None) => return Ok(None),
2103        Err(err) if method == "_CRS" && is_buffer_field_to_field_unit_store_gap(&err) => {
2104            let _ = interpreter.namespace.lock().remove_level(path);
2105            return Ok(None);
2106        }
2107        Err(err) => {
2108            let _ = interpreter.namespace.lock().remove_level(path);
2109            return Err(err);
2110        }
2111    };
2112    let resources = parse_link_irq_resources(&value)?;
2113    Ok(resources.into_iter().nth(source_index))
2114}
2115
2116fn is_buffer_field_to_field_unit_store_gap(err: &AmlError) -> bool {
2117    matches!(
2118        err,
2119        AmlError::ObjectNotOfExpectedType {
2120            expected: ObjectType::Integer,
2121            got: ObjectType::BufferField,
2122        }
2123    )
2124}
2125
2126fn program_known_pci_link_field(
2127    interpreter: &Interpreter<AcpiHandler>,
2128    handler: &AcpiHandler,
2129    link: &AmlName,
2130    irq: u32,
2131) -> Result<(), AmlError> {
2132    let Some(field_path) = known_pci_link_irq_field(interpreter, link) else {
2133        return Err(AmlError::ObjectNotOfExpectedType {
2134            expected: ObjectType::Integer,
2135            got: ObjectType::BufferField,
2136        });
2137    };
2138    let field = interpreter.namespace.lock().get(field_path)?.clone();
2139    let Object::FieldUnit(ref field) = *field else {
2140        return Err(AmlError::ObjectNotOfExpectedType {
2141            expected: ObjectType::FieldUnit,
2142            got: field.typ(),
2143        });
2144    };
2145    write_field_unit(interpreter, handler, field, irq as u64)
2146}
2147
2148fn known_pci_link_irq_field(
2149    interpreter: &Interpreter<AcpiHandler>,
2150    link: &AmlName,
2151) -> Option<AmlName> {
2152    let mut namespace = interpreter.namespace.lock();
2153    for field in pci_link_irq_field_candidates(link) {
2154        let path = AmlName::from_str(field).ok()?;
2155        if namespace.get(path.clone()).is_ok() {
2156            return Some(path);
2157        }
2158    }
2159    None
2160}
2161
2162fn pci_link_irq_field_candidates(link: &AmlName) -> &'static [&'static str] {
2163    match link.as_string().rsplit('.').next().unwrap_or_default() {
2164        "LNKA" => &["\\_SB.PRQA", "\\_SB.PRQ0"],
2165        "LNKB" => &["\\_SB.PRQB", "\\_SB.PRQ1"],
2166        "LNKC" => &["\\_SB.PRQC", "\\_SB.PRQ2"],
2167        "LNKD" => &["\\_SB.PRQD", "\\_SB.PRQ3"],
2168        "LNKE" => &["\\_SB.PRQE"],
2169        "LNKF" => &["\\_SB.PRQF"],
2170        "LNKG" => &["\\_SB.PRQG"],
2171        "LNKH" => &["\\_SB.PRQH"],
2172        _ => &[],
2173    }
2174}
2175
2176fn write_field_unit(
2177    interpreter: &Interpreter<AcpiHandler>,
2178    handler: &AcpiHandler,
2179    field: &FieldUnit,
2180    value: u64,
2181) -> Result<(), AmlError> {
2182    let access_width_bits = field.flags.access_type_bytes()? * 8;
2183    let FieldUnitKind::Normal { ref region } = field.kind else {
2184        return Err(AmlError::LibUnimplemented);
2185    };
2186    let Object::OpRegion(ref region) = **region else {
2187        return Err(AmlError::ObjectNotOfExpectedType {
2188            expected: ObjectType::OpRegion,
2189            got: region.typ(),
2190        });
2191    };
2192
2193    let value_bytes = value.to_le_bytes();
2194    let native_accesses =
2195        (field.bit_length + (field.bit_index % access_width_bits)).div_ceil(access_width_bits);
2196    let mut written_so_far = 0;
2197
2198    for i in 0..native_accesses {
2199        let aligned_bit = align_down(field.bit_index + i * access_width_bits, access_width_bits);
2200        let dst_index = if i == 0 {
2201            field.bit_index % access_width_bits
2202        } else {
2203            0
2204        };
2205        let remaining = field.bit_length - written_so_far;
2206        let length = if i == 0 {
2207            usize::min(
2208                remaining,
2209                access_width_bits - (field.bit_index % access_width_bits),
2210            )
2211        } else {
2212            usize::min(remaining, access_width_bits)
2213        };
2214
2215        let mut bytes = if dst_index > 0 || remaining < access_width_bits {
2216            match field.flags.update_rule() {
2217                FieldUpdateRule::Preserve => read_native_region(
2218                    interpreter,
2219                    handler,
2220                    region,
2221                    aligned_bit / 8,
2222                    access_width_bits / 8,
2223                )?
2224                .to_le_bytes(),
2225                FieldUpdateRule::WriteAsOnes => [0xff; 8],
2226                FieldUpdateRule::WriteAsZeros => [0; 8],
2227            }
2228        } else {
2229            [0; 8]
2230        };
2231
2232        copy_bits(&value_bytes, written_so_far, &mut bytes, dst_index, length);
2233        write_native_region(
2234            interpreter,
2235            handler,
2236            region,
2237            aligned_bit / 8,
2238            access_width_bits / 8,
2239            u64::from_le_bytes(bytes),
2240        )?;
2241        written_so_far += length;
2242    }
2243
2244    Ok(())
2245}
2246
2247fn read_native_region(
2248    interpreter: &Interpreter<AcpiHandler>,
2249    handler: &AcpiHandler,
2250    region: &OpRegion,
2251    offset: usize,
2252    length: usize,
2253) -> Result<u64, AmlError> {
2254    match region.space {
2255        RegionSpace::SystemMemory => {
2256            let address = region.base as usize + offset;
2257            match length {
2258                1 => Ok(u64::from(handler.read_u8(address))),
2259                2 => Ok(u64::from(handler.read_u16(address))),
2260                4 => Ok(u64::from(handler.read_u32(address))),
2261                8 => Ok(handler.read_u64(address)),
2262                _ => Err(AmlError::InvalidFieldFlags),
2263            }
2264        }
2265        RegionSpace::SystemIO => {
2266            let address = region.base as u16 + offset as u16;
2267            match length {
2268                1 => Ok(u64::from(handler.read_io_u8(address))),
2269                2 => Ok(u64::from(handler.read_io_u16(address))),
2270                4 => Ok(u64::from(handler.read_io_u32(address))),
2271                _ => Err(AmlError::InvalidFieldFlags),
2272            }
2273        }
2274        RegionSpace::PciConfig => {
2275            let address = pci_address_for_region(interpreter, region)?;
2276            let offset = region.base as u16 + offset as u16;
2277            match length {
2278                1 => Ok(u64::from(handler.read_pci_u8(address, offset))),
2279                2 => Ok(u64::from(handler.read_pci_u16(address, offset))),
2280                4 => Ok(u64::from(handler.read_pci_u32(address, offset))),
2281                _ => Err(AmlError::InvalidFieldFlags),
2282            }
2283        }
2284        _ => Err(AmlError::NoHandlerForRegionAccess(region.space)),
2285    }
2286}
2287
2288fn write_native_region(
2289    interpreter: &Interpreter<AcpiHandler>,
2290    handler: &AcpiHandler,
2291    region: &OpRegion,
2292    offset: usize,
2293    length: usize,
2294    value: u64,
2295) -> Result<(), AmlError> {
2296    match region.space {
2297        RegionSpace::SystemMemory => {
2298            let address = region.base as usize + offset;
2299            match length {
2300                1 => handler.write_u8(address, value as u8),
2301                2 => handler.write_u16(address, value as u16),
2302                4 => handler.write_u32(address, value as u32),
2303                8 => handler.write_u64(address, value),
2304                _ => return Err(AmlError::InvalidFieldFlags),
2305            }
2306            Ok(())
2307        }
2308        RegionSpace::SystemIO => {
2309            let address = region.base as u16 + offset as u16;
2310            match length {
2311                1 => handler.write_io_u8(address, value as u8),
2312                2 => handler.write_io_u16(address, value as u16),
2313                4 => handler.write_io_u32(address, value as u32),
2314                _ => return Err(AmlError::InvalidFieldFlags),
2315            }
2316            Ok(())
2317        }
2318        RegionSpace::PciConfig => {
2319            let address = pci_address_for_region(interpreter, region)?;
2320            let offset = region.base as u16 + offset as u16;
2321            match length {
2322                1 => handler.write_pci_u8(address, offset, value as u8),
2323                2 => handler.write_pci_u16(address, offset, value as u16),
2324                4 => handler.write_pci_u32(address, offset, value as u32),
2325                _ => return Err(AmlError::InvalidFieldFlags),
2326            }
2327            Ok(())
2328        }
2329        _ => Err(AmlError::NoHandlerForRegionAccess(region.space)),
2330    }
2331}
2332
2333fn pci_address_for_region(
2334    interpreter: &Interpreter<AcpiHandler>,
2335    region: &OpRegion,
2336) -> Result<acpi::PciAddress, AmlError> {
2337    let path = &region.parent_device_path;
2338    let segment = eval_integer_child(interpreter, path, "_SEG")?.unwrap_or(0) as u16;
2339    let bus = eval_integer_child(interpreter, path, "_BBN")?.unwrap_or(0) as u8;
2340    let address = eval_integer_child(interpreter, path, "_ADR")?.unwrap_or(0);
2341    Ok(acpi::PciAddress::new(
2342        segment,
2343        bus,
2344        ((address >> 16) & 0xff) as u8,
2345        (address & 0xff) as u8,
2346    ))
2347}
2348
2349fn copy_bits(src: &[u8], src_offset: usize, dst: &mut [u8], dst_offset: usize, length: usize) {
2350    for bit in 0..length {
2351        let src_bit = src_offset + bit;
2352        let dst_bit = dst_offset + bit;
2353        let is_set = src[src_bit / 8] & (1 << (src_bit % 8)) != 0;
2354        if is_set {
2355            dst[dst_bit / 8] |= 1 << (dst_bit % 8);
2356        } else {
2357            dst[dst_bit / 8] &= !(1 << (dst_bit % 8));
2358        }
2359    }
2360}
2361
2362fn align_down(value: usize, align: usize) -> usize {
2363    assert!(align.is_power_of_two());
2364    value & !(align - 1)
2365}
2366
2367fn parse_link_irq_resources(
2368    value: &acpi::aml::object::WrappedObject,
2369) -> Result<Vec<LinkIrqResource>, AmlError> {
2370    let Object::Buffer(ref bytes) = **value else {
2371        return Err(AmlError::InvalidOperationOnObject {
2372            op: acpi::aml::Operation::ParseResource,
2373            typ: value.typ(),
2374        });
2375    };
2376
2377    let mut resources = Vec::new();
2378    let mut rest = bytes.as_slice();
2379    while !rest.is_empty() {
2380        if rest[0] & 0x80 != 0 {
2381            if rest.len() < 3 {
2382                return Err(AmlError::InvalidResourceDescriptor);
2383            }
2384            let length = usize::from(u16::from_le_bytes([rest[1], rest[2]]));
2385            if rest.len() < length + 3 {
2386                return Err(AmlError::InvalidResourceDescriptor);
2387            }
2388            let descriptor = &rest[..length + 3];
2389            if rest[0] & 0x7f == 0x09 {
2390                resources.push(parse_extended_irq_resource(descriptor)?);
2391            }
2392            rest = &rest[length + 3..];
2393        } else {
2394            let length = usize::from(rest[0] & 0b111);
2395            if rest.len() < length + 1 {
2396                return Err(AmlError::InvalidResourceDescriptor);
2397            }
2398            let descriptor = &rest[..length + 1];
2399            match (rest[0] >> 3) & 0x0f {
2400                0x04 => resources.push(parse_small_irq_resource(descriptor)?),
2401                0x0f => break,
2402                _ => {}
2403            }
2404            rest = &rest[length + 1..];
2405        }
2406    }
2407    Ok(resources)
2408}
2409
2410fn parse_extended_irq_resource(bytes: &[u8]) -> Result<LinkIrqResource, AmlError> {
2411    if bytes.len() < 5 {
2412        return Err(AmlError::InvalidResourceDescriptor);
2413    }
2414    let count = usize::from(bytes[4]);
2415    if bytes.len() < 5 + count * 4 {
2416        return Err(AmlError::InvalidResourceDescriptor);
2417    }
2418
2419    let mut irqs = Vec::new();
2420    for idx in 0..count {
2421        let start = 5 + idx * 4;
2422        irqs.push(u32::from_le_bytes([
2423            bytes[start],
2424            bytes[start + 1],
2425            bytes[start + 2],
2426            bytes[start + 3],
2427        ]));
2428    }
2429
2430    Ok(LinkIrqResource {
2431        kind: LinkIrqResourceKind::ExtendedIrq,
2432        descriptor: IrqDescriptor {
2433            is_consumer: bytes[3] & 0b0000_0001 != 0,
2434            trigger: if bytes[3] & 0b0000_0010 != 0 {
2435                InterruptTrigger::Edge
2436            } else {
2437                InterruptTrigger::Level
2438            },
2439            polarity: if bytes[3] & 0b0000_0100 != 0 {
2440                InterruptPolarity::ActiveLow
2441            } else {
2442                InterruptPolarity::ActiveHigh
2443            },
2444            is_shared: bytes[3] & 0b0000_1000 != 0,
2445            is_wake_capable: bytes[3] & 0b0001_0000 != 0,
2446            irq: irqs.first().copied().unwrap_or(0),
2447        },
2448        irqs,
2449    })
2450}
2451
2452fn parse_small_irq_resource(bytes: &[u8]) -> Result<LinkIrqResource, AmlError> {
2453    if bytes.len() != 3 && bytes.len() != 4 {
2454        return Err(AmlError::InvalidResourceDescriptor);
2455    }
2456
2457    let mask = u16::from_le_bytes([bytes[1], bytes[2]]);
2458    let mut irqs = Vec::new();
2459    for irq in 0..16 {
2460        if mask & (1 << irq) != 0 {
2461            irqs.push(irq);
2462        }
2463    }
2464
2465    let (trigger, polarity, is_shared, is_wake_capable) = if bytes.len() == 4 {
2466        (
2467            if bytes[3] & 0b0000_0001 != 0 {
2468                InterruptTrigger::Edge
2469            } else {
2470                InterruptTrigger::Level
2471            },
2472            if bytes[3] & 0b0000_1000 != 0 {
2473                InterruptPolarity::ActiveLow
2474            } else {
2475                InterruptPolarity::ActiveHigh
2476            },
2477            bytes[3] & 0b0001_0000 != 0,
2478            bytes[3] & 0b0010_0000 != 0,
2479        )
2480    } else {
2481        (
2482            InterruptTrigger::Edge,
2483            InterruptPolarity::ActiveHigh,
2484            false,
2485            false,
2486        )
2487    };
2488
2489    Ok(LinkIrqResource {
2490        kind: LinkIrqResourceKind::SmallIrq,
2491        descriptor: IrqDescriptor {
2492            is_consumer: false,
2493            trigger,
2494            polarity,
2495            is_shared,
2496            is_wake_capable,
2497            irq: u32::from(mask),
2498        },
2499        irqs,
2500    })
2501}
2502
2503fn select_pci_link_irq<'a>(
2504    link: &AmlName,
2505    current: Option<&'a LinkIrqResource>,
2506    possible: Option<&'a LinkIrqResource>,
2507    allocator: &PciLinkAllocator,
2508) -> Option<LinkIrqSelection<'a>> {
2509    if let Some(irq) = allocator.assigned_irq(link) {
2510        let resource = possible
2511            .filter(|possible| possible.irqs.contains(&irq))
2512            .or(current.filter(|current| current.irqs.contains(&irq)))?;
2513        return Some(LinkIrqSelection {
2514            resource,
2515            irq,
2516            needs_programming: current.is_none_or(|current| current.irqs.first() != Some(&irq)),
2517        });
2518    }
2519
2520    if let Some(current) = current
2521        && let Some(irq) = current.irqs.first().copied().filter(|irq| *irq != 0)
2522        && possible.is_none_or(|possible| possible.irqs.contains(&irq))
2523    {
2524        return Some(LinkIrqSelection {
2525            resource: possible.unwrap_or(current),
2526            irq,
2527            needs_programming: false,
2528        });
2529    }
2530
2531    let possible = possible?;
2532    let irq = preferred_pci_link_irq(&possible.irqs, allocator)?;
2533    Some(LinkIrqSelection {
2534        resource: possible,
2535        irq,
2536        needs_programming: true,
2537    })
2538}
2539
2540fn preferred_pci_link_irq(irqs: &[u32], allocator: &PciLinkAllocator) -> Option<u32> {
2541    irqs.iter()
2542        .copied()
2543        .filter(|irq| *irq != 0)
2544        .min_by_key(|irq| (allocator.penalty(*irq), link_irq_tiebreaker(*irq)))
2545}
2546
2547fn link_irq_tiebreaker(irq: u32) -> usize {
2548    match irq {
2549        10 => 0,
2550        11 => 1,
2551        9 => 2,
2552        16.. => 3 + irq as usize,
2553        _ => 1024 + irq as usize,
2554    }
2555}
2556
2557fn build_link_srs_buffer(resource: &LinkIrqResource, irq: u32) -> Result<Vec<u8>, AmlError> {
2558    match resource.kind {
2559        LinkIrqResourceKind::ExtendedIrq => {
2560            let mut buffer = Vec::new();
2561            buffer.extend_from_slice(&[
2562                0x89,
2563                0x06,
2564                0x00,
2565                extended_irq_flags(&resource.descriptor),
2566                1,
2567            ]);
2568            buffer.extend_from_slice(&irq.to_le_bytes());
2569            buffer.extend_from_slice(&[0x79, 0x00]);
2570            Ok(buffer)
2571        }
2572        LinkIrqResourceKind::SmallIrq => {
2573            if irq >= 16 {
2574                return Err(AmlError::InvalidResourceDescriptor);
2575            }
2576            let mask = 1u16 << irq;
2577            let mut buffer = Vec::new();
2578            buffer.push((0x04 << 3) | 3);
2579            buffer.extend_from_slice(&mask.to_le_bytes());
2580            buffer.push(small_irq_flags(&resource.descriptor));
2581            buffer.extend_from_slice(&[0x79, 0x00]);
2582            Ok(buffer)
2583        }
2584    }
2585}
2586
2587impl LinkIrqResource {
2588    fn descriptor_for_irq(&self, irq: u32) -> IrqDescriptor {
2589        let mut descriptor = self.descriptor.clone();
2590        descriptor.irq = irq;
2591        descriptor
2592    }
2593}
2594
2595fn extended_irq_flags(descriptor: &IrqDescriptor) -> u8 {
2596    let mut flags = 0;
2597    if descriptor.is_consumer {
2598        flags |= 1 << 0;
2599    }
2600    if descriptor.trigger == InterruptTrigger::Edge {
2601        flags |= 1 << 1;
2602    }
2603    if descriptor.polarity == InterruptPolarity::ActiveLow {
2604        flags |= 1 << 2;
2605    }
2606    if descriptor.is_shared {
2607        flags |= 1 << 3;
2608    }
2609    if descriptor.is_wake_capable {
2610        flags |= 1 << 4;
2611    }
2612    flags
2613}
2614
2615fn small_irq_flags(descriptor: &IrqDescriptor) -> u8 {
2616    let mut flags = 0;
2617    if descriptor.trigger == InterruptTrigger::Edge {
2618        flags |= 1 << 0;
2619    }
2620    if descriptor.polarity == InterruptPolarity::ActiveLow {
2621        flags |= 1 << 3;
2622    }
2623    if descriptor.is_shared {
2624        flags |= 1 << 4;
2625    }
2626    if descriptor.is_wake_capable {
2627        flags |= 1 << 5;
2628    }
2629    flags
2630}
2631
2632fn acpi_pin(interrupt_pin: u8) -> Result<Pin, OnProbeError> {
2633    match interrupt_pin {
2634        1 => Ok(Pin::IntA),
2635        2 => Ok(Pin::IntB),
2636        3 => Ok(Pin::IntC),
2637        4 => Ok(Pin::IntD),
2638        _ => Err(OnProbeError::other(format!(
2639            "invalid PCI interrupt pin {interrupt_pin}"
2640        ))),
2641    }
2642}
2643
2644fn irq_descriptor_gsi(descriptor: &IrqDescriptor) -> Option<u32> {
2645    let irq = descriptor.irq;
2646    if !descriptor.is_consumer && irq.count_ones() == 1 && irq <= u16::MAX as u32 {
2647        Some(irq.trailing_zeros())
2648    } else {
2649        Some(irq)
2650    }
2651}
2652
2653fn pci_irq_descriptor_gsi(descriptor: &IrqDescriptor) -> Option<u32> {
2654    Some(descriptor.irq)
2655}
2656
2657fn route_with_irq_descriptor_flags(
2658    route: AcpiGsiRoute,
2659    descriptor: &IrqDescriptor,
2660) -> AcpiGsiRoute {
2661    AcpiGsiRoute {
2662        trigger: irq_trigger(descriptor.trigger),
2663        polarity: irq_polarity(descriptor.polarity),
2664        ..route
2665    }
2666}
2667
2668fn irq_trigger(trigger: acpi::aml::resource::InterruptTrigger) -> AcpiIrqTrigger {
2669    match trigger {
2670        acpi::aml::resource::InterruptTrigger::Edge => AcpiIrqTrigger::Edge,
2671        acpi::aml::resource::InterruptTrigger::Level => AcpiIrqTrigger::Level,
2672    }
2673}
2674
2675fn irq_polarity(polarity: acpi::aml::resource::InterruptPolarity) -> AcpiIrqPolarity {
2676    match polarity {
2677        acpi::aml::resource::InterruptPolarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
2678        acpi::aml::resource::InterruptPolarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
2679    }
2680}
2681
2682#[cfg(target_arch = "x86_64")]
2683fn pci_legacy_read_u8(address: acpi::PciAddress, offset: u16) -> Option<u8> {
2684    let value = pci_legacy_read_aligned_u32(address, offset)?;
2685    let shift = u32::from(offset & 0b11) * 8;
2686    Some((value >> shift) as u8)
2687}
2688
2689#[cfg(not(target_arch = "x86_64"))]
2690fn pci_legacy_read_u8(_address: acpi::PciAddress, _offset: u16) -> Option<u8> {
2691    None
2692}
2693
2694#[cfg(target_arch = "x86_64")]
2695fn pci_legacy_write_u8(address: acpi::PciAddress, offset: u16, value: u8) {
2696    let Some(old) = pci_legacy_read_aligned_u32(address, offset) else {
2697        return;
2698    };
2699    let shift = u32::from(offset & 0b11) * 8;
2700    let mask = 0xff_u32 << shift;
2701    let new = (old & !mask) | (u32::from(value) << shift);
2702    pci_legacy_write_aligned_u32(address, offset, new);
2703}
2704
2705#[cfg(not(target_arch = "x86_64"))]
2706fn pci_legacy_write_u8(_address: acpi::PciAddress, _offset: u16, _value: u8) {}
2707
2708#[cfg(target_arch = "x86_64")]
2709fn pci_legacy_config_address(address: acpi::PciAddress, offset: u16) -> Option<u32> {
2710    if address.segment() != 0 || offset >= 256 {
2711        return None;
2712    }
2713
2714    Some(
2715        0x8000_0000
2716            | (u32::from(address.bus()) << 16)
2717            | (u32::from(address.device()) << 11)
2718            | (u32::from(address.function()) << 8)
2719            | u32::from(offset & !0b11),
2720    )
2721}
2722
2723#[cfg(target_arch = "x86_64")]
2724fn pci_legacy_read_aligned_u32(address: acpi::PciAddress, offset: u16) -> Option<u32> {
2725    let config_address = pci_legacy_config_address(address, offset)?;
2726    unsafe {
2727        x86::io::outl(0xcf8, config_address);
2728        Some(x86::io::inl(0xcfc))
2729    }
2730}
2731
2732#[cfg(target_arch = "x86_64")]
2733fn pci_legacy_write_aligned_u32(address: acpi::PciAddress, offset: u16, value: u32) {
2734    if let Some(config_address) = pci_legacy_config_address(address, offset) {
2735        unsafe {
2736            x86::io::outl(0xcf8, config_address);
2737            x86::io::outl(0xcfc, value);
2738        }
2739    }
2740}
2741
2742pub fn acpi_trigger(trigger: TriggerMode) -> AcpiIrqTrigger {
2743    match trigger {
2744        TriggerMode::Edge => AcpiIrqTrigger::Edge,
2745        TriggerMode::Level => AcpiIrqTrigger::Level,
2746        _ => AcpiIrqTrigger::Level,
2747    }
2748}
2749
2750pub fn acpi_polarity(polarity: Polarity) -> AcpiIrqPolarity {
2751    match polarity {
2752        Polarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
2753        Polarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
2754        _ => AcpiIrqPolarity::ActiveLow,
2755    }
2756}
2757
2758#[cfg(target_arch = "x86_64")]
2759fn read_io_u8(port: u16) -> u8 {
2760    unsafe { x86::io::inb(port) }
2761}
2762
2763#[cfg(not(target_arch = "x86_64"))]
2764fn read_io_u8(_port: u16) -> u8 {
2765    0
2766}
2767
2768#[cfg(target_arch = "x86_64")]
2769fn read_io_u16(port: u16) -> u16 {
2770    unsafe { x86::io::inw(port) }
2771}
2772
2773#[cfg(not(target_arch = "x86_64"))]
2774fn read_io_u16(_port: u16) -> u16 {
2775    0
2776}
2777
2778#[cfg(target_arch = "x86_64")]
2779fn read_io_u32(port: u16) -> u32 {
2780    unsafe { x86::io::inl(port) }
2781}
2782
2783#[cfg(not(target_arch = "x86_64"))]
2784fn read_io_u32(_port: u16) -> u32 {
2785    0
2786}
2787
2788#[cfg(target_arch = "x86_64")]
2789fn write_io_u8(port: u16, value: u8) {
2790    unsafe { x86::io::outb(port, value) }
2791}
2792
2793#[cfg(not(target_arch = "x86_64"))]
2794fn write_io_u8(_port: u16, _value: u8) {}
2795
2796#[cfg(target_arch = "x86_64")]
2797fn write_io_u16(port: u16, value: u16) {
2798    unsafe { x86::io::outw(port, value) }
2799}
2800
2801#[cfg(not(target_arch = "x86_64"))]
2802fn write_io_u16(_port: u16, _value: u16) {}
2803
2804#[cfg(target_arch = "x86_64")]
2805fn write_io_u32(port: u16, value: u32) {
2806    unsafe { x86::io::outl(port, value) }
2807}
2808
2809#[cfg(not(target_arch = "x86_64"))]
2810fn write_io_u32(_port: u16, _value: u32) {}