1use 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)]
23pub struct AcpiDebugPortDescriptor {
28 pub r#type: AcpiDebugPortType,
29
30 pub address: usize,
33 pub length: u32,
34}
35
36pub 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
111pub 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}