Newer
Older
AMI-Aptio-BIOS-Reversed / CpRcPkg / Uba / CfgDb / Dxe / CfgDbDxe / UbaConfigDatabaseDxe.c
@Ajax Dong Ajax Dong 2 days ago 32 KB Restructure the repo
/** @file UbaConfigDatabaseDxe - Lenovo HR650X UBA Configuration Database DXE driver.

 This module implements a UEFI driver that provides a configuration database service for the Lenovo UBA (Universal BIOS Architecture) framework. It stores,
 retrieves, and manages configuration data identified by GUIDs, persisted via HOB (Hand-Off Block) during the DXE phase.

 The driver installs a protocol interface (gUbaConfigDatabaseProtocolGuid) with three main operations: GetInfo, SetData, and GetData for GUID-keyed config entries.

 Copyright (c) Lenovo. All rights reserved.
 SPDX-License-Identifier: BSD-2-Clause-Patent Source path: CpPlatPkg\Uba\CfgDb\Dxe\CfgDbDxe.c
**/

//
// Include UEFI types
//
typedef unsigned long long UINT64;
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
typedef signed long long INT64;
typedef signed int INT32;
typedef signed short INT16;
typedef signed char INT8;
typedef long long INTN;
typedef unsigned long long UINTN;
typedef char CHAR8;
typedef UINT16 CHAR16;
typedef void VOID;
typedef int BOOLEAN;
typedef UINTN EFI_STATUS;
typedef UINT16 *EFI_HANDLE;
typedef UINT64 EFI_PHYSICAL_ADDRESS;
typedef UINTN EFI_EVENT;
typedef UINT64 EFI_LBA;
typedef UINTN EFI_TPL;
typedef UINT64 UINT64_ALIGNED;

#define EFIAPI 
#define IN
#define OUT
#define OPTIONAL

//
// EFI_STATUS codes
//
#define EFI_SUCCESS 0
#define EFI_ERR_BASE 0x8000000000000000ULL
#define EFI_INVALID_PARAMETER (EFI_ERR_BASE | 2)
#define EFI_UNSUPPORTED (EFI_ERR_BASE | 3)
#define EFI_BUFFER_TOO_SMALL (EFI_ERR_BASE | 5)
#define EFI_NOT_FOUND (EFI_ERR_BASE | 14)
#define EFI_OUT_OF_RESOURCES (EFI_ERR_BASE | 9)
#define EFI_ALREADY_STARTED (EFI_ERR_BASE | 25)

//
// EFI_GUID structure (16 bytes)
//
typedef struct {
 UINT32 Data1;
 UINT16 Data2;
 UINT16 Data3;
 UINT8 Data4[8];
} EFI_GUID;

//
// EFI_SYSTEM_TABLE (abbreviated for this module)
//
typedef struct {
 char _pad0[0x60]; // 0x00 - 0x5F: header, firmware vendor, etc.
 VOID *BootServices; // 0x60 VOID *RuntimeServices; // 0x68
 // ... more fields follow
} EFI_SYSTEM_TABLE;

//
// EFI_BOOT_SERVICES (function table at offset 0x60 from SystemTable)
// Only the entries used by this module are defined.
//
typedef struct {
 char _pad0[0x18]; // 0x00 - 0x17: RaiseTPL, RestoreTPL, AllocatePages, FreePages UINT64 (*GetMemoryMap)(UINTN *MemoryMapSize, VOID *MemoryMap, UINTN *MapKey, UINTN *DescriptorSize, UINT32 *DescriptorVersion); // 0x18 UINT64 (*AllocatePool)(UINTN PoolType, UINTN Size, VOID **Buffer); // 0x20 (index 4)
 UINT64 (*FreePool)(VOID *Buffer); // 0x28 char _pad1[0x18]; // 0x30 - 0x47 UINT64 (*InstallProtocolInterface)(EFI_HANDLE *Handle, EFI_GUID *Protocol, UINTN InterfaceType, VOID *Interface); // 0x48 (index 9)
 char _pad2[0x38]; // 0x50 - 0x87 UINT64 (*LocateProtocol)(EFI_GUID *Protocol, VOID *Registration, VOID **Interface); // 0x88 (index 17)
 char _pad3[0x48]; // 0x90 - 0xD7 UINT64 (*InstallMultipleProtocolInterfaces)(VOID *...); // 0xD8 (index 27)
 char _pad4[0x20]; // 0xE0 - 0xFF
} EFI_BOOT_SERVICES;

//
// EFI_RUNTIME_SERVICES (function table at offset 0x68 from SystemTable)
//
typedef struct {
 char _pad[0x60];
} EFI_RUNTIME_SERVICES;

//
// LIST_ENTRY - standard UEFI doubly-linked list
//
typedef struct _LIST_ENTRY {
 struct _LIST_ENTRY *ForwardLink;
 struct _LIST_ENTRY *BackLink;
} LIST_ENTRY;

//
// UBA_CONFIG_NODE - a single configuration data node in the linked list
// Signature: 0x44534255 ("UBAD" = UBA Database)
//
// Structure layout:
// 0x00: Signature (UINT32) = 0x44534255
// 0x04: Version (UINT32) = 1
// 0x08: LIST_ENTRY Link (forward/back pointers)
// 0x18: ConfigData pointer (VOID*) - points to a sibling node's config data when linked
// 0x1C: ConfigGuid (EFI_GUID, 16 bytes) - GUID identifying this config entry
// 0x2C: ConfigNameStr (CHAR8[16]) - human-readable name
// 0x3C: ConfigDataSize (UINT32) - size of config data
// 0x40: ConfigData (VOID*) - pointer to the actual configuration data
// 0x48: NodeCount (UINT32) - number of entries in this database
// Total: 0x4C bytes
//
typedef struct {
 UINT32 Signature; // 0x00: "UBAD"
 UINT32 Version; // 0x04 LIST_ENTRY Link; // 0x08 VOID *ConfigDataRef; // 0x18 EFI_GUID ConfigGuid; // 0x1C CHAR8 ConfigName[16]; // 0x2C UINT32 ConfigDataSize; // 0x3C VOID *ConfigData; // 0x40 UINT32 NodeCount; // 0x48
} UBA_CONFIG_NODE;

