/** @file
UsbOcUpdateDxeLightningRidgeEXECB4 - USB Overcurrent Mapping Driver
DXE driver that installs a USB Overcurrent (UsbOc) configuration protocol
for the LightningRidge EX EC B4 platform. This driver is part of the UBA
(Universal Board Architecture) framework.
Functional flow:
1. _ModuleEntryPoint initializes gST, gBS, gRT, gImageHandle globals.
2. Calls GetHobList() to retrieve the HOB list from the system table.
3. Calls DebugPrintEx() to log "UBA:UsbOcUpdate-TypeLightningRidgeEXECB4\n".
4. Calls gBS->AllocatePool() + gBS->InstallProtocolInterface() to publish
the UBA USB OC protocol with platform-specific port mappings.
The port mapping is selected at runtime by reading CMOS index 0x4B
(board revision strap). Three tables are compiled in:
- mUsbOcTableDefault (0xba0): Default mapping
- mUsbOcTableAlt (0xbd0): Alternate/B2 stepping mapping
- mUsbOcTableExt (0xc10): Extended mapping (all OC pin 0x0702)
Build path:
e:\hs\Build\HR6N0XMLK\DEBUG_VS2015\X64\PurleyRpPkg\Uba\UbaMain\Dxe\
TypeLightningRidgeEXECB4\UsbOcUpdateDxe\UsbOcUpdateDxe\DEBUG\
UsbOcUpdateDxeLightningRidgeEXECB4.pdb
Copyright (C) 2025 American Megatrends Inc. (AMI)
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Module Index:
HR650X BIOS index 0044, SHA256 962bb14e57e35431057e4f23d4e3aae9e698b16facd4f1804c099b46c5a5e605
**/
#include "UsbOcUpdateDxeLightningRidgeEXECB4.h"
//
// ---- UEFI Global Variables ----
//
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_HANDLE gImageHandle = NULL;
VOID *mHobList = NULL;
UBA_PROTOCOL_FUNCS *mUbaProtocol = NULL;
//
// ---- USB OC Configuration Tables ----
//
// These tables are embedded in the .data section at the addresses
// returned by GetUsbOcConfigTables(). The values map USB physical
// ports to overcurrent sense pins.
//
// .data layout:
// 0xba0 (mUsbOcTableDefault): {0,0,0,0, 1,1,1,1, 2,2,2,2}
// 0xbd0 (mUsbOcTableAlt): {0,0,0,0, 0,0,1,1, 1,1,2,2}
// 0xc10 (mUsbOcTableExt): all 0x0702
//
USB_OC_CONFIG_TABLE mUsbOcTableDefault = {
{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }
};
USB_OC_CONFIG_TABLE mUsbOcTableAlt = {
{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2 }
};
USB_OC_CONFIG_TABLE mUsbOcTableExt = {
{ 0x0702, 0x0702, 0x0702, 0x0702, 0x0702, 0x0702,
0x0702, 0x0702, 0x0702, 0x0702, 0x0702, 0x0702 }
};
//
// ---- UBA Protocol GUID (binary layout) ----
//
// EFI_GUID {2638009e-3850-4e4b-b05d-042a32dbb9d1}
//
STATIC CONST EFI_GUID mUbaProtocolGuid = UBA_USBOC_PROTOCOL_GUID;
//
// ---- gEfiHobListGUID (binary layout) ----
//
STATIC CONST EFI_GUID mEfiHobListGuid = EFI_HOB_LIST_GUID;
//
// ---- USB OC HOB GUID (binary layout) ----
//
STATIC CONST EFI_GUID mUsbOcHobGuid = USBOC_HOB_GUID;
// ============================================================================
// GetUsbOcConfigTables
// ============================================================================
/**
Returns pointers to the three board-specific USB OC configuration tables.
@param[out] Table2 Pointer to mUsbOcTableAlt (0xbd0).
@param[out] Table1 Pointer to mUsbOcTableDefault (0xba0).
@param[out] Table3 Pointer to mUsbOcTableExt (0xc10).
@retval EFI_SUCCESS Always succeeds.
**/
EFI_STATUS
EFIAPI
GetUsbOcConfigTables (
OUT VOID **Table2,
OUT VOID **Table1,
OUT VOID **Table3
)
{
*Table2 = &mUsbOcTableAlt;
*Table1 = &mUsbOcTableDefault;
*Table3 = &mUsbOcTableExt;
return EFI_SUCCESS;
}
// ============================================================================
// LocateUbaProtocol
// ============================================================================
/**
Lazily locate and cache the UBA USB OC protocol.
Allocates a pool of at least 16 bytes via gBS->AllocatePool (type 31,
i.e., EfiBootServicesData), then calls gBS->LocateProtocol to find
the UBA protocol interface. The result is cached in mUbaProtocol.
@return Pointer to the located UBA_PROTOCOL_FUNCS, or NULL.
**/
UBA_PROTOCOL_FUNCS *
EFIAPI
LocateUbaProtocol (
VOID
)
{
EFI_STATUS Status;
UBA_PROTOCOL_FUNCS *Protocol;
if (mUbaProtocol != NULL) {
return mUbaProtocol;
}
//
// Allocate pool for the protocol structure (minimum 16 bytes).
//
Status = gBS->AllocatePool (EfiBootServicesData, 16, (VOID **)&Protocol);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem (Protocol, 16);
//
// Locate the UBA USB OC protocol by GUID.
//
Status = gBS->LocateProtocol (
(EFI_GUID *)&mUbaProtocolGuid,
NULL,
(VOID **)Protocol
);
if (EFI_ERROR (Status)) {
gBS->FreePool (Protocol);
return NULL;
}
//
// Cache the protocol pointer.
//
mUbaProtocol = Protocol;
return Protocol;
}
// ============================================================================
// DebugPrintEx
// ============================================================================
/**
Board-revision-aware debug print.
Reads CMOS index 0x4B to determine the board revision/stepping and
applies a filter mask:
- If board rev == 1: allow DEBUG_INIT | DEBUG_ERROR (0x80000004)
- If board rev >= 2: allow DEBUG_INIT | DEBUG_ERROR | DEBUG_INFO (0x80000006)
- If board rev == 0 and MMIO strap: derive revision from hardware
@param[in] DebugMask Debug message mask.
@param[in] Format Print format string.
@param[in] ... Variable arguments.
@return 0 if filtered out, otherwise the return from Print function.
**/
UINT8
EFIAPI
DebugPrintEx (
IN UINT64 DebugMask,
IN CHAR8 *Format,
...
)
{
UBA_PROTOCOL_FUNCS *Protocol;
UINT64 FilterMask;
UINT8 BoardRev;
UINT8 Result;
VA_LIST Args;
Protocol = LocateUbaProtocol ();
if (Protocol == NULL) {
return 0;
}
//
// Read board revision from RTC CMOS index 0x4B.
// Preserve NMI mask (bit 7) in the index register.
//
IoWrite8 (RTC_INDEX_PORT, IoRead8 (RTC_INDEX_PORT) & 0x80 | CMOS_BOARD_REV_INDEX);
BoardRev = IoRead8 (RTC_DATA_PORT);
//
// If the raw CMOS value is out of range, try to refine it.
//
if ((UINT8)BoardRev > BOARD_REV_MAX) {
//
// Board rev appears invalid. If the raw value is 0, check the
// hardware strap at the MMIO address.
//
if (BoardRev == 0) {
BoardRev = (MmioRead8 (BOARD_STRAP_MMIO) & 2) | 1;
}
}
//
// Determine the filter mask.
//
if ((UINT8)(BoardRev - 1) <= 0xFD) { // BoardRev >= 1
FilterMask = DEBUG_MASK_ALL; // 0x80000006
if (BoardRev == 1) {
FilterMask = DEBUG_MASK_INIT | DEBUG_MASK_ERROR; // 0x80000004
}
} else {
FilterMask = 0;
}
//
// Check if our debug mask passes the filter.
//
if ((FilterMask & DebugMask) == 0) {
return 0;
}
VA_START (Args, Format);
Result = (UINT8)Protocol->Print (DebugMask, Format, Args);
VA_END (Args);
return Result;
}
// ============================================================================
// ReportAssertion
// ============================================================================
/**
Report an assertion/error condition through the UBA protocol.
Lazily locates the UBA protocol if not yet cached, then calls
offset 8 (ReportError function) with FileName, LineNumber, and Message.
@param[in] FileName Source file name string.
@param[in] LineNumber Line number of the assertion.
@param[in] Message Assertion message.
@return The return value from the UBA protocol's ReportError function,
or 0 if the protocol cannot be located.
**/
__int64
EFIAPI
ReportAssertion (
IN __int64 FileName,
IN __int64 LineNumber,
IN __int64 Message
)
{
UBA_PROTOCOL_FUNCS *Protocol;
Protocol = mUbaProtocol;
if (Protocol == NULL) {
Protocol = LocateUbaProtocol ();
}
if (Protocol != NULL) {
return Protocol->ReportError (FileName, LineNumber, Message);
}
return 0;
}
// ============================================================================
// ReadUnaligned64Ex
// ============================================================================
/**
Read a 64-bit value from a potentially unaligned address.
Asserts if Buffer is NULL.
@param[in] Buffer Pointer to source memory.
@return The 64-bit value at Buffer.
**/
UINT64
EFIAPI
ReadUnaligned64Ex (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
192,
(__int64)"Buffer != ((void *) 0)"
);
}
return ReadUnaligned64 (Buffer);
}
// ============================================================================
// CompareGuidEx
// ============================================================================
/**
Compare two GUIDs for equality by reading them as two 64-bit values.
@param[in] Guid1 Pointer to first GUID.
@param[in] Guid2 Pointer to second GUID.
@retval TRUE GUIDs are identical.
@retval FALSE GUIDs differ.
**/
BOOLEAN
EFIAPI
CompareGuidEx (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
{
return ReadUnaligned64Ex (Guid1) == ReadUnaligned64Ex (Guid2) &&
ReadUnaligned64Ex ((UINT8 *)Guid1 + 8) == ReadUnaligned64Ex ((UINT8 *)Guid2 + 8);
}
// ============================================================================
// GetHobList
// ============================================================================
/**
Locate the HOB list pointer from the UEFI System Table.
Scans the system table's configuration table array (at SystemTable + 112)
for the gEfiHobListGuid entry. Once found, the associated pointer is
cached in mHobList.
If the HOB list is not found, an assertion is triggered.
@param[in] SystemTable Pointer to the EFI System Table.
@return Pointer to the HOB list, or NULL.
**/
VOID *
EFIAPI
GetHobList (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN TableCount;
UINTN Index;
VOID *HobList;
if (mHobList != NULL) {
return mHobList;
}
mHobList = NULL;
HobList = NULL;
//
// SystemTable->NumberOfTableEntries is at offset 104 in the
// EFI_SYSTEM_TABLE structure (field after RuntimeServices).
//
TableCount = *(UINTN *)((UINT8 *)SystemTable + 104);
if (TableCount == 0) {
//
// No configuration tables -- log assertion.
//
DebugPrintEx (DEBUG_MASK_INIT, "\nASSERT_EFI_ERROR (Status = %r)\n", 0x800000000000000ELL);
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
(__int64)"!EFI_ERROR (Status)"
);
return NULL;
}
//
// SystemTable->ConfigurationTable is at offset 112.
// Each entry is 24 bytes: { EFI_GUID Guid; VOID *Table; }.
//
for (Index = 0; Index < TableCount; Index++) {
//
// Compare the table's GUID with gEfiHobListGuid.
//
if (CompareGuidEx (
(EFI_GUID *)((UINT8 *)SystemTable + 112 + Index * 24),
(EFI_GUID *)&mEfiHobListGuid
)) {
//
// Found the HOB list entry. The table pointer is at offset 16
// within each configuration table entry.
//
HobList = *(VOID **)((UINT8 *)SystemTable + 112 + Index * 24 + 16);
break;
}
}
if (HobList == NULL) {
//
// HOB list not found -- this is an error condition.
//
DebugPrintEx (DEBUG_MASK_INIT, "\nASSERT_EFI_ERROR (Status = %r)\n", 0x800000000000000ELL);
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
54,
(__int64)"!EFI_ERROR (Status)"
);
}
//
// If the HOB list was found, verify it is non-NULL.
//
if (HobList == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c",
55,
(__int64)"mHobList != ((void *) 0)"
);
}
mHobList = HobList;
return HobList;
}
// ============================================================================
// _ModuleEntryPoint
// ============================================================================
/**
Main entry point for the UsbOcUpdateDxeLightningRidgeEXECB4 driver.
Initializes the UEFI protocol globals and installs the UBA USB OC
configuration protocol.
Flow:
1. Save gImageHandle, gST, gBS, gRT.
2. Locate the HOB list via GetHobList().
3. Log the board type via DebugPrintEx().
4. Allocate pool for the protocol structure.
5. Install the protocol interface via gBS->InstallProtocolInterface().
@param[in] ImageHandle The firmware-allocated handle for this image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The protocol was installed successfully.
@retval EFI_OUT_OF_RESOURCES Failed to allocate pool.
@retval Others Error from InstallProtocolInterface.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// 1. Initialize UEFI globals.
//
gImageHandle = ImageHandle;
if (ImageHandle == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
(__int64)"gImageHandle != ((void *) 0)"
);
}
gST = SystemTable;
if (SystemTable == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
(__int64)"gST != ((void *) 0)"
);
}
gBS = SystemTable->BootServices;
if (gBS == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
63,
(__int64)"gBS != ((void *) 0)"
);
}
gRT = SystemTable->RuntimeServices;
if (gRT == NULL) {
ReportAssertion (
(__int64)"e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
47,
(__int64)"gRT != ((void *) 0)"
);
}
//
// 2. Locate the HOB list from the system table.
//
GetHobList (SystemTable);
//
// 3. Log board type identification string.
//
DebugPrintEx (
DEBUG_MASK_INFO,
"UBA:UsbOcUpdate-TypeLightningRidgeEXECB4\n"
);
//
// 4. Allocate pool for the UBA USB OC protocol structure.
//
{
UINT32 *ProtocolBuffer;
Status = gBS->AllocatePool (
EfiBootServicesData,
16, // Minimum protocol structure size
(VOID **)&ProtocolBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
ZeroMem (ProtocolBuffer, 16);
//
// 5. Install the UBA USB OC protocol.
//
// The protocol buffer is installed with the board-specific GUID.
// The consumer (USB stack) will use this protocol to determine
// USB port-to-overcurrent-pin mappings.
//
Status = gBS->InstallProtocolInterface (
&ImageHandle,
(EFI_GUID *)&mUbaProtocolGuid,
EFI_NATIVE_INTERFACE,
ProtocolBuffer
);
}
return Status;
}