Skip to main content

acpi_lite/
debug_port.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use crate::binary_reader::{BinaryReader, Unaligned};
8use crate::structures::{
9    ACPI_ADDR_SPACE_IO, ACPI_ADDR_SPACE_MEMORY, ACPI_DBG2_SUBTYPE_16550_COMPATIBLE,
10    ACPI_DBG2_TYPE_SERIAL_PORT, AcpiDbg2Device, AcpiDbg2Table, AcpiGenericAddress,
11};
12use crate::{AcpiParserInterface, get_table_by_type};
13use kprint::kprintln;
14use zx_status::Status;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq)]
17pub enum AcpiDebugPortType {
18    Mmio,
19    Pio,
20}
21
22#[derive(Copy, Clone, Debug, Eq, PartialEq)]
23// Describes a dedicated system debug port suitable for low-level
24// debugging and diagnostics.
25//
26// Currently, we only support a 16550-compatible UART using MMIO or PIO.
27pub struct AcpiDebugPortDescriptor {
28    pub r#type: AcpiDebugPortType,
29
30    // Physical address of the 16550 MMIO registers for Type::Mmio.
31    // IO port base for Type::Pio.
32    pub address: usize,
33    pub length: u32,
34}
35
36// Parse an AcpiDbg2Table ACPI structure.
37pub fn parse_acpi_dbg2_table(
38    debug_table: &AcpiDbg2Table,
39) -> Result<AcpiDebugPortDescriptor, Status> {
40    let num_entries = debug_table.num_entries;
41    if num_entries < 1 {
42        kprintln!("acpi_lite: DBG2 table contains no debug ports.");
43        return Err(Status::NOT_FOUND);
44    }
45
46    let offset = debug_table.offset as usize;
47    let mut reader = BinaryReader::from_variable_sized(debug_table);
48    if !reader.skip_bytes(offset) {
49        return Err(Status::INTERNAL);
50    }
51
52    let device = reader.read::<AcpiDbg2Device>().ok_or(Status::INTERNAL)?;
53
54    let port_type = device.port_type;
55    let port_subtype = device.port_subtype;
56    if port_type != ACPI_DBG2_TYPE_SERIAL_PORT || port_subtype != ACPI_DBG2_SUBTYPE_16550_COMPATIBLE
57    {
58        kprintln!(
59            "acpi_lite: DBG2 debug port unsupported. (type={:x}, subtype={:x})",
60            port_type,
61            port_subtype,
62        );
63        return Err(Status::NOT_SUPPORTED);
64    }
65
66    if device.register_count < 1 {
67        kprintln!("acpi_lite: DBG2 debug port doesn't have any registers defined.");
68        return Err(Status::NOT_SUPPORTED);
69    }
70
71    let base_address_offset = device.base_address_offset as usize;
72    let mut reader = BinaryReader::from_variable_sized(device);
73    if !reader.skip_bytes(base_address_offset) {
74        return Err(Status::INTERNAL);
75    }
76    let address = reader.read_fixed_length::<AcpiGenericAddress>().ok_or(Status::INTERNAL)?;
77
78    let address_size_offset = device.address_size_offset as usize;
79    let mut reader = BinaryReader::from_variable_sized(device);
80    if !reader.skip_bytes(address_size_offset) {
81        return Err(Status::INTERNAL);
82    }
83    let length = reader.read_fixed_length::<Unaligned<u32>>().ok_or(Status::INTERNAL)?;
84
85    let addr = address.address as usize;
86    let mut result = AcpiDebugPortDescriptor {
87        r#type: AcpiDebugPortType::Mmio,
88        address: addr,
89        length: length.0,
90    };
91
92    match address.address_space_id {
93        ACPI_ADDR_SPACE_MEMORY => {
94            result.r#type = AcpiDebugPortType::Mmio;
95        }
96        ACPI_ADDR_SPACE_IO => {
97            result.r#type = AcpiDebugPortType::Pio;
98        }
99        _ => {
100            kprintln!(
101                "acpi_lite: Address space unsupported (space_id={:x})",
102                address.address_space_id,
103            );
104            return Err(Status::NOT_SUPPORTED);
105        }
106    }
107
108    Ok(result)
109}
110
111// Lookup low-level debug port information.
112pub fn get_debug_port(parser: &dyn AcpiParserInterface) -> Result<AcpiDebugPortDescriptor, Status> {
113    let debug_table = get_table_by_type::<AcpiDbg2Table>(parser).ok_or_else(|| {
114        kprintln!("acpi_lite: could not find debug port (v2) ACPI entry");
115        Status::NOT_FOUND
116    })?;
117
118    parse_acpi_dbg2_table(debug_table)
119}