//
// UBA_CONFIG_DATABASE_PRIVATE - private structure for the config database
// Signature: 0x44534255 ("UBAD" = UBA Database)
//
// Structure layout:
// 0x00: Signature (UINT32) = 0x44534255
// 0x04: Version (UINT32) = 1
// 0x08: TotalConfigDataSize (UINT64) - total size of all config data entries
// 0x10: ConfigCount (UINT64) - count of configuration entries
// 0x18: EntryCount (UINT64) - count of entries total
// 0x1C: ConfigGuid (EFI_GUID, 16 bytes) - protocol GUID for installed interface
// 0x2C: GetInfo (function pointer)
// 0x34: SetData (function pointer)
// 0x3C: GetData (function pointer)
// Total: 0x44 bytes
//
typedef struct {
 UINT32 Signature; // 0x00: "UBAD"
 UINT32 Version; // 0x04: 1 UINT64 TotalConfigDataSize; // 0x08 UINT64 ConfigCount; // 0x10 UINT64 EntryCount; // 0x18 EFI_GUID ConfigGuid; // 0x1C
 // Protocol interface starts here EFI_STATUS (*GetInfo)(VOID *This, UINT32 *ConfigCount, CHAR8 *ConfigGuid, UINTN *ConfigDataSize); // 0x2C EFI_STATUS (*SetData)(VOID *This, EFI_GUID *ConfigGuid, VOID *ConfigData, UINTN ConfigDataSize); // 0x34 EFI_STATUS (*GetData)(VOID *This, EFI_GUID *ConfigGuid, VOID *ConfigData, UINTN *ConfigDataSize); // 0x3C
} UBA_CONFIG_DATABASE_PRIVATE;

//
// HOB (Hand-Off Block) structures
//
#define EFI_HOB_TYPE_GUID_EXT 4
#define EFI_HOB_TYPE_END_OF_HOB 0xFFFF typedef struct {
 UINT16 HobType; // 0x00 UINT16 HobLength; // 0x02 UINT32 Reserved; // 0x04
} EFI_HOB_HEADER; // Total: 8 bytes typedef struct {
 EFI_GUID Guid; // 0x00 UINT32 DataCount; // 0x10: number of config entries
 // followed by per-entry data starting at offset 0x14 (0x14 + 4 = 0x18 if 1st entry)
} UBA_CONFIG_HOB_HEADER;

//
// UBA config HOB per-entry structure (36 bytes each)
// Each entry has a relative offset to data + data size
//
typedef struct {
 UINT64 DataOffset; // 0x00: relative offset from HOB start to config GUID data UINT32 DataType; // 0x08: data type indicator UINT32 DataSize; // 0x0C: size of config data
 // 0x10: config name string (16 bytes = CHAR8[16])
 // 0x20: end
} UBA_CONFIG_HOB_ENTRY;

//
// EFI SYSTEM TABLE globals (assigned by _ModuleEntryPoint)
//
extern UINTN ImageHandle;
extern EFI_SYSTEM_TABLE *gST;
extern EFI_BOOT_SERVICES *gBS;
extern EFI_RUNTIME_SERVICES *gRT;

//
// Module globals
//
EFI_HANDLE mImageHandle;
EFI_SYSTEM_TABLE *mSystemTable;
EFI_BOOT_SERVICES *gBootServices;
EFI_RUNTIME_SERVICES *gRuntimeServices;

//
// Globals for this module
//
VOID *mDebugProtocol; // 0x1F50: cached debug logging protocol UINT64 mHobList; // 0x1F58: cached HOB list pointer EFI_GUID gUbaConfigDatabaseProtocolGuid = {0x45809603, 0x4E5EC91B, 0x252CF326, 0x8D8DF0FA}; // 0x1F10 EFI_GUID gUbaConfigHobGuid = {0xCC4CC9E4, 0x4E5EF25B, 0x252CFB26, 0x8D8D8D8D}; // 0x1F20 (example - not exact)

// Forward declarations EFI_STATUS EFIAPI UbaConfigDatabaseGetInfo(
 IN VOID *This,
 OUT UINT32 *ConfigCount OPTIONAL,
 OUT CHAR8 *ConfigGuid OPTIONAL,
 OUT UINTN *ConfigDataSize OPTIONAL
 );

EFI_STATUS EFIAPI UbaConfigDatabaseSetData(
 IN VOID *This,
 IN EFI_GUID *ConfigGuid,
 IN VOID *ConfigData,
 IN UINTN ConfigDataSize
 );

EFI_STATUS EFIAPI UbaConfigDatabaseGetData(
 IN VOID *This,
 IN EFI_GUID *ConfigGuid,
 OUT VOID *ConfigData,
 IN OUT UINTN *ConfigDataSize
 );

