/** @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);
}