1use alloc::{
2 collections::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 aml::{
13 AmlError, Interpreter,
14 namespace::{AmlName, NamespaceLevelKind},
15 object::Object,
16 pci_routing::{IrqDescriptor, PciRoutingTable, Pin},
17 resource::{InterruptPolarity, InterruptTrigger},
18 },
19 platform::{
20 AcpiPlatform,
21 interrupt::{InterruptModel, Polarity, TriggerMode},
22 pci::PciConfigRegions,
23 },
24};
25pub use rdif_base::irq::{AcpiGsiRoute, AcpiIrqPolarity, AcpiIrqTrigger};
26use spin::{Mutex, Once};
27
28use crate::{
29 DeviceId, PlatformDevice,
30 error::DriverError,
31 probe::{OnProbeError, ProbeError, pci::PciAddress},
32 register::{DriverRegister, ProbeKind},
33};
34
35pub const PCI_INTX_VECTOR_BASE: usize = 0x30;
36const PCI_ROOT_FALLBACK_PATHS: &[&str] = &["\\_SB.PCI0", "\\_SB.PCI1", "\\_SB.PC00", "\\_SB.PC01"];
37
38static SYSTEM: Once<System> = Once::new();
39static NULL_LOCK: Mutex<()> = Mutex::new(());
40
41#[derive(Clone, Copy)]
42pub struct AcpiRoot {
43 pub rsdp: usize,
44 pub phys_to_virt: fn(usize) -> *mut u8,
45}
46
47impl core::fmt::Debug for AcpiRoot {
48 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49 f.debug_struct("AcpiRoot")
50 .field("rsdp", &self.rsdp)
51 .finish_non_exhaustive()
52 }
53}
54
55impl AcpiRoot {
56 pub const fn new(rsdp: usize, phys_to_virt: fn(usize) -> *mut u8) -> Self {
57 Self { rsdp, phys_to_virt }
58 }
59
60 pub const fn identity(rsdp: usize) -> Self {
61 Self::new(rsdp, identity_phys_to_virt)
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct AcpiId {
67 pub hid: &'static str,
68 pub cids: &'static [&'static str],
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub struct AcpiPciEcam {
73 pub segment_group: u16,
74 pub bus_start: u8,
75 pub bus_end: u8,
76 pub base_address: u64,
77}
78
79impl AcpiPciEcam {
80 pub fn size(&self) -> usize {
81 let buses = usize::from(self.bus_end.saturating_sub(self.bus_start)) + 1;
82 buses << 20
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub struct AcpiIoApic {
88 pub id: u8,
89 pub address: u32,
90 pub gsi_base: u32,
91 pub redirection_entries: u8,
92}
93
94impl AcpiIoApic {
95 fn contains_gsi(self, gsi: u32) -> bool {
96 let start = self.gsi_base;
97 let end = start.saturating_add(u32::from(self.redirection_entries));
98 (start..end).contains(&gsi)
99 }
100}
101
102#[derive(Debug, Clone)]
103pub struct AcpiRouting {
104 io_apics: Vec<AcpiIoApic>,
105}
106
107impl AcpiRouting {
108 pub const fn new() -> Self {
109 Self {
110 io_apics: Vec::new(),
111 }
112 }
113
114 pub fn add_io_apic(&mut self, io_apic: AcpiIoApic) {
115 self.io_apics.push(io_apic);
116 }
117
118 pub fn io_apics(&self) -> &[AcpiIoApic] {
119 &self.io_apics
120 }
121
122 pub fn resolve_gsi(&self, gsi: u32) -> Option<AcpiGsiRoute> {
123 let io_apic = self
124 .io_apics
125 .iter()
126 .copied()
127 .find(|io_apic| io_apic.contains_gsi(gsi))?;
128 let input = u8::try_from(gsi.saturating_sub(io_apic.gsi_base)).ok()?;
129 Some(AcpiGsiRoute {
130 gsi,
131 vector: PCI_INTX_VECTOR_BASE + gsi as usize,
132 controller_id: io_apic.id,
133 controller_address: io_apic.address,
134 controller_input: input,
135 trigger: AcpiIrqTrigger::Level,
136 polarity: AcpiIrqPolarity::ActiveLow,
137 })
138 }
139
140 pub fn resolve_vector(&self, vector: usize) -> Option<AcpiGsiRoute> {
141 let gsi = vector.checked_sub(PCI_INTX_VECTOR_BASE)?;
142 self.resolve_gsi(gsi as u32)
143 }
144}
145
146impl Default for AcpiRouting {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::{AcpiIoApic, AcpiIrqPolarity, AcpiIrqTrigger, AcpiRouting};
155
156 #[test]
157 fn ioapic_routes_map_gsi_to_stable_vector() {
158 let mut routing = AcpiRouting::new();
159 routing.add_io_apic(AcpiIoApic {
160 id: 0,
161 address: 0xfec0_0000,
162 gsi_base: 0,
163 redirection_entries: 24,
164 });
165
166 let irq = routing
167 .resolve_gsi(16)
168 .expect("gsi 16 should be handled by the IOAPIC");
169 assert_eq!(irq.gsi, 16);
170 assert_eq!(irq.controller_id, 0);
171 assert_eq!(irq.controller_address, 0xfec0_0000);
172 assert_eq!(irq.controller_input, 16);
173 assert_eq!(irq.vector, 0x40);
174 assert_eq!(irq.trigger, AcpiIrqTrigger::Level);
175 assert_eq!(irq.polarity, AcpiIrqPolarity::ActiveLow);
176 assert!(routing.resolve_gsi(24).is_none());
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
181pub struct AcpiPciIrqRoute {
182 pub address: PciAddress,
183 pub interrupt_pin: u8,
184 pub gsi: AcpiGsiRoute,
185}
186
187pub struct AcpiInfo<'a> {
188 pub root: &'a System,
189 pub path: &'a str,
190}
191
192pub type FnOnProbe = fn(AcpiInfo<'_>, PlatformDevice) -> Result<(), OnProbeError>;
193
194pub fn check_root(root: AcpiRoot) -> Result<(), DriverError> {
195 if root.rsdp == 0 {
196 return Err(acpi_error(AcpiError::NoValidRsdp));
197 }
198 root.tables().map(|_| ()).map_err(acpi_error)
199}
200
201pub fn init(root: AcpiRoot) -> Result<(), DriverError> {
202 let system = System::new(root)?;
203 info!(
204 "ACPI initialized: {} PCI ECAM region(s), {} IOAPIC(s)",
205 system.pci_ecam_regions().len(),
206 system.routing().io_apics().len()
207 );
208 SYSTEM.call_once(|| system);
209 Ok(())
210}
211
212pub(crate) fn try_probe_register(
213 register: &DriverRegister,
214) -> Option<Result<alloc::vec::Vec<Result<(), OnProbeError>>, ProbeError>> {
215 SYSTEM.get().map(|system| system.probe_register(register))
216}
217
218pub(crate) fn try_system() -> Option<&'static System> {
219 SYSTEM.get()
220}
221
222pub fn with_acpi<T>(f: impl FnOnce(&System) -> T) -> Option<T> {
223 try_system().map(f)
224}
225
226fn acpi_error(err: AcpiError) -> DriverError {
227 DriverError::Unknown(format!("{err:?}"))
228}
229
230fn on_probe_error(err: impl core::fmt::Debug) -> OnProbeError {
231 OnProbeError::other(format!("{err:?}"))
232}
233
234fn identity_phys_to_virt(paddr: usize) -> *mut u8 {
235 paddr as *mut u8
236}
237
238#[derive(Clone)]
239struct AcpiHandler {
240 root: AcpiRoot,
241 pci_ecam_regions: Rc<Vec<AcpiPciEcam>>,
242}
243
244impl AcpiHandler {
245 fn new(root: AcpiRoot, pci_ecam_regions: Vec<AcpiPciEcam>) -> Self {
246 Self {
247 root,
248 pci_ecam_regions: Rc::new(pci_ecam_regions),
249 }
250 }
251
252 fn virt_addr(&self, physical_address: usize) -> usize {
253 (self.root.phys_to_virt)(physical_address) as usize
254 }
255
256 fn pci_config_ptr(
257 &self,
258 address: acpi::PciAddress,
259 offset: u16,
260 width: usize,
261 ) -> Option<*mut u8> {
262 let offset = usize::from(offset);
263 if offset.checked_add(width)? > 4096 {
264 return None;
265 }
266
267 let bus = address.bus();
268 let region = self.pci_ecam_regions.iter().find(|region| {
269 address.segment() == region.segment_group
270 && bus >= region.bus_start
271 && bus <= region.bus_end
272 })?;
273 let bus_offset = usize::from(bus - region.bus_start) << 20;
274 let device_offset = usize::from(address.device()) << 15;
275 let function_offset = usize::from(address.function()) << 12;
276 let physical_address =
277 region.base_address as usize + bus_offset + device_offset + function_offset + offset;
278
279 Some((self.root.phys_to_virt)(physical_address))
280 }
281}
282
283impl Handler for AcpiHandler {
284 unsafe fn map_physical_region<T>(
285 &self,
286 physical_address: usize,
287 size: usize,
288 ) -> PhysicalMapping<Self, T> {
289 PhysicalMapping {
290 physical_start: physical_address,
291 virtual_start: NonNull::new(self.virt_addr(physical_address) as *mut T)
292 .expect("ACPI physical mapping must not be null"),
293 region_length: size,
294 mapped_length: size,
295 handler: self.clone(),
296 }
297 }
298
299 fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
300
301 fn read_u8(&self, address: usize) -> u8 {
302 unsafe { (self.virt_addr(address) as *const u8).read_volatile() }
303 }
304
305 fn read_u16(&self, address: usize) -> u16 {
306 unsafe { (self.virt_addr(address) as *const u16).read_volatile() }
307 }
308
309 fn read_u32(&self, address: usize) -> u32 {
310 unsafe { (self.virt_addr(address) as *const u32).read_volatile() }
311 }
312
313 fn read_u64(&self, address: usize) -> u64 {
314 unsafe { (self.virt_addr(address) as *const u64).read_volatile() }
315 }
316
317 fn write_u8(&self, address: usize, value: u8) {
318 unsafe { (self.virt_addr(address) as *mut u8).write_volatile(value) }
319 }
320
321 fn write_u16(&self, address: usize, value: u16) {
322 unsafe { (self.virt_addr(address) as *mut u16).write_volatile(value) }
323 }
324
325 fn write_u32(&self, address: usize, value: u32) {
326 unsafe { (self.virt_addr(address) as *mut u32).write_volatile(value) }
327 }
328
329 fn write_u64(&self, address: usize, value: u64) {
330 unsafe { (self.virt_addr(address) as *mut u64).write_volatile(value) }
331 }
332
333 fn read_io_u8(&self, port: u16) -> u8 {
334 read_io_u8(port)
335 }
336
337 fn read_io_u16(&self, port: u16) -> u16 {
338 read_io_u16(port)
339 }
340
341 fn read_io_u32(&self, port: u16) -> u32 {
342 read_io_u32(port)
343 }
344
345 fn write_io_u8(&self, port: u16, value: u8) {
346 write_io_u8(port, value);
347 }
348
349 fn write_io_u16(&self, port: u16, value: u16) {
350 write_io_u16(port, value);
351 }
352
353 fn write_io_u32(&self, port: u16, value: u32) {
354 write_io_u32(port, value);
355 }
356
357 fn read_pci_u8(&self, address: acpi::PciAddress, offset: u16) -> u8 {
358 if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
359 return unsafe { ptr.read_volatile() };
360 }
361 pci_legacy_read_u8(address, offset).unwrap_or(u8::MAX)
362 }
363
364 fn read_pci_u16(&self, address: acpi::PciAddress, offset: u16) -> u16 {
365 let lo = u16::from(self.read_pci_u8(address, offset));
366 let hi = u16::from(self.read_pci_u8(address, offset.saturating_add(1)));
367 lo | (hi << 8)
368 }
369
370 fn read_pci_u32(&self, address: acpi::PciAddress, offset: u16) -> u32 {
371 let b0 = u32::from(self.read_pci_u8(address, offset));
372 let b1 = u32::from(self.read_pci_u8(address, offset.saturating_add(1)));
373 let b2 = u32::from(self.read_pci_u8(address, offset.saturating_add(2)));
374 let b3 = u32::from(self.read_pci_u8(address, offset.saturating_add(3)));
375 b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
376 }
377
378 fn write_pci_u8(&self, address: acpi::PciAddress, offset: u16, value: u8) {
379 if let Some(ptr) = self.pci_config_ptr(address, offset, 1) {
380 unsafe { ptr.write_volatile(value) };
381 return;
382 }
383 pci_legacy_write_u8(address, offset, value);
384 }
385
386 fn write_pci_u16(&self, address: acpi::PciAddress, offset: u16, value: u16) {
387 self.write_pci_u8(address, offset, value as u8);
388 self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
389 }
390
391 fn write_pci_u32(&self, address: acpi::PciAddress, offset: u16, value: u32) {
392 self.write_pci_u8(address, offset, value as u8);
393 self.write_pci_u8(address, offset.saturating_add(1), (value >> 8) as u8);
394 self.write_pci_u8(address, offset.saturating_add(2), (value >> 16) as u8);
395 self.write_pci_u8(address, offset.saturating_add(3), (value >> 24) as u8);
396 }
397
398 fn nanos_since_boot(&self) -> u64 {
399 0
400 }
401
402 fn stall(&self, microseconds: u64) {
403 for _ in 0..microseconds.saturating_mul(100) {
404 core::hint::spin_loop();
405 }
406 }
407
408 fn sleep(&self, milliseconds: u64) {
409 self.stall(milliseconds.saturating_mul(1000));
410 }
411
412 fn create_mutex(&self) -> acpi::Handle {
413 acpi::Handle(0)
414 }
415
416 fn acquire(&self, _mutex: acpi::Handle, _timeout: u16) -> Result<(), acpi::aml::AmlError> {
417 let _guard = NULL_LOCK.lock();
418 Ok(())
419 }
420
421 fn release(&self, _mutex: acpi::Handle) {}
422}
423
424impl AcpiRoot {
425 fn handler(self) -> AcpiHandler {
426 AcpiHandler::new(self, Vec::new())
427 }
428
429 fn handler_with_pci_ecam(self, pci_ecam_regions: Vec<AcpiPciEcam>) -> AcpiHandler {
430 AcpiHandler::new(self, pci_ecam_regions)
431 }
432
433 fn tables(self) -> Result<AcpiTables<AcpiHandler>, AcpiError> {
434 unsafe { AcpiTables::from_rsdp(self.handler(), self.rsdp) }
435 }
436}
437
438pub struct System {
439 ecam_regions: Vec<AcpiPciEcam>,
440 routing: AcpiRouting,
441 pci: Option<AcpiPciNamespace>,
442 probed_names: Mutex<BTreeSet<&'static str>>,
443}
444
445unsafe impl Send for System {}
446unsafe impl Sync for System {}
447
448struct AcpiPciNamespace {
449 interpreter: Interpreter<AcpiHandler>,
450 roots: Vec<AcpiPciRoot>,
451}
452
453struct AcpiPciRoot {
454 segment: u16,
455 bus: u8,
456 path: String,
457 prt: Option<PciRoutingTable>,
458}
459
460impl System {
461 pub fn new(root: AcpiRoot) -> Result<Self, DriverError> {
462 let tables = root.tables().map_err(acpi_error)?;
463 let ecam_regions = read_pci_ecam_regions(&tables)?;
464 let routing = read_interrupt_routing(&tables)?;
465 let pci = match read_pci_namespace(root, ecam_regions.clone()) {
466 Ok(pci) => Some(pci),
467 Err(err) => {
468 warn!("failed to discover ACPI PCI namespace: {err:?}");
469 None
470 }
471 };
472
473 Ok(Self {
474 ecam_regions,
475 routing,
476 pci,
477 probed_names: Mutex::new(BTreeSet::new()),
478 })
479 }
480
481 pub fn pci_ecam_regions(&self) -> &[AcpiPciEcam] {
482 &self.ecam_regions
483 }
484
485 pub fn routing(&self) -> &AcpiRouting {
486 &self.routing
487 }
488
489 pub fn pci_irq_for_endpoint(
490 &self,
491 address: PciAddress,
492 interrupt_pin: u8,
493 ) -> Result<Option<AcpiPciIrqRoute>, OnProbeError> {
494 let Some(mut irq) = self.resolve_endpoint_gsi(address, interrupt_pin)? else {
495 return Ok(None);
496 };
497 let Some(gsi) = irq_descriptor_gsi(&irq) else {
498 return Err(OnProbeError::other(format!(
499 "ACPI PCI endpoint {} pin {} returned an invalid IRQ descriptor: {:?}",
500 address, interrupt_pin, irq
501 )));
502 };
503 irq.irq = gsi;
504
505 let Some(route) = self.routing.resolve_gsi(gsi) else {
506 return Err(OnProbeError::other(format!(
507 "ACPI GSI {} for PCI endpoint {} is not covered by an IOAPIC",
508 gsi, address
509 )));
510 };
511
512 Ok(Some(AcpiPciIrqRoute {
513 address,
514 interrupt_pin,
515 gsi: AcpiGsiRoute {
516 trigger: irq_trigger(irq.trigger),
517 polarity: irq_polarity(irq.polarity),
518 ..route
519 },
520 }))
521 }
522
523 fn resolve_endpoint_gsi(
524 &self,
525 address: PciAddress,
526 interrupt_pin: u8,
527 ) -> Result<Option<IrqDescriptor>, OnProbeError> {
528 let pin = acpi_pin(interrupt_pin)?;
529 let Some(pci) = &self.pci else {
530 return Ok(None);
531 };
532 let roots = self.pci_root_candidates(address, pci);
533 if roots.is_empty() {
534 return Ok(None);
535 }
536
537 for root in roots {
538 let Some(prt) = &root.prt else {
539 continue;
540 };
541
542 match prt.route(
543 u16::from(address.device()),
544 u16::from(address.function()),
545 pin,
546 &pci.interpreter,
547 ) {
548 Ok(route) => return Ok(Some(route)),
549 Err(AmlError::PrtNoEntry) => {}
550 Err(err) => return Err(on_probe_error(err)),
551 }
552 }
553
554 Ok(None)
555 }
556
557 fn pci_root_candidates<'a>(
558 &self,
559 address: PciAddress,
560 pci: &'a AcpiPciNamespace,
561 ) -> Vec<&'a AcpiPciRoot> {
562 let mut roots = Vec::new();
563 if let Some(root) = pci
564 .roots
565 .iter()
566 .find(|root| root.segment == address.segment() && root.bus == address.bus())
567 .or_else(|| {
568 pci.roots
569 .iter()
570 .find(|root| root.segment == address.segment() && root.bus == 0)
571 })
572 {
573 roots.push(root);
574 }
575 for path in PCI_ROOT_FALLBACK_PATHS {
576 if let Some(root) = pci.roots.iter().find(|root| root.path == *path)
577 && !roots.iter().any(|candidate| candidate.path == root.path)
578 {
579 roots.push(root);
580 }
581 }
582 roots
583 }
584
585 fn probe_register(
586 &self,
587 register: &DriverRegister,
588 ) -> Result<Vec<Result<(), OnProbeError>>, ProbeError> {
589 let mut out = Vec::new();
590 for probe in register.probe_kinds {
591 let ProbeKind::Acpi { ids, on_probe } = probe else {
592 continue;
593 };
594 if ids.is_empty() {
595 continue;
596 }
597 if self.probed_names.lock().contains(register.name) {
598 continue;
599 }
600
601 let desc = crate::Descriptor {
602 name: register.name,
603 device_id: DeviceId::new(),
604 irq_parent: None,
605 };
606 let info = AcpiInfo {
607 root: self,
608 path: "\\",
609 };
610 let res = on_probe(info, PlatformDevice::new(desc));
611 if res.is_ok() {
612 self.probed_names.lock().insert(register.name);
613 }
614 out.push(res);
615 }
616 Ok(out)
617 }
618}
619
620fn read_pci_ecam_regions(
621 tables: &AcpiTables<AcpiHandler>,
622) -> Result<Vec<AcpiPciEcam>, DriverError> {
623 let regions = PciConfigRegions::new(tables).map_err(acpi_error)?;
624 Ok(regions
625 .regions
626 .iter()
627 .map(|region| AcpiPciEcam {
628 segment_group: region.pci_segment_group,
629 bus_start: region.bus_number_start,
630 bus_end: region.bus_number_end,
631 base_address: region.base_address,
632 })
633 .collect())
634}
635
636fn read_interrupt_routing(tables: &AcpiTables<AcpiHandler>) -> Result<AcpiRouting, DriverError> {
637 let (model, _) = InterruptModel::new(tables).map_err(acpi_error)?;
638 let mut routing = AcpiRouting::new();
639 if let InterruptModel::Apic(apic) = model {
640 for io_apic in &apic.io_apics {
641 routing.add_io_apic(AcpiIoApic {
642 id: io_apic.id,
643 address: io_apic.address,
644 gsi_base: io_apic.global_system_interrupt_base,
645 redirection_entries: 24,
646 });
647 }
648 }
649 Ok(routing)
650}
651
652fn read_pci_namespace(
653 root: AcpiRoot,
654 ecam_regions: Vec<AcpiPciEcam>,
655) -> Result<AcpiPciNamespace, AcpiError> {
656 let handler = root.handler_with_pci_ecam(ecam_regions);
657 let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), root.rsdp) }?;
658 let platform = AcpiPlatform::new(tables, handler)?;
659 let interpreter = Interpreter::new_from_platform(&platform)?;
660 interpreter.initialize_namespace();
661
662 let mut roots = Vec::new();
663 {
664 let mut namespace = interpreter.namespace.lock().clone();
665 namespace
666 .traverse(|path, level| {
667 if level.kind == NamespaceLevelKind::Device && is_pci_root(&interpreter, path) {
668 let segment =
669 eval_integer_child(&interpreter, path, "_SEG")?.unwrap_or(0) as u16;
670 let bus = eval_integer_child(&interpreter, path, "_BBN")?.unwrap_or(0) as u8;
671 roots.push(AcpiPciRoot {
672 segment,
673 bus,
674 path: path.as_string(),
675 prt: None,
676 });
677 }
678 Ok(true)
679 })
680 .map_err(AcpiError::Aml)?;
681 }
682
683 for root in &mut roots {
684 root.prt = read_pci_routing_table(&interpreter, &root.path)?;
685 }
686 for path in PCI_ROOT_FALLBACK_PATHS {
687 if roots.iter().any(|root| root.path == *path) {
688 continue;
689 }
690 let Some(prt) = read_pci_routing_table(&interpreter, path)? else {
691 continue;
692 };
693 roots.push(AcpiPciRoot {
694 segment: 0,
695 bus: 0,
696 path: path.to_string(),
697 prt: Some(prt),
698 });
699 }
700
701 Ok(AcpiPciNamespace { interpreter, roots })
702}
703
704fn read_pci_routing_table(
705 interpreter: &Interpreter<AcpiHandler>,
706 root_path: &str,
707) -> Result<Option<PciRoutingTable>, AcpiError> {
708 let prt_path = AmlName::from_str(&format!("{root_path}._PRT")).map_err(AcpiError::Aml)?;
709 match PciRoutingTable::from_prt_path(prt_path, interpreter) {
710 Ok(prt) => Ok(Some(prt)),
711 Err(AmlError::ObjectDoesNotExist(_)) | Err(AmlError::LevelDoesNotExist(_)) => Ok(None),
712 Err(err) => Err(AcpiError::Aml(err)),
713 }
714}
715
716fn is_pci_root(interpreter: &Interpreter<AcpiHandler>, path: &AmlName) -> bool {
717 has_pci_root_id(interpreter, path, "_HID") || has_pci_root_id(interpreter, path, "_CID")
718}
719
720fn has_pci_root_id(interpreter: &Interpreter<AcpiHandler>, path: &AmlName, name: &str) -> bool {
721 let Ok(Some(value)) = eval_child(interpreter, path, name) else {
722 return false;
723 };
724 object_matches_pci_root_id(&value)
725}
726
727fn object_matches_pci_root_id(value: &Object) -> bool {
728 match value {
729 Object::String(id) => matches!(id.as_str(), "PNP0A03" | "PNP0A08"),
730 Object::Integer(id) => {
731 let id = decode_eisa_id(*id as u32);
732 matches!(id.as_deref(), Some("PNP0A03" | "PNP0A08"))
733 }
734 Object::Package(values) => values.iter().any(|value| object_matches_pci_root_id(value)),
735 _ => false,
736 }
737}
738
739fn eval_integer_child(
740 interpreter: &Interpreter<AcpiHandler>,
741 path: &AmlName,
742 name: &str,
743) -> Result<Option<u64>, AmlError> {
744 eval_child(interpreter, path, name)?
745 .map(|value| value.as_integer())
746 .transpose()
747}
748
749fn eval_child(
750 interpreter: &Interpreter<AcpiHandler>,
751 path: &AmlName,
752 name: &str,
753) -> Result<Option<Rc<Object>>, AmlError> {
754 let child = AmlName::from_str(name)?.resolve(path)?;
755 match interpreter.evaluate_if_present(child, Vec::new())? {
756 Some(value) => Ok(Some(Rc::new((*value).clone()))),
757 None => Ok(None),
758 }
759}
760
761fn decode_eisa_id(raw: u32) -> Option<String> {
762 if raw == 0 {
763 return None;
764 }
765 let chars = [
766 (((raw >> 26) & 0x1f) as u8).wrapping_add(b'@'),
767 (((raw >> 21) & 0x1f) as u8).wrapping_add(b'@'),
768 (((raw >> 16) & 0x1f) as u8).wrapping_add(b'@'),
769 ];
770 if !chars.iter().all(u8::is_ascii_uppercase) {
771 return None;
772 }
773 Some(format!(
774 "{}{}{}{:04X}",
775 chars[0] as char,
776 chars[1] as char,
777 chars[2] as char,
778 raw & 0xffff
779 ))
780}
781
782fn acpi_pin(interrupt_pin: u8) -> Result<Pin, OnProbeError> {
783 match interrupt_pin {
784 1 => Ok(Pin::IntA),
785 2 => Ok(Pin::IntB),
786 3 => Ok(Pin::IntC),
787 4 => Ok(Pin::IntD),
788 _ => Err(OnProbeError::other(format!(
789 "invalid PCI interrupt pin {interrupt_pin}"
790 ))),
791 }
792}
793
794fn irq_descriptor_gsi(descriptor: &IrqDescriptor) -> Option<u32> {
795 let irq = descriptor.irq;
796 if !descriptor.is_consumer && irq.count_ones() == 1 && irq <= u16::MAX as u32 {
797 Some(irq.trailing_zeros())
798 } else {
799 Some(irq)
800 }
801}
802
803fn irq_trigger(trigger: InterruptTrigger) -> AcpiIrqTrigger {
804 match trigger {
805 InterruptTrigger::Edge => AcpiIrqTrigger::Edge,
806 InterruptTrigger::Level => AcpiIrqTrigger::Level,
807 }
808}
809
810fn irq_polarity(polarity: InterruptPolarity) -> AcpiIrqPolarity {
811 match polarity {
812 InterruptPolarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
813 InterruptPolarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
814 }
815}
816
817#[cfg(target_arch = "x86_64")]
818fn pci_legacy_read_u8(address: acpi::PciAddress, offset: u16) -> Option<u8> {
819 let value = pci_legacy_read_aligned_u32(address, offset)?;
820 let shift = u32::from(offset & 0b11) * 8;
821 Some((value >> shift) as u8)
822}
823
824#[cfg(not(target_arch = "x86_64"))]
825fn pci_legacy_read_u8(_address: acpi::PciAddress, _offset: u16) -> Option<u8> {
826 None
827}
828
829#[cfg(target_arch = "x86_64")]
830fn pci_legacy_write_u8(address: acpi::PciAddress, offset: u16, value: u8) {
831 let Some(old) = pci_legacy_read_aligned_u32(address, offset) else {
832 return;
833 };
834 let shift = u32::from(offset & 0b11) * 8;
835 let mask = 0xff_u32 << shift;
836 let new = (old & !mask) | (u32::from(value) << shift);
837 pci_legacy_write_aligned_u32(address, offset, new);
838}
839
840#[cfg(not(target_arch = "x86_64"))]
841fn pci_legacy_write_u8(_address: acpi::PciAddress, _offset: u16, _value: u8) {}
842
843#[cfg(target_arch = "x86_64")]
844fn pci_legacy_config_address(address: acpi::PciAddress, offset: u16) -> Option<u32> {
845 if address.segment() != 0 || offset >= 256 {
846 return None;
847 }
848
849 Some(
850 0x8000_0000
851 | (u32::from(address.bus()) << 16)
852 | (u32::from(address.device()) << 11)
853 | (u32::from(address.function()) << 8)
854 | u32::from(offset & !0b11),
855 )
856}
857
858#[cfg(target_arch = "x86_64")]
859fn pci_legacy_read_aligned_u32(address: acpi::PciAddress, offset: u16) -> Option<u32> {
860 let config_address = pci_legacy_config_address(address, offset)?;
861 unsafe {
862 x86::io::outl(0xcf8, config_address);
863 Some(x86::io::inl(0xcfc))
864 }
865}
866
867#[cfg(target_arch = "x86_64")]
868fn pci_legacy_write_aligned_u32(address: acpi::PciAddress, offset: u16, value: u32) {
869 if let Some(config_address) = pci_legacy_config_address(address, offset) {
870 unsafe {
871 x86::io::outl(0xcf8, config_address);
872 x86::io::outl(0xcfc, value);
873 }
874 }
875}
876
877pub fn acpi_trigger(trigger: TriggerMode) -> AcpiIrqTrigger {
878 match trigger {
879 TriggerMode::Edge => AcpiIrqTrigger::Edge,
880 TriggerMode::Level => AcpiIrqTrigger::Level,
881 _ => AcpiIrqTrigger::Level,
882 }
883}
884
885pub fn acpi_polarity(polarity: Polarity) -> AcpiIrqPolarity {
886 match polarity {
887 Polarity::ActiveHigh => AcpiIrqPolarity::ActiveHigh,
888 Polarity::ActiveLow => AcpiIrqPolarity::ActiveLow,
889 _ => AcpiIrqPolarity::ActiveLow,
890 }
891}
892
893#[cfg(target_arch = "x86_64")]
894fn read_io_u8(port: u16) -> u8 {
895 unsafe { x86::io::inb(port) }
896}
897
898#[cfg(not(target_arch = "x86_64"))]
899fn read_io_u8(_port: u16) -> u8 {
900 0
901}
902
903#[cfg(target_arch = "x86_64")]
904fn read_io_u16(port: u16) -> u16 {
905 unsafe { x86::io::inw(port) }
906}
907
908#[cfg(not(target_arch = "x86_64"))]
909fn read_io_u16(_port: u16) -> u16 {
910 0
911}
912
913#[cfg(target_arch = "x86_64")]
914fn read_io_u32(port: u16) -> u32 {
915 unsafe { x86::io::inl(port) }
916}
917
918#[cfg(not(target_arch = "x86_64"))]
919fn read_io_u32(_port: u16) -> u32 {
920 0
921}
922
923#[cfg(target_arch = "x86_64")]
924fn write_io_u8(port: u16, value: u8) {
925 unsafe { x86::io::outb(port, value) }
926}
927
928#[cfg(not(target_arch = "x86_64"))]
929fn write_io_u8(_port: u16, _value: u8) {}
930
931#[cfg(target_arch = "x86_64")]
932fn write_io_u16(port: u16, value: u16) {
933 unsafe { x86::io::outw(port, value) }
934}
935
936#[cfg(not(target_arch = "x86_64"))]
937fn write_io_u16(_port: u16, _value: u16) {}
938
939#[cfg(target_arch = "x86_64")]
940fn write_io_u32(port: u16, value: u32) {
941 unsafe { x86::io::outl(port, value) }
942}
943
944#[cfg(not(target_arch = "x86_64"))]
945fn write_io_u32(_port: u16, _value: u32) {}