/**Internal optimized memcpy handling overlapping source/destination.

 @param[out] Dst Destination buffer
 @param[in] Src Source buffer
 @param[in] Count Number of bytes to copy

 @return Dst
**/
CHAR8 *EFIAPI InternalCopyMem (
 OUT CHAR8 *Dst,
 IN CONST CHAR8 *Src,
 IN UINTN Count
 )
{
 if (Src < Dst && &Src[Count - 1] >= Dst) {
 //
 // Overlapping case: source is before destination and overlaps,
 // copy from end to start (backward copy not shown, IDA optimizes to same)
 //
 return InternalCopyMemBackward(Dst, Src, Count);
 } else {
 //
 // Non-overlapping: copy in 8-byte chunks then remainder
 //
 UINTN Count8 = Count >> 3;
 Count &= 7;
 qmemcpy(Dst, Src, 8 *Count8);
 qmemcpy(&Dst[8 *Count8], &Src[8 *Count8], Count);
 }
 return Dst;
}

/**Internal optimized zero memory.

 @param[out] Buf Buffer to zero
 @param[in] Size Size in bytes

 @return Buf
**/
VOID *EFIAPI InternalZeroMem (
 OUT VOID *Buf,
 IN UINTN Size
 )
{
 memset(Buf, 0, 8 * (Size >> 3));
 memset(&((UINT8 *)Buf)[8 * (Size >> 3)], 0, Size & 7);
 return Buf;
}

/**Read an unaligned 64-bit value.

 @param[in] Buffer Pointer to read from

 @return The 64-bit value read
**/
UINT64 EFIAPI ReadUnaligned64 (
 IN CONST VOID *Buffer
 )
{
 return *(UINT64 *)Buffer;
}

/**UEFI ASSERT print function. Calls into debug protocol.

 @param[in] FileName Source file name
 @param[in] LineNumber Line number
 @param[in] Message Assert message
**/
VOID EFIAPI AssertPrint (
 IN CONST CHAR8 *FileName,
 IN UINTN LineNumber,
 IN CONST CHAR8 *Message
 )
{
 UINT64 (*DebugAssert)(CONST CHAR8 *, UINTN, CONST CHAR8 *);

 DebugAssert = GetDebugLogger();
 if (DebugAssert) {
 DebugAssert(FileName, LineNumber, Message);
 }
}

/**Debug print function with level filtering.
 Checks CMOS to determine debug level and only prints if the requested level matches.

 @param[in] ErrorLevel Debug error level
 @param[in] Format Format string
 @param[in] ... Variable arguments
**/
VOID EFIAPI DebugPrint (
 IN UINTN ErrorLevel,
 IN CONST CHAR8 *Format,
 ...
 )
{
 UINT64 (*DebugPrintFn)(UINTN, CONST CHAR8 *, VA_LIST);
 UINT8 DebugLevel;
 UINT64 FilterLevel;

 DebugPrintFn = (UINT64 (*)(UINTN, CONST CHAR8 *, VA_LIST))GetDebugLogger();
 if (!DebugPrintFn) return;

 //
 // Read CMOS status register to determine debug level
 //
 __outbyte(0x70, __inbyte(0x70) & 0x80 | 0x4B);
 DebugLevel = __inbyte(0x71);

 if (DebugLevel > 3) {
 if (DebugLevel == 0) {
 DebugLevel = *(UINT8 *)0xFDAF0490 & 2 | 1;
 }
 }

 FilterLevel = 0;
 switch (DebugLevel) {
 case 1:
 FilterLevel = 0x80000004; // EFI_D_INFO break;
 default:
 FilterLevel = 0x80000006; // EFI_D_ERROR | EFI_D_INFO break;
 }

 if ((FilterLevel & ErrorLevel) != 0) {
 DebugPrintFn(ErrorLevel, Format, (VA_LIST)&Format + 1);
 }
}

/**Allocate pool memory.

 @param[in] PoolType Type of pool to allocate (0 = NonEx, 1 = BS, 2 = RT, 3 = S4)
 @param[in] Size Number of bytes to allocate
 @param[out] Buffer Pointer to receive allocated buffer

 @return Allocated buffer, or NULL on failure
**/
VOID *EFIAPI AllocatePool (
 IN UINTN PoolType,
 IN UINTN Size
 )
{
 EFI_STATUS Status;
 VOID *Buffer;

 Status = gBS->AllocatePool(PoolType, Size, &Buffer);
 if (EFI_ERROR(Status)) {
 return NULL;
 }
 return Buffer;
}

/**Allocate pool memory and copy data into it.

 @param[in] PoolType Type of pool
 @param[in] Size Number of bytes
 @param[in] Src Source data to copy

 @return Allocated buffer with copied data, or NULL
**/
VOID *EFIAPI AllocateCopyPool (
 IN UINTN PoolType,
 IN UINTN Size,
 IN CONST VOID *Src
 )
{
 VOID *Dst;

 Dst = AllocatePool(PoolType, Size);
 if (Dst && Size) {
 CopyMem(Dst, Src, Size);
 }
 return Dst;
}

/**ZeroMem wrapper with safety checks.

 @param[out] Buf Buffer to zero
 @param[in] Length Length in bytes

 @return Buf
**/
VOID *EFIAPI ZeroMem (
 OUT VOID *Buf,
 IN UINTN Length
 )
{
 if (Length == 0) return Buf;
 return InternalZeroMem(Buf, Length);
}

/**CopyMem wrapper with destination/source overlap safety checks.

 @param[out] Dst Destination buffer
 @param[in] Src Source buffer
 @param[in] Count Number of bytes to copy

 @return Dst
**/
VOID *EFIAPI CopyMem (
 OUT VOID *Dst,
 IN CONST VOID *Src,
 IN UINTN Count
 )
{
 if (Dst == Src) return Dst;
 return InternalCopyMem(Dst, Src, Count);
}

