blob: 112084a9d3ce2a0e2ec36066d2ae1904f3e1e48e [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/acpi_lite/debug_port.h>
#include <lib/uart/all.h>
#include <lib/uart/amlogic.h>
#include <lib/uart/ns8250.h>
#include <lib/zbi-format/driver-config.h>
#include <string>
#include <zxtest/zxtest.h>
#include "../parse.h"
namespace {
#if defined(__i386__) || defined(__x86_64__)
constexpr bool kX86 = true;
#else
constexpr bool kX86 = false;
#endif
template <typename Uint>
void TestOneUint() {
// No leading comma.
{
Uint u{0xe};
EXPECT_FALSE(uart::internal::ParseInts("", &u));
}
// Fewer elements than integers.
{
Uint u{0xe};
EXPECT_FALSE(uart::internal::ParseInts(",", &u));
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",12", &u));
EXPECT_EQ(12, u);
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",-12", &u));
EXPECT_EQ(static_cast<Uint>(-12), u);
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",0xa", &u));
EXPECT_EQ(0xa, u);
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",-0xa", &u));
EXPECT_EQ(static_cast<Uint>(-0xa), u);
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",010", &u));
EXPECT_EQ(8, u);
}
{
Uint u{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",-010", &u));
EXPECT_EQ(static_cast<Uint>(-8), u);
}
// More elements than integers.
{
Uint u{0xe};
EXPECT_FALSE(uart::internal::ParseInts(",12,34", &u));
}
}
template <typename UintA, typename UintB>
void TestTwoUints() {
// No leading comma.
{
UintA uA{0xe};
UintB uB{0xe};
EXPECT_FALSE(uart::internal::ParseInts("", &uA, &uB));
}
// Fewer elements than integers: no elements.
{
UintA uA{0xe};
UintB uB{0xe};
EXPECT_FALSE(uart::internal::ParseInts(",", &uA, &uB));
}
// Fewer elements than integers: one element.
{
UintA uA{0xe};
UintB uB{0xe};
EXPECT_FALSE(uart::internal::ParseInts(",12", &uA, &uB));
}
{
UintA uA{0xe};
UintB uB{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",12,34", &uA, &uB));
EXPECT_EQ(12, uA);
EXPECT_EQ(34, uB);
}
{
UintA uA{0xe};
UintB uB{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",0x12,34", &uA, &uB));
EXPECT_EQ(0x12, uA);
EXPECT_EQ(34, uB);
}
{
UintA uA{0xe};
UintB uB{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",12,0x34", &uA, &uB));
EXPECT_EQ(12, uA);
EXPECT_EQ(0x34, uB);
}
{
UintA uA{0xe};
UintB uB{0xe};
ASSERT_TRUE(uart::internal::ParseInts(",0x12,0x34", &uA, &uB));
EXPECT_EQ(0x12, uA);
EXPECT_EQ(0x34, uB);
}
// More elements than integers.
{
UintA uA;
UintB uB;
EXPECT_FALSE(uart::internal::ParseInts(",12,34,56", &uA, &uB));
}
}
TEST(ParsingTests, NoUints) {
EXPECT_TRUE(uart::internal::ParseInts(""));
EXPECT_FALSE(uart::internal::ParseInts(",12"));
EXPECT_FALSE(uart::internal::ParseInts(",12,34"));
}
TEST(ParsingTests, ParsingLargeValues) {
{
uint64_t u64{0xe};
EXPECT_TRUE(uart::internal::ParseInts(",0xffffffffffffffff", &u64));
EXPECT_EQ(static_cast<uint64_t>(-1), u64);
}
{
uint64_t u64{0xe};
EXPECT_TRUE(uart::internal::ParseInts(",0x0123456789", &u64));
EXPECT_EQ(0x0123456789, u64);
}
}
TEST(ParsingTests, Overflow) {
{
uint8_t u8{0xe};
EXPECT_TRUE(uart::internal::ParseInts(",0xabc", &u8));
EXPECT_EQ(0xbc, u8);
}
{
uint8_t u8{0xe};
EXPECT_TRUE(uart::internal::ParseInts(",0x100", &u8));
EXPECT_EQ(0x00, u8);
}
}
TEST(ParsingTests, ParsingLongStrings) {
std::string waylong(",");
waylong += std::string(100, '0'); // Longer than any integer size needs.
waylong += "52";
uint8_t u8{};
EXPECT_TRUE(uart::internal::ParseInts(waylong, &u8));
EXPECT_EQ(052, u8);
waylong[2] = 'x';
EXPECT_TRUE(uart::internal::ParseInts(waylong, &u8));
EXPECT_EQ(0x52, u8);
std::string longoverflow(",");
longoverflow += std::string(100, '1'); // Extreme overflow.
uint64_t u64{};
EXPECT_FALSE(uart::internal::ParseInts(longoverflow, &u64));
}
TEST(ParsingTests, OneUint8) { ASSERT_NO_FATAL_FAILURE(TestOneUint<uint8_t>()); }
TEST(ParsingTests, OneUint16) { ASSERT_NO_FATAL_FAILURE(TestOneUint<uint16_t>()); }
TEST(ParsingTests, OneUint32) { ASSERT_NO_FATAL_FAILURE(TestOneUint<uint32_t>()); }
TEST(ParsingTests, OneUint64) { ASSERT_NO_FATAL_FAILURE(TestOneUint<uint64_t>()); }
TEST(ParsingTests, TwoUint8s) {
auto test = TestTwoUints<uint8_t, uint8_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint8AndUint16) {
auto test = TestTwoUints<uint8_t, uint16_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint8AndUint32) {
auto test = TestTwoUints<uint8_t, uint32_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint8AndUint64) {
auto test = TestTwoUints<uint8_t, uint32_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, TwoUint16s) {
auto test = TestTwoUints<uint16_t, uint16_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint16AndUint32) {
auto test = TestTwoUints<uint16_t, uint32_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint16AndUint64) {
auto test = TestTwoUints<uint16_t, uint64_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, TwoUint32s) {
auto test = TestTwoUints<uint32_t, uint32_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, Uint32AndUint64) {
auto test = TestTwoUints<uint32_t, uint64_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
TEST(ParsingTests, TwoUint64s) {
auto test = TestTwoUints<uint64_t, uint64_t>;
ASSERT_NO_FATAL_FAILURE(test());
}
// Currently only these two are supported.
acpi_lite::AcpiDebugPortDescriptor kMmioDebugPort = {
.type = acpi_lite::AcpiDebugPortDescriptor::Type::kMmio,
.address = 1234,
.length = 4,
};
acpi_lite::AcpiDebugPortDescriptor kPioDebugPort = {
.type = acpi_lite::AcpiDebugPortDescriptor::Type::kPio,
.address = 4321,
.length = 2,
};
template <typename T, bool Matches, typename U>
void CheckMaybeCreateFromAcpi(const U& debug_port) {
auto driver = T::MaybeCreate(debug_port);
if constexpr (Matches) {
ASSERT_TRUE(driver);
if constexpr (std::is_same_v<decltype(driver->config()), zbi_dcfg_simple_t>) {
EXPECT_EQ(driver->config().mmio_phys, debug_port.address);
}
if constexpr (std::is_same_v<decltype(driver->config()), zbi_dcfg_simple_pio_t>) {
EXPECT_EQ(driver->config().base, debug_port.address);
}
} else {
ASSERT_FALSE(driver);
}
}
TEST(ParsingTests, Ns8250MmioDriver) {
auto driver = uart::ns8250::Mmio32Driver::MaybeCreate(kX86 ? "mmio,0xa,0xb" : "ns8250,0xa,0xb");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ(kX86 ? "mmio" : "ns8250", driver->config_name());
const zbi_dcfg_simple_t& config = driver->config();
EXPECT_EQ(0xa, config.mmio_phys);
EXPECT_EQ(0xb, config.irq);
CheckMaybeCreateFromAcpi<uart::ns8250::Mmio32Driver, true>(kMmioDebugPort);
CheckMaybeCreateFromAcpi<uart::ns8250::Mmio32Driver, false>(kPioDebugPort);
}
TEST(ParsingTests, Ns82508BMmioDriver) {
auto driver = uart::ns8250::Mmio8Driver::MaybeCreate("ns8250-8bit,0xa,0xb");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("ns8250-8bit", driver->config_name());
const zbi_dcfg_simple_t& config = driver->config();
EXPECT_EQ(0xa, config.mmio_phys);
EXPECT_EQ(0xb, config.irq);
}
TEST(ParsingTests, Ns8250PioDriver) {
auto driver = uart::ns8250::PioDriver::MaybeCreate("ioport,0xa,0xb");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("ioport", driver->config_name());
const zbi_dcfg_simple_pio_t& config = driver->config();
EXPECT_EQ(0xa, config.base);
EXPECT_EQ(0xb, config.irq);
CheckMaybeCreateFromAcpi<uart::ns8250::PioDriver, false>(kMmioDebugPort);
CheckMaybeCreateFromAcpi<uart::ns8250::PioDriver, true>(kPioDebugPort);
}
TEST(ParsingTests, Ns8250LegacyDriver) {
auto driver = uart::ns8250::PioDriver::MaybeCreate("legacy");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("ioport", driver->config_name());
const zbi_dcfg_simple_pio_t& config = driver->config();
EXPECT_EQ(0x3f8, config.base);
EXPECT_EQ(4, config.irq);
}
TEST(ParsingTests, Pl011Driver) {
auto driver = uart::pl011::Driver::MaybeCreate("pl011,0xa,0xb");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("pl011", driver->config_name());
const zbi_dcfg_simple_t& config = driver->config();
EXPECT_EQ(0xa, config.mmio_phys);
EXPECT_EQ(0xb, config.irq);
CheckMaybeCreateFromAcpi<uart::pl011::Driver, false>(kMmioDebugPort);
CheckMaybeCreateFromAcpi<uart::pl011::Driver, false>(kPioDebugPort);
}
TEST(ParsingTests, Pl011QemuDriver) {
auto driver = uart::pl011::Driver::MaybeCreate("qemu");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("pl011", driver->config_name());
const zbi_dcfg_simple_t& config = driver->config();
EXPECT_EQ(0x09000000, config.mmio_phys);
EXPECT_EQ(33, config.irq);
}
TEST(ParsingTests, AmlogicDriver) {
auto driver = uart::amlogic::Driver::MaybeCreate("amlogic,0xa,0xb");
ASSERT_TRUE(driver.has_value());
EXPECT_STREQ("amlogic", driver->config_name());
const zbi_dcfg_simple_t& config = driver->config();
EXPECT_EQ(0xa, config.mmio_phys);
EXPECT_EQ(0xb, config.irq);
CheckMaybeCreateFromAcpi<uart::amlogic::Driver, false>(kMmioDebugPort);
CheckMaybeCreateFromAcpi<uart::amlogic::Driver, false>(kPioDebugPort);
}
} // namespace