1use crate::acpi_lite::printf;
8use crate::binary_reader::{BinaryReader, Unaligned};
9use crate::structures::{
10 ACPI_ADDR_SPACE_IO, ACPI_ADDR_SPACE_MEMORY, ACPI_DBG2_SUBTYPE_16550_COMPATIBLE,
11 ACPI_DBG2_TYPE_SERIAL_PORT, AcpiDbg2Device, AcpiDbg2Table, AcpiGenericAddress,
12};
13use crate::{AcpiParserInterface, get_table_by_type};
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 unsafe {
43 printf(b"acpi_lite: DBG2 table contains no debug ports.\n\0".as_ptr()
44 as *const core::ffi::c_char);
45 }
46 return Err(Status::NOT_FOUND);
47 }
48
49 let offset = debug_table.offset as usize;
50 let mut reader = BinaryReader::from_variable_sized(debug_table);
51 if !reader.skip_bytes(offset) {
52 return Err(Status::INTERNAL);
53 }
54
55 let device = reader.read::<AcpiDbg2Device>().ok_or(Status::INTERNAL)?;
56
57 let port_type = device.port_type;
58 let port_subtype = device.port_subtype;
59 if port_type != ACPI_DBG2_TYPE_SERIAL_PORT || port_subtype != ACPI_DBG2_SUBTYPE_16550_COMPATIBLE
60 {
61 unsafe {
62 printf(
63 b"acpi_lite: DBG2 debug port unsupported. (type=%x, subtype=%x)\n\0".as_ptr()
64 as *const core::ffi::c_char,
65 port_type as core::ffi::c_uint,
66 port_subtype as core::ffi::c_uint,
67 );
68 }
69 return Err(Status::NOT_SUPPORTED);
70 }
71
72 if device.register_count < 1 {
73 unsafe {
74 printf(b"acpi_lite: DBG2 debug port doesn't have any registers defined.\n\0".as_ptr()
75 as *const core::ffi::c_char);
76 }
77 return Err(Status::NOT_SUPPORTED);
78 }
79
80 let base_address_offset = device.base_address_offset as usize;
81 let mut reader = BinaryReader::from_variable_sized(device);
82 if !reader.skip_bytes(base_address_offset) {
83 return Err(Status::INTERNAL);
84 }
85 let address = reader.read_fixed_length::<AcpiGenericAddress>().ok_or(Status::INTERNAL)?;
86
87 let address_size_offset = device.address_size_offset as usize;
88 let mut reader = BinaryReader::from_variable_sized(device);
89 if !reader.skip_bytes(address_size_offset) {
90 return Err(Status::INTERNAL);
91 }
92 let length = reader.read_fixed_length::<Unaligned<u32>>().ok_or(Status::INTERNAL)?;
93
94 let addr = address.address as usize;
95 let mut result = AcpiDebugPortDescriptor {
96 r#type: AcpiDebugPortType::Mmio,
97 address: addr,
98 length: length.0,
99 };
100
101 match address.address_space_id {
102 ACPI_ADDR_SPACE_MEMORY => {
103 result.r#type = AcpiDebugPortType::Mmio;
104 }
105 ACPI_ADDR_SPACE_IO => {
106 result.r#type = AcpiDebugPortType::Pio;
107 }
108 _ => {
109 unsafe {
110 printf(
111 b"acpi_lite: Address space unsupported (space_id=%x)\n\0".as_ptr()
112 as *const core::ffi::c_char,
113 address.address_space_id as core::ffi::c_uint,
114 );
115 }
116 return Err(Status::NOT_SUPPORTED);
117 }
118 }
119
120 Ok(result)
121}
122
123pub fn get_debug_port(parser: &dyn AcpiParserInterface) -> Result<AcpiDebugPortDescriptor, Status> {
125 let debug_table = get_table_by_type::<AcpiDbg2Table>(parser).ok_or_else(|| {
126 unsafe {
127 printf(b"acpi_lite: could not find debug port (v2) ACPI entry\n\0".as_ptr()
128 as *const core::ffi::c_char);
129 }
130 Status::NOT_FOUND
131 })?;
132
133 parse_acpi_dbg2_table(debug_table)
134}