/**Linked list validation helper.

 @param[in] ListHead Pointer to LIST_ENTRY to validate

 @return TRUE if valid
**/
BOOLEAN EFIAPI InternalBaseLibIsListValid (
 IN CONST LIST_ENTRY *ListHead
 )
{
 if (!ListHead)
 AssertPrint("e:\\hs\\MdePkg\\Library\\BaseLib\\LinkedList.c", 80, "List != ((void *) 0)");
 if (!ListHead->ForwardLink)
 AssertPrint("e:\\hs\\MdePkg\\Library\\BaseLib\\LinkedList.c", 81, "List->ForwardLink != ((void *) 0)");
 if (!ListHead->BackLink)
 AssertPrint("e:\\hs\\MdePkg\\Library\\BaseLib\\LinkedList.c", 82, "List->BackLink != ((void *) 0)");
 return TRUE;
}

/**Insert a list entry at the tail of a doubly-linked list.

 @param[in] ListHead The list head to insert after
 @param[out] Entry The entry to insert

 @return ListHead
**/
LIST_ENTRY *EFIAPI InsertTailList (
 IN LIST_ENTRY *ListHead,
 OUT LIST_ENTRY *Entry
 )
{
 LIST_ENTRY *PrevEntry;

 InternalBaseLibIsListValid(ListHead);
 Entry->ForwardLink = ListHead;
 PrevEntry = ListHead->BackLink;
 Entry->BackLink = PrevEntry;
 PrevEntry->ForwardLink = Entry;
 ListHead->BackLink = Entry;
 return ListHead;
}

/**AsciiStrLen - returns the length of a null-terminated ASCII string.

 @param[in] String The string to measure

 @return Length in bytes, excluding null terminator
**/
UINTN EFIAPI AsciiStrLen (
 IN CONST CHAR8 *String
 )
{
 UINTN Length;

 for (Length = 0; *String; Length++) {
 String++;
 }
 return Length;
}

/**AsciiStrnLenS - returns the length of a null-terminated ASCII string,
 bounded by MaxSize.

 @param[in] String The string to measure
 @param[in] MaxSize Maximum number of bytes to check

 @return Length in bytes, excluding null terminator, <= MaxSize
**/
UINTN EFIAPI AsciiStrnLenS (
 IN CONST CHAR8 *String,
 IN UINTN MaxSize
 )
{
 UINTN Length;

 if (!String || !MaxSize) return 0;
 for (Length = 0; *String && Length < MaxSize - 1; Length++, String++);
 if (!*String) return Length;
 return MaxSize;
}

//
// UBA_CONFIG_DATABASE_PRIVATE helper: CR-based node access
// CR = CONTAINER_RECORD macro: from a member pointer, get the containing struct
//

/**Retrieve the linked list data pointer from the config database private.

 Given the protocol interface address (offset into the private struct),
 check signature and return the list head pointer.

 @param[in] This Protocol interface address (offset 0x2C from private)
 @param[out] ListHead Receives the linked list head pointer

 @return EFI_SUCCESS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseGetListNode (
 IN VOID *This,
 OUT LIST_ENTRY **ListHead
 )
{
 UBA_CONFIG_DATABASE_PRIVATE *Private;

 Private = CR (This, UBA_CONFIG_DATABASE_PRIVATE, ConfigGuid);
 if (Private->Signature != UBA_DATABASE_SIGNATURE) {
 Private = (UBA_CONFIG_DATABASE_PRIVATE *)This;
 }
 *ListHead = (LIST_ENTRY *)Private->ConfigDataRef;
 return EFI_SUCCESS;
}

/**Initialize a new config data node and optionally insert it into the database.

 Called by UbaConfigDatabaseSetData to create a new entry for GUID-keyed configuration data when it doesn't already exist.

 @param[in] This Protocol interface
 @param[in] DataType Data type identifier
 @param[in] ConfigGuid GUID string for this configuration
 @param[in] ConfigName Name string (optional)
 @param[out] NewNode Receives pointer to newly created node (optional)

 @return EFI_SUCCESS or EFI_OUT_OF_RESOURCES
**/
EFI_STATUS EFIAPI UbaConfigDatabaseNodeInit (
 IN VOID *This,
 IN UINT32 DataType,
 IN CHAR8 *ConfigGuid OPTIONAL,
 IN VOID *ConfigName OPTIONAL,
 OUT VOID **NewNode OPTIONAL
 )
{
 UBA_CONFIG_DATABASE_PRIVATE *Private;
 UBA_CONFIG_NODE *Node;
 CHAR8 *Buf;

 Private = CR (This, UBA_CONFIG_DATABASE_PRIVATE, ConfigGuid);
 if (Private->Signature != UBA_DATABASE_SIGNATURE) {
 Private = (UBA_CONFIG_DATABASE_PRIVATE *)This;
 }

 Buf = AllocatePool((UINTN)This, 64);
 if (!Buf) return EFI_OUT_OF_RESOURCES;

 Node = ZeroMem(Buf, 64);
 if (!Node) return EFI_OUT_OF_RESOURCES;

 Node->Signature = UBA_DATABASE_SIGNATURE; // "UBAD"
 Node->Version = 1;
 Node->ConfigDataSize = DataType;

 if (ConfigName) {
 AsciiStrnCpyS((CHAR8 *)Node->ConfigName, AsciiStrLen((CHAR8 *)ConfigName) + 1, (CHAR8 *)ConfigName);
 }

 if (ConfigGuid) {
 CopyMem(&Node->ConfigGuid, ConfigGuid, sizeof(EFI_GUID));
 }

 //
 // Initialize linked list entry to point to itself (empty list)
 //
 Node->Link.ForwardLink = &Node->Link;
 Node->Link.BackLink = &Node->Link;

 if (NewNode) {
 *NewNode = Node;
 Private->ConfigDataRef = Node;
 }

 return EFI_SUCCESS;
}

