/** @file
Unit tests for DBG2 Generator
Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
extern "C" {
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "GoogleTest/Protocol/MockConfigurationManagerProtocol.h"
#include "../Dbg2Generator.h"
#define SERIAL_PORT_BASE_ADDRESS(i) (0x1000ULL * (i + 1))
#define SERIAL_PORT_BASE_ADDRESS_LENGTH (0x1000ULL)
#define SERIAL_PORT_BAUD_RATE (115200)
#define DBG2_BASE_ADDRESS(i) (0x1000ULL * (i + 1))
#define DBG2_BASE_ADDRESS_LENGTH (0x1000ULL)
EFI_STATUS
EFIAPI
AcpiDbg2LibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
EFI_STATUS
EFIAPI
AcpiDbg2LibDestructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
// Global generator instance
static ACPI_TABLE_GENERATOR *gDbg2Generator = NULL;
// C++ wrapper functions for C linkage functions
EFI_STATUS
RegisterAcpiTableGenerator (
IN CONST ACPI_TABLE_GENERATOR *CONST TableGenerator
)
{
if (TableGenerator == NULL) {
return EFI_INVALID_PARAMETER;
}
// Store the generator for use in tests
gDbg2Generator = const_cast(TableGenerator);
return EFI_SUCCESS;
}
EFI_STATUS
DeregisterAcpiTableGenerator (
IN CONST ACPI_TABLE_GENERATOR *CONST TableGenerator
)
{
if (TableGenerator == NULL) {
return EFI_INVALID_PARAMETER;
}
// Clear the stored generator
gDbg2Generator = NULL;
return EFI_SUCCESS;
}
}
using namespace testing;
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::DoAll;
using ::testing::SetArgPointee;
using ::testing::AtLeast;
// Add base class before the test classes
class Dbg2GeneratorTestBase {
protected:
void
ValidateDbg2TableHeader (
IN EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table
)
{
EXPECT_NE (Dbg2Table, nullptr);
EXPECT_EQ (Dbg2Table->Header.Signature, (UINT32)EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE);
EXPECT_EQ (Dbg2Table->Header.Revision, EFI_ACPI_DEBUG_PORT_2_TABLE_REVISION);
EXPECT_EQ (Dbg2Table->Header.OemId[0], (UINT8)'T');
EXPECT_EQ (Dbg2Table->Header.OemId[1], (UINT8)'E');
EXPECT_EQ (Dbg2Table->Header.OemId[2], (UINT8)'S');
EXPECT_EQ (Dbg2Table->Header.OemId[3], (UINT8)'T');
EXPECT_EQ (Dbg2Table->Header.OemId[4], (UINT8)'I');
EXPECT_EQ (Dbg2Table->Header.OemId[5], (UINT8)'D');
}
void
ValidateSerialDeviceInfo (
IN EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo,
IN UINT64 ExpectedBaseAddress,
IN UINT32 ExpectedAddressSize
)
{
EXPECT_EQ (DeviceInfo->Revision, EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION);
EXPECT_EQ (DeviceInfo->PortType, EFI_ACPI_DBG2_PORT_TYPE_SERIAL);
EXPECT_EQ (DeviceInfo->PortSubtype, EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550);
EXPECT_EQ (DeviceInfo->NumberofGenericAddressRegisters, 1U);
// Validate base address register
EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *Gas = (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *)((UINT8 *)DeviceInfo + DeviceInfo->BaseAddressRegisterOffset);
EXPECT_EQ (Gas->AddressSpaceId, (UINT8)EFI_ACPI_6_3_SYSTEM_MEMORY);
EXPECT_EQ (Gas->RegisterBitWidth, 32U);
EXPECT_EQ (Gas->RegisterBitOffset, 0U);
EXPECT_EQ (Gas->AccessSize, (UINT8)EFI_ACPI_6_3_DWORD);
EXPECT_EQ (Gas->Address, ExpectedBaseAddress);
// Validate address size
UINT32 *AddressSize = (UINT32 *)((UINT8 *)DeviceInfo + DeviceInfo->AddressSizeOffset);
EXPECT_EQ (*AddressSize, ExpectedAddressSize);
}
void
ValidateNonSerialDeviceInfo (
IN EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo,
IN const std::vector &MemoryRanges
)
{
EXPECT_EQ (DeviceInfo->Revision, (UINT8)EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION);
// Cast both sides to UINT16 to ensure proper comparison
EXPECT_EQ ((UINT16)DeviceInfo->PortType, (UINT16)EFI_ACPI_DBG2_PORT_TYPE_NET);
EXPECT_EQ (DeviceInfo->PortSubtype, (UINT16)0x0000);
EXPECT_EQ ((UINT32)DeviceInfo->NumberofGenericAddressRegisters, (UINT32)MemoryRanges.size ());
// Validate base address registers
EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *Gas = (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *)((UINT8 *)DeviceInfo + DeviceInfo->BaseAddressRegisterOffset);
// Validate each memory range
for (size_t j = 0; j < MemoryRanges.size (); j++) {
EXPECT_EQ (Gas->AddressSpaceId, (UINT8)EFI_ACPI_6_3_SYSTEM_MEMORY);
EXPECT_EQ (Gas->RegisterBitWidth, (UINT8)32);
EXPECT_EQ (Gas->RegisterBitOffset, (UINT8)0);
EXPECT_EQ (Gas->AccessSize, (UINT8)EFI_ACPI_6_3_DWORD);
EXPECT_EQ (Gas->Address, MemoryRanges[j].BaseAddress);
// Move to next GAS structure
Gas = (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *)((UINT8 *)Gas + sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE));
}
// Validate address sizes
UINT32 *AddressSize = (UINT32 *)((UINT8 *)DeviceInfo + DeviceInfo->AddressSizeOffset);
for (size_t j = 0; j < MemoryRanges.size (); j++) {
EXPECT_EQ (AddressSize[j], MemoryRanges[j].Length);
}
}
void
ValidateSsdtTableHeader (
IN EFI_ACPI_DESCRIPTION_HEADER *SsdtTable
)
{
EXPECT_NE (SsdtTable, nullptr);
EXPECT_EQ (SsdtTable->Signature, (UINT32)EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE);
EXPECT_EQ (SsdtTable->Revision, EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_REVISION);
EXPECT_EQ (SsdtTable->OemId[0], (UINT8)'A');
EXPECT_EQ (SsdtTable->OemId[1], (UINT8)'R');
EXPECT_EQ (SsdtTable->OemId[2], (UINT8)'M');
EXPECT_EQ (SsdtTable->OemId[3], (UINT8)'L');
EXPECT_EQ (SsdtTable->OemId[4], (UINT8)'T');
EXPECT_EQ (SsdtTable->OemId[5], (UINT8)'D');
}
};
// Update test class declarations to inherit from base class
class Dbg2GeneratorTest : public ::testing::Test, public Dbg2GeneratorTestBase {
protected:
MockConfigurationManagerProtocol MockConfigMgrProtocol;
CM_STD_OBJ_CONFIGURATION_MANAGER_INFO CfgMgrInfo = { 0 };
void
SetUp (
) override
{
// Set up default behavior for GetObject
ON_CALL (MockConfigMgrProtocol, GetObject (_, _, _, _))
.WillByDefault (Return (EFI_NOT_FOUND));
// Set up configuration manager info
CfgMgrInfo.Revision = CREATE_REVISION (1, 0);
CfgMgrInfo.OemId[0] = 'T';
CfgMgrInfo.OemId[1] = 'E';
CfgMgrInfo.OemId[2] = 'S';
CfgMgrInfo.OemId[3] = 'T';
CfgMgrInfo.OemId[4] = 'I';
CfgMgrInfo.OemId[5] = 'D';
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo), CM_NULL_TOKEN, _))
.WillRepeatedly (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
sizeof (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO),
&CfgMgrInfo,
1
}
),
Return (EFI_SUCCESS)
)
);
// Initialize the DBG2 library with our mock protocol
EXPECT_EQ (AcpiDbg2LibConstructor (NULL, NULL), EFI_SUCCESS);
// Setup common test data with proper initialization
mAcpiTableInfo.TableGeneratorId = CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdDbg2);
mAcpiTableInfo.AcpiTableSignature = EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE;
mAcpiTableInfo.AcpiTableRevision = EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION;
}
void
TearDown (
) override
{
// Clean up the DBG2 library
AcpiDbg2LibDestructor (NULL, NULL);
}
void
SetupSerialPortInfo (
UINT32 Count
)
{
mSerialPortInfo.resize (Count);
for (UINT32 i = 0; i < Count; i++) {
CM_ARCH_COMMON_SERIAL_PORT_INFO info = { 0 };
info.BaseAddress = SERIAL_PORT_BASE_ADDRESS (i);
info.BaseAddressLength = SERIAL_PORT_BASE_ADDRESS_LENGTH;
info.AccessSize = EFI_ACPI_6_3_DWORD;
info.BaudRate = SERIAL_PORT_BAUD_RATE;
info.PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
mSerialPortInfo[i] = info;
}
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo), CM_NULL_TOKEN, _))
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
(UINT32)sizeof (CM_ARCH_COMMON_SERIAL_PORT_INFO) * Count,
&mSerialPortInfo[0],
Count
}
),
Return (EFI_SUCCESS)
)
);
// Set up expectation for DBG2 device info
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo), CM_NULL_TOKEN, _))
.WillOnce (Return (EFI_NOT_FOUND));
}
void
SetupNonSerialDbg2DeviceInfo (
VOID
)
{
// Set up memory range descriptors
mMemoryRangeDescriptors.clear ();
for (UINT32 i = 0; i < 2; i++) {
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR desc = { 0 };
desc.BaseAddress = DBG2_BASE_ADDRESS (i);
desc.Length = DBG2_BASE_ADDRESS_LENGTH;
mMemoryRangeDescriptors.push_back (desc);
}
// Set up DBG2 device info
mDbg2DeviceInfo.clear ();
CM_ARCH_COMMON_DBG2_DEVICE_INFO info = { 0 };
info.AddressResourceToken = 1; // Unique token for each device
info.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
info.PortSubtype = 0;
info.AccessSize = EFI_ACPI_6_3_DWORD;
CopyMem (info.ObjectName, "DBG2", sizeof ("DBG2"));
mDbg2DeviceInfo.push_back (info);
// Set up mock expectations
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo), CM_NULL_TOKEN, _))
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&mDbg2DeviceInfo[0],
1
}
),
Return (EFI_SUCCESS)
)
);
// Set up mock expectations
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
1,
_
)
).WillOnce (
DoAll (
SetArgPointee<3> (
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR) * 2,
&mMemoryRangeDescriptors[0],
2
}
),
Return (EFI_SUCCESS)
)
);
}
CM_STD_OBJ_ACPI_TABLE_INFO mAcpiTableInfo;
std::vector mSerialPortInfo;
std::vector mDbg2DeviceInfo;
std::vector mMemoryRangeDescriptors;
};
TEST_F (Dbg2GeneratorTest, BuildDbg2TableEx_SingleSerialPort) {
SetupSerialPortInfo (1U);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_SUCCESS
);
EXPECT_NE (Table, nullptr);
EXPECT_EQ (TableCount, 2U);
// Find the DBG2 table
EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table = nullptr;
EFI_ACPI_DESCRIPTION_HEADER *SsdtTable = nullptr;
for (UINTN i = 0; i < TableCount; i++) {
if (Table[i]->Signature == EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE) {
Dbg2Table = (EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *)Table[i];
} else if (Table[i]->Signature == EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
SsdtTable = Table[i];
}
}
ValidateDbg2TableHeader (Dbg2Table);
ValidateSsdtTableHeader (SsdtTable);
// Validate DBG2 table structure
EXPECT_EQ (Dbg2Table->NumberDbgDeviceInfo, 1U);
EXPECT_NE (Dbg2Table->OffsetDbgDeviceInfo, 0U);
// Get pointer to device information structure
EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)Dbg2Table + Dbg2Table->OffsetDbgDeviceInfo);
ValidateSerialDeviceInfo (DeviceInfo, SERIAL_PORT_BASE_ADDRESS (0), SERIAL_PORT_BASE_ADDRESS_LENGTH);
gDbg2Generator->FreeTableResourcesEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
TableCount
);
}
TEST_F (Dbg2GeneratorTest, BuildDbg2TableEx_NoDevices) {
// Setup expectation for no devices
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo), CM_NULL_TOKEN, _))
.WillOnce (Return (EFI_NOT_FOUND));
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo), CM_NULL_TOKEN, _))
.WillOnce (Return (EFI_NOT_FOUND));
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_NOT_FOUND
);
EXPECT_EQ (Table, nullptr);
EXPECT_EQ (TableCount, 0U);
}
TEST_F (Dbg2GeneratorTest, BuildDbg2TableEx_NonSerialDbg2Device) {
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo), CM_NULL_TOKEN, _))
.WillOnce (Return (EFI_NOT_FOUND));
SetupNonSerialDbg2DeviceInfo ();
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_SUCCESS
);
EXPECT_NE (Table, nullptr);
EXPECT_EQ (TableCount, 1U);
// Find the DBG2 table
EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table = nullptr;
for (UINTN i = 0; i < TableCount; i++) {
if (Table[i]->Signature == EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE) {
Dbg2Table = (EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *)Table[i];
break;
}
}
ValidateDbg2TableHeader (Dbg2Table);
// Validate DBG2 table structure
EXPECT_EQ (Dbg2Table->NumberDbgDeviceInfo, 1U);
EXPECT_NE (Dbg2Table->OffsetDbgDeviceInfo, 0U);
// Get pointer to device information structure
EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)Dbg2Table + Dbg2Table->OffsetDbgDeviceInfo);
ValidateNonSerialDeviceInfo (DeviceInfo, mMemoryRangeDescriptors);
gDbg2Generator->FreeTableResourcesEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
TableCount
);
}
// Replace tuple-based test structure with a simpler struct
struct DeviceTestConfig {
UINT32 DeviceCount;
UINT32 RangesPerDevice;
BOOLEAN HasSerialPort; // Changed from SerialPortCount to HasSerialPort since only one port is supported
};
// Update test class declarations to inherit from base class
class Dbg2GeneratorParameterizedTest : public ::testing::TestWithParam, public Dbg2GeneratorTestBase {
protected:
MockConfigurationManagerProtocol MockConfigMgrProtocol;
CM_STD_OBJ_CONFIGURATION_MANAGER_INFO CfgMgrInfo = { 0 };
CM_STD_OBJ_ACPI_TABLE_INFO mAcpiTableInfo;
std::vector mDevices;
std::vector mMemoryRanges;
std::vector > mDeviceSpecificRanges;
std::vector mSerialPortInfo;
void
SetUp (
) override
{
// Set up default behavior for GetObject
ON_CALL (MockConfigMgrProtocol, GetObject (_, _, _, _))
.WillByDefault (Return (EFI_NOT_FOUND));
// Set up configuration manager info
CfgMgrInfo.Revision = CREATE_REVISION (1, 0);
CfgMgrInfo.OemId[0] = 'T';
CfgMgrInfo.OemId[1] = 'E';
CfgMgrInfo.OemId[2] = 'S';
CfgMgrInfo.OemId[3] = 'T';
CfgMgrInfo.OemId[4] = 'I';
CfgMgrInfo.OemId[5] = 'D';
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo), CM_NULL_TOKEN, _))
.WillRepeatedly (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
sizeof (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO),
&CfgMgrInfo,
1
}
),
Return (EFI_SUCCESS)
)
);
// Initialize the DBG2 library with our mock protocol
EXPECT_EQ (AcpiDbg2LibConstructor (NULL, NULL), EFI_SUCCESS);
// Setup common test data
mAcpiTableInfo.TableGeneratorId = CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdDbg2);
mAcpiTableInfo.AcpiTableSignature = EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE;
mAcpiTableInfo.AcpiTableRevision = EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION;
// Set up devices and memory ranges based on test parameters
mDevices.clear ();
mMemoryRanges.clear ();
mDeviceSpecificRanges.clear ();
mSerialPortInfo.clear ();
UINT32 totalRanges = 0;
const DeviceTestConfig &config = GetParam ();
// Set up serial port info if configured
if (config.HasSerialPort) {
mSerialPortInfo.resize (1); // Always create just one serial port
CM_ARCH_COMMON_SERIAL_PORT_INFO info = { 0 };
info.BaseAddress = SERIAL_PORT_BASE_ADDRESS (0);
info.BaseAddressLength = SERIAL_PORT_BASE_ADDRESS_LENGTH;
info.AccessSize = EFI_ACPI_6_3_DWORD;
info.BaudRate = SERIAL_PORT_BAUD_RATE;
info.PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
mSerialPortInfo[0] = info;
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo), CM_NULL_TOKEN, _))
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
sizeof (CM_ARCH_COMMON_SERIAL_PORT_INFO),
&mSerialPortInfo[0],
1
}
),
Return (EFI_SUCCESS)
)
);
} else {
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo), CM_NULL_TOKEN, _))
.WillOnce (Return (EFI_NOT_FOUND));
}
// Create devices
for (UINT32 i = 0; i < config.DeviceCount; i++) {
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = mDevices.size () + 1;
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
CopyMem (device.ObjectName, "DBG2", sizeof (device.ObjectName) - 1);
device.ObjectName[sizeof (device.ObjectName) - 1] = '\0';
mDevices.push_back (device);
// Create memory ranges for this device
std::vector deviceRanges;
for (UINT32 j = 0; j < config.RangesPerDevice; j++) {
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR range = { 0 };
range.BaseAddress = DBG2_BASE_ADDRESS (totalRanges + j);
range.Length = DBG2_BASE_ADDRESS_LENGTH;
deviceRanges.push_back (range);
mMemoryRanges.push_back (range);
}
mDeviceSpecificRanges.push_back (deviceRanges);
totalRanges += config.RangesPerDevice;
}
// Set up mock expectations for DBG2 device info
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo), CM_NULL_TOKEN, _))
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
(UINT32)(sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO) * mDevices.size ()),
&mDevices[0],
(UINT32)mDevices.size ()
}
),
Return (EFI_SUCCESS)
)
);
// Set up mock expectations for memory range descriptors
for (size_t i = 0; i < mDevices.size (); i++) {
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
mDevices[i].AddressResourceToken,
_
)
).WillOnce (
DoAll (
SetArgPointee<3> (
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
(UINT32)(sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR) * mDeviceSpecificRanges[i].size ()),
&mDeviceSpecificRanges[i][0],
(UINT32)mDeviceSpecificRanges[i].size ()
}
),
Return (EFI_SUCCESS)
)
);
}
}
void
TearDown (
) override
{
// Clean up the DBG2 library
AcpiDbg2LibDestructor (NULL, NULL);
}
};
TEST_P (Dbg2GeneratorParameterizedTest, BuildDbg2TableEx_MultipleNonSerialDevices) {
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_SUCCESS
);
EXPECT_NE (Table, nullptr);
EXPECT_EQ (TableCount, GetParam ().HasSerialPort ? 2U : 1U);
// Find the DBG2 table
EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table = nullptr;
EFI_ACPI_DESCRIPTION_HEADER *SsdtTable = nullptr;
for (UINTN i = 0; i < TableCount; i++) {
if (Table[i]->Signature == EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE) {
Dbg2Table = (EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *)Table[i];
} else if (Table[i]->Signature == EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
SsdtTable = Table[i];
}
}
ValidateDbg2TableHeader (Dbg2Table);
// Validate DBG2 table structure
UINT32 expectedDeviceCount = (UINT32)(mDevices.size () + (GetParam ().HasSerialPort ? 1 : 0));
EXPECT_EQ (Dbg2Table->NumberDbgDeviceInfo, expectedDeviceCount);
EXPECT_NE (Dbg2Table->OffsetDbgDeviceInfo, 0U);
// Get pointer to first device information structure
EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)Dbg2Table + Dbg2Table->OffsetDbgDeviceInfo);
// Validate each device
for (size_t i = 0; i < mDevices.size (); i++) {
ValidateNonSerialDeviceInfo (DeviceInfo, mDeviceSpecificRanges[i]);
DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)DeviceInfo + DeviceInfo->Length);
}
// Validate SSDT table if present
if (GetParam ().HasSerialPort) {
ValidateSsdtTableHeader (SsdtTable);
}
gDbg2Generator->FreeTableResourcesEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
TableCount
);
}
INSTANTIATE_TEST_SUITE_P (
Dbg2GeneratorTests,
Dbg2GeneratorParameterizedTest,
::testing::Values (
DeviceTestConfig { 1, 2, false }, // 1 device, 2 ranges per device, no serial port
DeviceTestConfig { 2, 3, false }, // 2 devices, 3 ranges per device, no serial port
DeviceTestConfig { 2, 2, true } // 2 devices, 2 ranges per device, with serial port
)
);
// Test class for adversarial test cases
class Dbg2GeneratorAdversarialTest : public ::testing::Test, public Dbg2GeneratorTestBase {
protected:
MockConfigurationManagerProtocol MockConfigMgrProtocol;
CM_STD_OBJ_CONFIGURATION_MANAGER_INFO CfgMgrInfo = { 0 };
CM_STD_OBJ_ACPI_TABLE_INFO mAcpiTableInfo;
void
SetUp (
) override
{
// Set up default behavior for GetObject
ON_CALL (MockConfigMgrProtocol, GetObject (_, _, _, _))
.WillByDefault (Return (EFI_NOT_FOUND));
// Set up configuration manager info
CfgMgrInfo.Revision = CREATE_REVISION (1, 0);
CfgMgrInfo.OemId[0] = 'T';
CfgMgrInfo.OemId[1] = 'E';
CfgMgrInfo.OemId[2] = 'S';
CfgMgrInfo.OemId[3] = 'T';
CfgMgrInfo.OemId[4] = 'I';
CfgMgrInfo.OemId[5] = 'D';
EXPECT_CALL (MockConfigMgrProtocol, GetObject (_, CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo), CM_NULL_TOKEN, _))
.WillRepeatedly (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
sizeof (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO),
&CfgMgrInfo,
1
}
),
Return (EFI_SUCCESS)
)
);
// Initialize the DBG2 library with our mock protocol
EXPECT_EQ (AcpiDbg2LibConstructor (NULL, NULL), EFI_SUCCESS);
// Setup common test data
mAcpiTableInfo.TableGeneratorId = CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdDbg2);
mAcpiTableInfo.AcpiTableSignature = EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE;
mAcpiTableInfo.AcpiTableRevision = EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION;
}
void
TearDown (
) override
{
// Clean up the DBG2 library
AcpiDbg2LibDestructor (NULL, NULL);
}
};
// Test invalid memory range base address (0)
TEST_F (Dbg2GeneratorAdversarialTest, InvalidMemoryRangeBaseAddress) {
// Set up DBG2 device info
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = 1;
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
// Set up memory range with invalid base address
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR range = { 0 };
range.BaseAddress = 0; // Invalid - must be non-zero
range.Length = DBG2_BASE_ADDRESS_LENGTH;
// Mock serial port info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
// Mock DBG2 device info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&device,
1
}
),
Return (EFI_SUCCESS)
)
);
// Mock memory range descriptor query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
1,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR),
&range,
1
}
),
Return (EFI_SUCCESS)
)
);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_INVALID_PARAMETER
);
}
// Test memory range length too large
TEST_F (Dbg2GeneratorAdversarialTest, MemoryRangeTooLarge) {
// Set up DBG2 device info
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = 1;
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
// Set up memory range with length > MAX_UINT32
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR range = { 0 };
range.BaseAddress = DBG2_BASE_ADDRESS (0);
range.Length = ((UINT64)MAX_UINT32) + 1; // Too large for DBG2 table
// Mock serial port info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
// Mock DBG2 device info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&device,
1
}
),
Return (EFI_SUCCESS)
)
);
// Mock memory range descriptor query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
1,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR),
&range,
1
}
),
Return (EFI_SUCCESS)
)
);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_INVALID_PARAMETER
);
}
// Test too many memory ranges
TEST_F (Dbg2GeneratorAdversarialTest, TooManyMemoryRanges) {
// Set up DBG2 device info
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = 1;
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
// Create array of memory ranges with count > MAX_UINT8
std::vector ranges;
for (UINT32 i = 0; i <= MAX_UINT8 + 1; i++) {
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR range = { 0 };
range.BaseAddress = DBG2_BASE_ADDRESS (i);
range.Length = DBG2_BASE_ADDRESS_LENGTH;
ranges.push_back (range);
}
// Mock serial port info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
// Mock DBG2 device info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&device,
1
}
),
Return (EFI_SUCCESS)
)
);
// Mock memory range descriptor query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
1,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
(UINT32)(sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR) * ranges.size ()),
ranges.data (),
(UINT32)ranges.size ()
}
),
Return (EFI_SUCCESS)
)
);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_INVALID_PARAMETER
);
}
// Test invalid resource token
TEST_F (Dbg2GeneratorAdversarialTest, InvalidResourceToken) {
// Set up DBG2 device info with CM_NULL_TOKEN for AddressResourceToken
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = CM_NULL_TOKEN; // Invalid - must be non-zero
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
// Mock serial port info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
// Mock DBG2 device info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&device,
1
}
),
Return (EFI_SUCCESS)
)
);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_INVALID_PARAMETER
);
}
// Test invalid serial port access size
TEST_F (Dbg2GeneratorAdversarialTest, InvalidSerialPortAccessSize) {
CM_ARCH_COMMON_SERIAL_PORT_INFO serialPort = { 0 };
serialPort.BaseAddress = SERIAL_PORT_BASE_ADDRESS (0);
serialPort.BaseAddressLength = SERIAL_PORT_BASE_ADDRESS_LENGTH;
serialPort.AccessSize = EFI_ACPI_6_3_QWORD; // Invalid - must be <= DWORD
serialPort.BaudRate = SERIAL_PORT_BAUD_RATE;
serialPort.PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
// Mock serial port info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
sizeof (CM_ARCH_COMMON_SERIAL_PORT_INFO),
&serialPort,
1
}
),
Return (EFI_SUCCESS)
)
);
// Mock DBG2 device info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_INVALID_PARAMETER
);
}
// Test non-serial DBG2 device with missing object name (should default to ".")
TEST_F (Dbg2GeneratorAdversarialTest, MissingObjectName) {
// Set up DBG2 device info with empty object name
CM_ARCH_COMMON_DBG2_DEVICE_INFO device = { 0 };
device.AddressResourceToken = 1;
device.PortType = EFI_ACPI_DBG2_PORT_TYPE_NET;
device.PortSubtype = 0;
device.AccessSize = EFI_ACPI_6_3_DWORD;
// Intentionally leave ObjectName empty
// Set up memory range
CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR range = { 0 };
range.BaseAddress = DBG2_BASE_ADDRESS (0);
range.Length = DBG2_BASE_ADDRESS_LENGTH;
// Mock serial port info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
// Mock DBG2 device info query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
sizeof (CM_ARCH_COMMON_DBG2_DEVICE_INFO),
&device,
1
}
),
Return (EFI_SUCCESS)
)
);
// Mock memory range descriptor query
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
1,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjMemoryRangeDescriptor),
sizeof (CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR),
&range,
1
}
),
Return (EFI_SUCCESS)
)
);
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_SUCCESS
);
EXPECT_NE (Table, nullptr);
EXPECT_EQ (TableCount, 1U);
// Find the DBG2 table
EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table = nullptr;
for (UINTN i = 0; i < TableCount; i++) {
if (Table[i]->Signature == EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE) {
Dbg2Table = (EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *)Table[i];
break;
}
}
ValidateDbg2TableHeader (Dbg2Table);
// Validate DBG2 table structure
EXPECT_EQ (Dbg2Table->NumberDbgDeviceInfo, 1U);
EXPECT_NE (Dbg2Table->OffsetDbgDeviceInfo, 0U);
// Get pointer to device information structure
EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)Dbg2Table + Dbg2Table->OffsetDbgDeviceInfo);
// Validate device info
EXPECT_EQ (DeviceInfo->Revision, EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION);
EXPECT_EQ ((UINT16)DeviceInfo->PortType, (UINT16)EFI_ACPI_DBG2_PORT_TYPE_NET);
EXPECT_EQ (DeviceInfo->PortSubtype, (UINT16)0x0000);
EXPECT_EQ (DeviceInfo->NumberofGenericAddressRegisters, 1U);
// Validate that the name string is "."
CHAR8 *NameString = (CHAR8 *)((UINT8 *)DeviceInfo + DeviceInfo->NameSpaceStringOffset);
EXPECT_EQ (NameString[0], '.');
EXPECT_EQ (NameString[1], '\0');
// Validate memory range
EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *Gas = (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *)((UINT8 *)DeviceInfo + DeviceInfo->BaseAddressRegisterOffset);
EXPECT_EQ (Gas->AddressSpaceId, (UINT8)EFI_ACPI_6_3_SYSTEM_MEMORY);
EXPECT_EQ (Gas->RegisterBitWidth, (UINT8)32);
EXPECT_EQ (Gas->RegisterBitOffset, (UINT8)0);
EXPECT_EQ (Gas->AccessSize, (UINT8)EFI_ACPI_6_3_DWORD);
EXPECT_EQ (Gas->Address, range.BaseAddress);
// Validate address size
UINT32 *AddressSize = (UINT32 *)((UINT8 *)DeviceInfo + DeviceInfo->AddressSizeOffset);
EXPECT_EQ (*AddressSize, range.Length);
gDbg2Generator->FreeTableResourcesEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
TableCount
);
}
// Test multiple serial ports where only first one is used
TEST_F (Dbg2GeneratorTest, MultipleSerialPorts) {
// Create two serial ports
std::vector serialPorts;
// First serial port
CM_ARCH_COMMON_SERIAL_PORT_INFO port1 = { 0 };
port1.BaseAddress = SERIAL_PORT_BASE_ADDRESS (0);
port1.BaseAddressLength = SERIAL_PORT_BASE_ADDRESS_LENGTH;
port1.AccessSize = EFI_ACPI_6_3_DWORD;
port1.BaudRate = SERIAL_PORT_BAUD_RATE;
port1.PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
serialPorts.push_back (port1);
// Second serial port
CM_ARCH_COMMON_SERIAL_PORT_INFO port2 = { 0 };
port2.BaseAddress = SERIAL_PORT_BASE_ADDRESS (1);
port2.BaseAddressLength = SERIAL_PORT_BASE_ADDRESS_LENGTH;
port2.AccessSize = EFI_ACPI_6_3_DWORD;
port2.BaudRate = SERIAL_PORT_BAUD_RATE;
port2.PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
serialPorts.push_back (port2);
// Mock serial port info query to return both ports
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (
DoAll (
SetArgPointee<3>(
CM_OBJ_DESCRIPTOR {
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjSerialDebugPortInfo),
(UINT32)(sizeof (CM_ARCH_COMMON_SERIAL_PORT_INFO) * serialPorts.size ()),
serialPorts.data (),
(UINT32)serialPorts.size ()
}
),
Return (EFI_SUCCESS)
)
);
// Mock DBG2 device info query to return not found
EXPECT_CALL (
MockConfigMgrProtocol,
GetObject (
_,
CREATE_CM_ARCH_COMMON_OBJECT_ID (EArchCommonObjGenericDbg2DeviceInfo),
CM_NULL_TOKEN,
_
)
)
.WillOnce (Return (EFI_NOT_FOUND));
EFI_ACPI_DESCRIPTION_HEADER **Table = nullptr;
UINTN TableCount = 0;
EXPECT_EQ (
gDbg2Generator->BuildAcpiTableEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
&TableCount
),
EFI_SUCCESS
);
EXPECT_NE (Table, nullptr);
EXPECT_EQ (TableCount, 2U); // DBG2 table and SSDT table
// Find the DBG2 table
EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *Dbg2Table = nullptr;
EFI_ACPI_DESCRIPTION_HEADER *SsdtTable = nullptr;
for (UINTN i = 0; i < TableCount; i++) {
if (Table[i]->Signature == EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE) {
Dbg2Table = (EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE *)Table[i];
} else if (Table[i]->Signature == EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
SsdtTable = Table[i];
}
}
ValidateDbg2TableHeader (Dbg2Table);
ValidateSsdtTableHeader (SsdtTable);
// Validate DBG2 table structure - should only have one device
EXPECT_EQ (Dbg2Table->NumberDbgDeviceInfo, 1U);
EXPECT_NE (Dbg2Table->OffsetDbgDeviceInfo, 0U);
// Get pointer to device information structure
EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *DeviceInfo = (EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT *)((UINT8 *)Dbg2Table + Dbg2Table->OffsetDbgDeviceInfo);
// Validate that only the first serial port is included
ValidateSerialDeviceInfo (DeviceInfo, port1.BaseAddress, (UINT32)port1.BaseAddressLength);
gDbg2Generator->FreeTableResourcesEx (
gDbg2Generator,
&mAcpiTableInfo,
gConfigurationManagerProtocol,
&Table,
TableCount
);
}
int
main (
int argc,
char *argv[]
)
{
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}