blob: 1c5e0b214d8f2a7c9cb9785e58376d2320fcf656 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/acpi_lite.h>
#include <lib/acpi_lite/debug_port.h>
#include <lib/acpi_lite/structures.h>
#include <lib/zx/result.h>
#include <zircon/types.h>
#include "binary_reader.h"
#include "debug.h"
namespace acpi_lite {
zx::result<AcpiDebugPortDescriptor> ParseAcpiDbg2Table(const AcpiDbg2Table& debug_table) {
// Ensure there is at least one debug port.
if (debug_table.num_entries < 1) {
LOG_INFO("acpi_lite: DBG2 table contains no debug ports.\n");
return zx::error(ZX_ERR_NOT_FOUND);
}
// Read the first device by seeking to |offset| and reading an AcpiDbg2Device.
BinaryReader reader = BinaryReader::FromVariableSizedStruct(&debug_table);
if (!reader.SkipBytes(debug_table.offset)) {
return zx::error(ZX_ERR_INTERNAL);
}
const AcpiDbg2Device* device = reader.Read<AcpiDbg2Device>();
if (device == nullptr) {
return zx::error(ZX_ERR_INTERNAL);
}
// Ensure we are a supported type.
if (device->port_type != ACPI_DBG2_TYPE_SERIAL_PORT ||
device->port_subtype != ACPI_DBG2_SUBTYPE_16550_COMPATIBLE) {
LOG_INFO("acpi_lite: DBG2 debug port unsuported. (type=%x, subtype=%x)\n", device->port_type,
device->port_subtype);
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
// We need at least one register.
if (device->register_count < 1) {
LOG_INFO("acpi_lite: DBG2 debug port doesn't have any registers defined.\n");
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
// Get base address.
reader = BinaryReader::FromVariableSizedStruct(device);
if (!reader.SkipBytes(device->base_address_offset)) {
return zx::error(ZX_ERR_INTERNAL);
}
const AcpiGenericAddress* address = reader.ReadFixedLength<AcpiGenericAddress>();
if (address == nullptr) {
return zx::error(ZX_ERR_INTERNAL);
}
// Get length.
reader = BinaryReader::FromVariableSizedStruct(device);
if (!reader.SkipBytes(device->address_size_offset)) {
return zx::error(ZX_ERR_INTERNAL);
}
const auto* length = reader.ReadFixedLength<Packed<uint32_t>>();
if (length == nullptr) {
return zx::error(ZX_ERR_INTERNAL);
}
AcpiDebugPortDescriptor result = {
.address = static_cast<zx_paddr_t>(address->address),
.length = length->value,
};
switch (address->address_space_id) {
case ACPI_ADDR_SPACE_MEMORY:
result.type = AcpiDebugPortDescriptor::Type::kMmio;
break;
case ACPI_ADDR_SPACE_IO:
result.type = AcpiDebugPortDescriptor::Type::kPio;
break;
default:
LOG_INFO("acpi_lite: Address space unsupported (space_id=%x)\n", address->address_space_id);
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
return zx::success(result);
}
zx::result<AcpiDebugPortDescriptor> GetDebugPort(const AcpiParserInterface& parser) {
// Find the DBG2 table entry.
const AcpiDbg2Table* debug_table = GetTableByType<AcpiDbg2Table>(parser);
if (debug_table == nullptr) {
LOG_INFO("acpi_lite: could not find debug port (v2) ACPI entry\n");
return zx::error(ZX_ERR_NOT_FOUND);
}
return ParseAcpiDbg2Table(*debug_table);
}
} // namespace acpi_lite