/**Get HOB list from the UEFI system table.

 Scans the SystemTable configuration table for the HOB list GUID,
 then caches and returns it.

 @return Pointer to the HOB list, or ASSERTs on failure
**/
VOID *EFIAPI GetHobList (
 VOID
 )
{
 UINTN Index;
 UINT64 *ConfigTable;
 EFI_GUID *HobListGuid = &gUbaConfigHobGuid; // GUID for HOB list if (mHobList) return (VOID *)mHobList;

 mHobList = 0;
 if (mSystemTable->NumberOfTableEntries > 0) {
 ConfigTable = (UINT64 *)mSystemTable->ConfigurationTable;
 for (Index = 0; Index < mSystemTable->NumberOfTableEntries; Index++) {
 if (CompareGuid(HobListGuid, (EFI_GUID *)(ConfigTable + 0))) {
 mHobList = *(ConfigTable + 2);
 break;
 }
 ConfigTable += 3; // each entry = GUID + Address (3 UINT64s)
 }
 }

 if (!mHobList) {
 DebugPrint(EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND);
 AssertPrint("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 54, "!EFI_ERROR (Status)");
 AssertPrint("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 55, "mHobList != ((void *) 0)");
 }

 return (VOID *)mHobList;
}

/**Find the next HOB of type EFI_HOB_TYPE_GUID_EXT matching a given GUID.

 Walks the HOB list looking for a GUID_EXT (type 4) HOB.

 @param[in] HobStart Start of HOB list

 @return HOB with type 4, or NULL if not found / end-of-list
**/
UBA_CONFIG_HOB_HEADER *EFIAPI GetNextGuidHob (
 IN VOID *HobStart
 )
{
 EFI_HOB_HEADER *Hob;

 Hob = (EFI_HOB_HEADER *)HobStart;
 if (!Hob) {
 AssertPrint("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 108, "HobStart != ((void *) 0)");
 }

 while (1) {
 if (Hob->HobType == EFI_HOB_TYPE_END_OF_HOB) return NULL;
 if (Hob->HobType == 4) return (UBA_CONFIG_HOB_HEADER *)Hob;
 Hob = (EFI_HOB_HEADER *)((UINT8 *)Hob + Hob->HobLength);
 }
}

/**Compare two EFI_GUID values.

 Reads them as unaligned 64-bit values and compares both halves.

 @param[in] Guid1 First GUID
 @param[in] Guid2 Second GUID

 @return TRUE if equal
**/
BOOLEAN EFIAPI CompareGuid (
 IN EFI_GUID *Guid1,
 IN EFI_GUID *Guid2
 )
{
 UINT64 *G1;
 UINT64 *G2;

 G1 = (UINT64 *)Guid1;
 G2 = (UINT64 *)Guid2;

 return (ReadUnaligned64(G1) == ReadUnaligned64(G2) &&
 ReadUnaligned64(&G1[1]) == ReadUnaligned64(&G2[1]));
}

/**Get debug protocol (logger).

 Locates and caches the protocol used for debug print / assert output.

 @return Debug protocol interface (0 if not available)
**/
VOID *EFIAPI GetDebugLogger (
 VOID
 )
{
 EFI_STATUS Status;
 VOID *DebugProtocol;

 if (mDebugProtocol) return mDebugProtocol;

 //
 // Check if debug is available via CMOS diagnostic port
 //
 __outbyte(0x70, __inbyte(0x70) & 0x80 | 0x4B);
 if ((__inbyte(0x71) & 0x10) != 0x10) {
 return NULL;
 }

 Status = gBS->LocateProtocol(&gEfiDebugProtocolGuid, NULL, &DebugProtocol);
 if (EFI_ERROR(Status)) {
 return NULL;
 }

 mDebugProtocol = DebugProtocol;
 return DebugProtocol;
}

/**Safe ASCII string copy with bounds checking.

 @param[out] Destination Destination buffer
 @param[in] DestMax Maximum number of chars in destination
 @param[in] Source Source string

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI AsciiStrCpyS (
 OUT CHAR8 *Destination,
 IN UINTN DestMax,
 IN CONST CHAR8 *Source
 )
{
 UINTN SourceLen;
 CHAR8 *DstPtr;

 SourceLen = AsciiStrnLenS(Source, DestMax);

 if (DestMax <= SourceLen) {
 return EFI_BUFFER_TOO_SMALL;
 }

 //
 // Check overlap
 //
 if (Source > Destination && Source < &Destination[DestMax]) {
 return EFI_INVALID_PARAMETER;
 }
 if (Destination > Source && Destination < &Source[SourceLen + 1]) {
 return EFI_INVALID_PARAMETER;
 }

 DstPtr = Destination;
 CopyMem(DstPtr, Source, SourceLen);
 DstPtr[SourceLen] = '\0';
 return EFI_SUCCESS;
}

/**Safe bounded ASCII string copy (max 16 chars typically).

 @param[out] Destination Destination buffer
 @param[in] DestMax Maximum number of chars in dest (capped at 16)
 @param[in] Source Source string

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI AsciiStrnCpyS (
 OUT CHAR8 *Destination,
 IN UINTN DestMax,
 IN CONST CHAR8 *Source
 )
{
 UINTN SourceLen;
 CHAR8 *DstPtr;

 SourceLen = AsciiStrnLenS(Source, DestMax);

 if (DestMax <= 0xF && DestMax <= SourceLen) {
 return EFI_BUFFER_TOO_SMALL;
 }

 if (SourceLen > 15) SourceLen = 15;

 if (Destination < &Source[SourceLen + 1] && Source < &Destination[DestMax]) {
 return EFI_INVALID_PARAMETER;
 }

 DstPtr = Destination;
 while (SourceLen && *Source) {
 *DstPtr++ = *Source++;
 SourceLen--;
 }
 *DstPtr = '\0';

 return EFI_SUCCESS;
}

/**The main driver entry point after module initialization.

 Creates the UBA_CONFIG_DATABASE_PRIVATE instance, initializes it,
 loads config data from HOB, and installs the protocol interface.

 @param[in] ImageHandle The firmware allocated handle for the EFI image
 @param[in] SystemTable A pointer to the EFI System Table

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseDxeEntry (
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
{
 UBA_CONFIG_DATABASE_PRIVATE *Private;
 UBA_CONFIG_NODE *Node;
 EFI_STATUS Status;
 EFI_HANDLE Handle;

 Private = AllocatePool(4, 64);
 if (!Private) return EFI_OUT_OF_RESOURCES;

 Node = ZeroMem(Private, 64);
 if (!Node) return EFI_OUT_OF_RESOURCES;

 //
 // Initialize private structure
 //
 Private->Signature = UBA_DATABASE_SIGNATURE; // "UBAD"
 Private->Version = 1;
 Private->ConfigCount = 1;
 Private->GetInfo = (EFI_STATUS (*)())UbaConfigDatabaseGetInfo;
 Private->SetData = (EFI_STATUS (*)())UbaConfigDatabaseSetDataDispatch;
 Private->GetData = (EFI_STATUS (*)())UbaConfigDatabaseGetDataDispatch;

 //
 // Set protocol GUID (0x504C4342 = "BCLP")
 // This is the UBA protocol GUID data that identifies this interface
 //
 Private->ConfigGuid.Data1 = 0x504C4342;
 Private->ConfigGuid.Data2 = 0;

 DebugPrint(EFI_D_INFO, "UbaConfigDatabasedxeEntry: after allocate Memory!\n");

 //
 // Load initial configuration from HOB
 //
 Status = UbaConfigDatabaseLoadFromHob(&Private->ConfigGuid);
 if (EFI_ERROR(Status)) {
 return Status;
 }

 //
 // Install the protocol interface
 //
 Handle = NULL;
 Status = gBS->InstallProtocolInterface(
 &Handle,
 &gUbaConfigDatabaseProtocolGuid,
 0,
 &Private->ConfigGuid
 );

 return Status;
}

/**Locate protocol and install the UBA config database protocol.

 This is the entry point handler called from ModuleEntryPoint(ImageHandle, SystemTable)
 after the standard UEFI DXE driver initialization (save gST, gBS, gRT).

 @param[in] ImageHandle Image handle
 @param[in] SystemTable System table

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseInstallDriver (
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
{
 return UbaConfigDatabaseDxeEntry(ImageHandle, SystemTable);
}

/**Load initial configuration data from HOB (Hand-Off Block).

 Scans the UBA config HOB to find config entries and calls SetData for each one. This populates the database during driver start.

 @param[in] ProtocolGuid Pointer to the protocol GUID data area

 @return EFI_SUCCESS or EFI_NOT_FOUND / ASSERT on failure
**/
EFI_STATUS EFIAPI UbaConfigDatabaseLoadFromHob (
 IN EFI_GUID *ProtocolGuid
 )
{
 UBA_CONFIG_DATABASE_PRIVATE *Private;
 VOID *HobList;
 UBA_CONFIG_HOB_HEADER *Hob;
 EFI_GUID TargetGuid;
 UINT32 Index;
 EFI_STATUS Status;
 UINT64 GuidOffset;
 UINT32 DataSize;
 VOID *Node;

 Private = CR (ProtocolGuid, UBA_CONFIG_DATABASE_PRIVATE, ConfigGuid);
 if (Private->Signature != UBA_DATABASE_SIGNATURE) {
 // Signature check - will ASSERT if invalid
 }

 //
 // GUID to search for in HOB (target config HOB)
 //
 TargetGuid.Data1 = 0xE4C9CC4C;
 TargetGuid.Data2 = 0x5BF2;
 TargetGuid.Data3 = 0x26FB;
 TargetGuid.Data4[0] = 0x8D;
 TargetGuid.Data4[1] = 0x8D;
 TargetGuid.Data4[2] = 0x8D;
 TargetGuid.Data4[3] = 0x8D;
 TargetGuid.Data4[4] = 0x8D;
 TargetGuid.Data4[5] = 0x8D;
 TargetGuid.Data4[6] = 0x8D;
 TargetGuid.Data4[7] = 0x8D;

 HobList = GetHobList();
 if (!HobList) {
 DebugPrint(EFI_D_ERROR, "UBA Current config HOB is not found!\n");
 return EFI_NOT_FOUND;
 }

 Hob = GetNextGuidHob(HobList);
 if (!Hob) {
 DebugPrint(EFI_D_ERROR, "UBA Current config HOB is not found!\n");
 return EFI_NOT_FOUND;
 }

 DebugPrint(EFI_D_INFO, "UbaConfigDatabasedxeEntry: get first hob!\n");

 //
 // Initialize the config database with data from HOB
 //
 Status = UbaConfigDatabaseNodeInit(
 ProtocolGuid,
 Hob->DataCount,
 (CHAR8 *)((UINT8 *)Hob + 0x38), // First config GUID data
 (VOID *)((UINT8 *)Hob + 0x48), // Config name
 &Node
 );

 if (EFI_ERROR(Status)) {
 return Status;
 }

 //
 // Process each config entry in the HOB
 //
 if (Hob->DataCount > 0) {
 for (Index = 0; Index < Hob->DataCount; Index++) {
 UBA_CONFIG_HOB_ENTRY *Entry;
 CHAR8 *ConfigData;
 UINT32 ConfigDataSize;
 UINT32 EntryType;

 Entry = (UBA_CONFIG_HOB_ENTRY *)((UINT8 *)Hob + 0x74 + Index *36);
 ConfigData = (CHAR8 *)Hob + Entry->DataOffset + 24;
 ConfigDataSize = Entry->DataSize;
 EntryType = Entry->DataType;

 Status = ((EFI_STATUS (*)(VOID *, CHAR8 *, UINT32, UINT32))ProtocolGuid->GetInfo)(
 ProtocolGuid,
 ConfigData,
 ConfigDataSize,
 EntryType
 );

 if (EFI_ERROR(Status)) {
 DebugPrint(EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
 AssertPrint("e:\\hs\\CpPlatPkg\\Uba\\CfgDb\\Dxe\\CfgDbDxe.c", 468, "!EFI_ERROR (Status)");
 return Status;
 }
 }
 }

 return EFI_SUCCESS;
}

/**Dispatch wrapper for UbaConfigDatabaseSetData.

 Called via the protocol interface.

 @param[in] This Protocol interface
 @param[in] ConfigGuid GUID of the config entry
 @param[in] ConfigData Configuration data to store
 @param[in] ConfigDataSize Size of configuration data

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseSetDataDispatch (
 IN VOID *This,
 IN EFI_GUID *ConfigGuid,
 IN VOID *ConfigData,
 IN UINTN ConfigDataSize
 )
{
 return UbaConfigDatabaseSetData(This, ConfigGuid, ConfigData, ConfigDataSize);
}

/**Dispatch wrapper for UbaConfigDatabaseGetData.

 Called via the protocol interface.

 @param[in] This Protocol interface
 @param[in] ConfigGuid GUID of the config entry
 @param[out] ConfigData Buffer to receive config data
 @param[in,out] ConfigDataSize On input: buffer size, On output: actual size

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseGetDataDispatch (
 IN VOID *This,
 IN EFI_GUID *ConfigGuid,
 OUT VOID *ConfigData,
 IN OUT UINTN *ConfigDataSize
 )
{
 EFI_STATUS Status;
 LIST_ENTRY *ListHead;

 if (!ConfigGuid || !ConfigData || !ConfigDataSize) return EFI_INVALID_PARAMETER;

 Status = UbaConfigDatabaseGetListNode(This, &ListHead);
 if (EFI_ERROR(Status)) return EFI_NOT_FOUND;

 return UbaConfigDatabaseFindData(ListHead, ConfigGuid, ConfigData, ConfigDataSize);
}

/**Get info about the config database.

 Returns the number of config entries, a GUID, and total data size.

 @param[in] This Protocol interface
 @param[out] ConfigCount Number of config entries (optional)
 @param[out] ConfigName Config name string (optional)
 @param[out] ConfigDataSize Total size of config data (optional)

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI UbaConfigDatabaseGetInfo (
 IN VOID *This,
 OUT UINT32 *ConfigCount OPTIONAL,
 OUT CHAR8 *ConfigName OPTIONAL,
 OUT UINTN *ConfigDataSize OPTIONAL
 )
{
 EFI_STATUS Status;
 UBA_CONFIG_NODE *Node;
 LIST_ENTRY *ListHead;
 LIST_ENTRY ListHeadStorage[3];

 ListHeadStorage[0] = 0;
 Status = UbaConfigDatabaseGetListNode(This, &ListHead);
 if (EFI_ERROR(Status)) return Status;

 Node = (UBA_CONFIG_NODE *)ListHead;
 if (Node->Signature != UBA_DATABASE_SIGNATURE) {
 // Already the right pointer from CR macro
 }

 if (ConfigCount) *ConfigCount = Node->ConfigDataSize;
 if (ConfigDataSize) {
 AsciiStrCpyS((CHAR8 *)ConfigDataSize, AsciiStrLen((CHAR8 *)(&Node->ConfigName[0])) + 1, (CHAR8 *)(&Node->ConfigName[0]));
 }
 if (ConfigName) {
 CopyMem(ConfigName, Node->ConfigName, sizeof(EFI_GUID));
 }

 return EFI_SUCCESS;
}

/**Set (store or update) configuration data identified by GUID.

 Allocates a new config node, fills in the data, and inserts it into the config database linked list.

 @param[in] This Protocol interface
 @param[in] ConfigGuid GUID identifying this config data
 @param[in] ConfigData Pointer to config data
 @param[in] ConfigDataSize Size of config data

 @return EFI_SUCCESS or EFI_OUT_OF_RESOURCES
**/
EFI_STATUS EFIAPI UbaConfigDatabaseSetData (
 IN VOID *This,
 IN CHAR8 *ConfigGuid OPTIONAL,
 IN VOID *ConfigData OPTIONAL,
 IN EFI_GUID *ConfigDataSize
 )
{
 UBA_CONFIG_DATABASE_PRIVATE *Private;
 UBA_CONFIG_NODE *Node;
 LIST_ENTRY *ListHead;
 VOID *CopiedData;
 EFI_GUID *Guid;
 EFI_STATUS Status;
 LIST_ENTRY ListStorage[5];
 EFI_HANDLE Handle;

 if (!ConfigGuid || !ConfigData || !ConfigDataSize) return EFI_INVALID_PARAMETER;

 Private = CR (This, UBA_CONFIG_DATABASE_PRIVATE, ConfigGuid);
 if (Private->Signature != UBA_DATABASE_SIGNATURE) {
 Private = (UBA_CONFIG_DATABASE_PRIVATE *)This;
 }

 Status = UbaConfigDatabaseGetListNode(This, ListStorage);
 if (EFI_ERROR(Status)) return Status;

 ListHead = (LIST_ENTRY *)ListStorage[0];

 //
 // Allocate and initialize a new config node
 //
 Node = AllocatePool((UINTN)This, 60);
 if (!Node) return EFI_OUT_OF_RESOURCES;

 Node = ZeroMem(Node, 60);
 if (!Node) return EFI_OUT_OF_RESOURCES;

 Node->Signature = UBA_DATABASE_SIGNATURE;
 Node->Version = 1;
 //
 // Copy the GUID data
 //
 Node->ConfigDataSize = (UINT32)ConfigGuid;
 Node->ConfigDataRef = Private->ConfigDataRef;
 CopiedData = AllocateCopyPool((UINTN)Private->ConfigDataRef, (UINTN)ConfigDataSize, ConfigData);
 Node->ConfigData = (UINT32)ConfigDataSize;
 Node->ConfigDataSize = (UINT32)ConfigDataSize; // actually the GUID data
 // Store the GUID Node->ConfigData = CopiedData;
 Node->ConfigDataSize = (UINT32)(UINTN)ConfigDataSize;

 //
 // Set GUID from parameter
 //
 CopyMem(&Node->ConfigGuid, ConfigGuid, sizeof(EFI_GUID));

 //
 // Insert into linked list
 //
 InsertTailList((LIST_ENTRY *)((UINT8 *)Node + 8), (LIST_ENTRY *)&Node->Link);
 Node->NodeCount++;

 //
 // Update counters
 //
 Private->EntryCount++;

 //
 // Re-install protocol to notify listeners
 //
 Handle = NULL;
 Status = gBS->InstallProtocolInterface(
 &Handle,
 &Node->ConfigGuid,
 0,
 (VOID *)((UINTN)This + 36) // This + 0x24 from CR macro
 );

 if (EFI_ERROR(Status)) {
 DebugPrint(EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
 AssertPrint("e:\\hs\\CpPlatPkg\\Uba\\CfgDb\\Dxe\\CfgDbDxe.c", 187, "!EFI_ERROR (Status)");
 }

 return EFI_SUCCESS;
}

/**Find configuration data by GUID and copy it to the output buffer.

 Walks the linked list in the config database, looking for a node whose GUID matches the given ConfigGuid.

 @param[in] ListHead Linked list head of config database
 @param[in] ConfigGuid GUID to search for
 @param[out] ConfigData Buffer to receive config data
 @param[in,out] ConfigDataSize On input: buffer size, On output: data size

 @return EFI_SUCCESS, EFI_NOT_FOUND, or EFI_BUFFER_TOO_SMALL
**/
EFI_STATUS EFIAPI UbaConfigDatabaseFindData (
 IN LIST_ENTRY *ListHead,
 IN EFI_GUID *ConfigGuid,
 OUT VOID *ConfigData OPTIONAL,
 IN OUT UINTN *ConfigDataSize
 )
{
 LIST_ENTRY *Link;
 UBA_CONFIG_NODE *Node;
 BOOLEAN Found;

 if (!ConfigGuid || !ConfigDataSize) return EFI_INVALID_PARAMETER;

 //
 // Walk the linked list looking for a matching GUID
 //
 if (!InternalBaseLibIsListValid(ListHead)) return EFI_NOT_FOUND;

 Link = ListHead->ForwardLink;
 while (Link != ListHead) {
 Node = CR (Link, UBA_CONFIG_NODE, Link);
 if (Node->Signature != UBA_DATABASE_SIGNATURE) {
 Node = (UBA_CONFIG_NODE *)Link;
 }
 if (!Node) {
 return EFI_NOT_FOUND;
 }

 if (CompareGuid(ConfigGuid, &Node->ConfigGuid)) {
 //
 // Found a matching node, copy data if buffer is large enough
 //
 if (ConfigDataSize) {
 if (*ConfigDataSize < Node->ConfigDataSize) {
 *ConfigDataSize = Node->ConfigDataSize;
 return EFI_BUFFER_TOO_SMALL;
 }
 if (ConfigData && Node->ConfigDataSize) {
 CopyMem(ConfigData, Node->ConfigData, Node->ConfigDataSize);
 }
 }
 return EFI_SUCCESS;
 }

 Link = Link->ForwardLink;
 }

 return EFI_NOT_FOUND;
}

/**UEFI Driver Entry Point - ModuleEntryPoint.

 Standard DXE driver entry point. Saves global pointers and calls the main driver initialization routine.

 @param[in] ImageHandle Handle for this image
 @param[in] SystemTable Pointer to EFI system table

 @return EFI_STATUS
**/
EFI_STATUS EFIAPI ModuleEntryPoint (
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
{
 mImageHandle = (UINTN)ImageHandle;
 mSystemTable = SystemTable;
 gBootServices = SystemTable->BootServices;
 gRuntimeServices = SystemTable->RuntimeServices;

 //
 // Get the HOB list (for later config loading)
 //
 GetHobList();

 //
 // Install the UBA config database protocol
 //
 return UbaConfigDatabaseInstallDriver(ImageHandle, SystemTable);
}