| /** @file | |
| Unit tests for DBG2 Generator | |
| Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. <BR> | |
| Copyright (c) Microsoft Corporation. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Library/GoogleTestLib.h> | |
| extern "C" { | |
| #include <Uefi.h> | |
| #include <Protocol/ConfigurationManagerProtocol.h> | |
| #include <Library/FunctionMockLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/TableHelperLib.h> | |
| #include <Library/SsdtSerialPortFixupLib.h> | |
| #include <AcpiTableGenerator.h> | |
| #include <ConfigurationManagerObject.h> | |
| #include <ConfigurationManagerHelper.h> | |
| #include <StandardNameSpaceObjects.h> | |
| #include <IndustryStandard/DebugPort2Table.h> | |
| #include <Protocol/SerialIo.h> | |
| #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<ACPI_TABLE_GENERATOR *>(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<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> &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<CM_ARCH_COMMON_SERIAL_PORT_INFO> mSerialPortInfo; | |
| std::vector<CM_ARCH_COMMON_DBG2_DEVICE_INFO> mDbg2DeviceInfo; | |
| std::vector<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> 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<DeviceTestConfig>, public Dbg2GeneratorTestBase { | |
| protected: | |
| MockConfigurationManagerProtocol MockConfigMgrProtocol; | |
| CM_STD_OBJ_CONFIGURATION_MANAGER_INFO CfgMgrInfo = { 0 }; | |
| CM_STD_OBJ_ACPI_TABLE_INFO mAcpiTableInfo; | |
| std::vector<CM_ARCH_COMMON_DBG2_DEVICE_INFO> mDevices; | |
| std::vector<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> mMemoryRanges; | |
| std::vector<std::vector<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> > mDeviceSpecificRanges; | |
| std::vector<CM_ARCH_COMMON_SERIAL_PORT_INFO> 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<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> 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<CM_ARCH_COMMON_MEMORY_RANGE_DESCRIPTOR> 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<CM_ARCH_COMMON_SERIAL_PORT_INFO> 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 (); | |
| } |