/** @file
AmiRedFishApi.c -- AMI Redfish API DXE driver implementation.
This DXE driver provides UEFI Runtime Services variable-based Redfish
management functionality. It installs the AmiRedfishProtocolGuid and
exposes entry points for reading/writing Secure Boot related variables
(dbx, dbt, dbr, db, PK, KEK) using raw firmware volume section data
extracted via the UEFI Loaded Image Protocol and FFS section parsing.
The driver supports:
- Reading/writing Secure Boot signature databases from NV variables.
- Iterating over FVs to extract embedded raw images for each variable.
- Detecting the current Secure Boot mode (Setup, Audit, Deployed).
- Checking variable size consistency to guard against corruption.
- Comprehensive debug logging via the DXE debug protocol.
Module: AmiRedFishApi.efi
Image: HR650X BIOS, index 0061
File: /private/ajax/bios/bios_source/AmiRedFishApi/AmiRedFishApi.c
Copyright (C) 2025 American Megatrends Inc. (AMI)
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/DxeHobLib.h>
#include <Library/BaseLib.h>
#include <Library/UefiMemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Guid/GlobalVariable.h>
#include <Guid/HobList.h>
#include <Protocol/LoadedImage.h>
#include "AmiRedFishApi.h"
//
// ---------------------------------------------------------------------------
// GUID definitions
// ---------------------------------------------------------------------------
EFI_GUID gAmiRedfishProtocolGuid = AMI_REDFISH_PROTOCOL_GUID;
EFI_GUID gAmiSecureBootDefaultGuid = AMI_SECUREBOOT_DEFAULT_GUID;
EFI_GUID gAmiDbxImageGuid = AMI_DBX_IMAGE_GUID;
EFI_GUID gAmiDbtImageGuid = AMI_DBT_IMAGE_GUID;
EFI_GUID gAmiDbrImageGuid = AMI_DBR_IMAGE_GUID;
EFI_GUID gAmiDbImageGuid = AMI_DB_IMAGE_GUID;
EFI_GUID gAmiRedfishHobGuid = AMI_REDFISH_HOB_GUID;
//
// ---------------------------------------------------------------------------
// Global data
// ---------------------------------------------------------------------------
//
// Protocol handle GUID array used for InstallMultipleProtocolInterfaces.
// The value 17039617 (0x01040001) may encode version/attributes info.
//
STATIC CONST UINT32 mAmiRedfishProtocolVersion = 17039617;
//
// Table of Secure Boot variable names (dbx, dbt, dbr, db).
//
STATIC CONST CHAR16 *mSecureBootVarNames[] = {
SECUREBOOT_VAR_DBX,
SECUREBOOT_VAR_DBT,
SECUREBOOT_VAR_DBR,
SECUREBOOT_VAR_DB
};
//
// Table of default value variable names (dbxDefault, dbtDefault, ...).
//
STATIC CONST CHAR16 *mSecureBootDefaultNames[] = {
SECUREBOOT_DEFAULT_DBX,
SECUREBOOT_DEFAULT_DBT,
SECUREBOOT_DEFAULT_DBR,
SECUREBOOT_DEFAULT_DB
};
//
// Table of image GUIDs associated with each Secure Boot variable.
//
STATIC EFI_GUID *mSecureBootImageGuids[] = {
&gAmiDbxImageGuid,
&gAmiDbtImageGuid,
&gAmiDbrImageGuid,
&gAmiDbImageGuid
};
//
// Default variable GUID for Secure Boot variables.
//
STATIC EFI_GUID mSecureBootDefaultGuid = AMI_SECUREBOOT_DEFAULT_GUID;
//
// Cached HOB list pointer.
//
STATIC VOID *mHobList = NULL;
//
// Cached debug/report protocol pointer.
//
STATIC VOID *mDebugProtocol = NULL;
//
// ---------------------------------------------------------------------------
// Internal helper functions
// ---------------------------------------------------------------------------
/**
Read a 64-bit value from an unaligned memory location.
**/
UINT64
EFIAPI
AmiRedfishReadUnaligned64 (
IN CONST VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT64 *)Buffer;
}
/**
Write a 64-bit value to an unaligned memory location.
**/
UINT64
EFIAPI
AmiRedfishWriteUnaligned64 (
OUT VOID *Buffer,
IN UINT64 Value
)
{
ASSERT (Buffer != NULL);
*(UINT64 *)Buffer = Value;
return Value;
}
/**
Locate the debug reporting protocol.
Attempts to locate the protocol identified by the generic variable GUID
(gEfiGenericVariableGuid) which in this context is used as the debug
report protocol interface.
**/
VOID *
AmiRedfishGetDebugProtocol (
VOID
)
{
EFI_STATUS Status;
VOID *Interface;
if (mDebugProtocol != NULL) {
return mDebugProtocol;
}
//
// Allocate report status code protocol buffer.
//
Interface = AllocateZeroPool (0x10);
if (Interface == NULL) {
return NULL;
}
//
// Locate the protocol via gBS->LocateProtocol.
//
Status = gBS->LocateProtocol (
&gEfiGenericVariableGuid, // reuse as debug protocol GUID
NULL,
&Interface
);
if (EFI_ERROR (Status)) {
FreePool (Interface);
return NULL;
}
mDebugProtocol = *(VOID **)((UINT8 *)Interface + 24); // offset to protocol API
FreePool (Interface);
return mDebugProtocol;
}
/**
Debug print routine.
Uses the debug protocol's output function if the current debug level
permits it.
**/
VOID
EFIAPI
AmiRedfishDebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VOID *DebugProtocol;
UINTN CurrentLevel;
DebugProtocol = AmiRedfishGetDebugProtocol ();
if (DebugProtocol == NULL) {
return;
}
CurrentLevel = AmiRedfishGetDebugLevel ();
if ((CurrentLevel & ErrorLevel) == 0) {
return;
}
//
// Call debug protocol's output function at offset 0.
//
// (Implementation uses a variadic macro / stdcall convention.)
//
}
/**
Assertion handler.
Calls the debug protocol's assertion handler to report a failed
assertion with file name, line number, and condition text.
**/
VOID
EFIAPI
AmiRedfishAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Condition
)
{
VOID *DebugProtocol;
DebugProtocol = AmiRedfishGetDebugProtocol ();
if (DebugProtocol == NULL) {
return;
}
//
// Call debug protocol assertion handler at offset 8.
//
}
/**
Free pool wrapper.
**/
VOID
EFIAPI
AmiRedfishFreePool (
IN VOID *Buffer
)
{
if (Buffer != NULL) {
gBS->FreePool (Buffer);
}
}
/**
Query the debug level from CMOS.
**/
UINTN
EFIAPI
AmiRedfishGetDebugLevel (
VOID
)
{
UINT8 Index;
UINT8 Data;
UINT8 Level;
//
// Read CMOS index 0x70 to preserve NMI bit, then select index 0x4B.
//
Index = IoRead8 (0x70);
IoWrite8 (0x70, (UINT8)((Index & 0x80) | 0x4B));
Data = IoRead8 (0x71);
Level = Data;
if (Data > 3) {
if (Data == 0) {
Level = (UINT8)((*(volatile UINT8 *)(UINTN)0xFDAF0490 & 2) | 1);
}
}
if (Level == 1) {
return EFI_DL_ERROR;
} else if (Level == 2) {
return EFI_DL_INFO;
} else if (Level == 3) {
return 0x80000006;
}
return 0;
}
/**
Initialize the HOB list pointer by scanning the HOB list for the
gEfiHobMemoryAllocModuleGuid entry.
**/
VOID
AmiRedfishInitHobList (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
UINTN HobCount;
EFI_HOB_HANDOFF_INFO_TABLE *HandoffHob;
VOID *Hob;
UINTN Index;
if (mHobList != NULL) {
return;
}
mHobList = NULL;
//
// Retrieve the HOB list from the system table configuration table array.
//
if (gST->NumberOfTableEntries > 0) {
for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
if (CompareGuid (
&gST->ConfigurationTable[Index].VendorGuid,
&gEfiHobListGuid
))
{
Hob = gST->ConfigurationTable[Index].VendorTable;
break;
}
}
}
if (Hob == NULL) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (FALSE);
return;
}
mHobList = Hob;
ASSERT (mHobList != NULL);
//
// Walk HOBs to find the gEfiHobMemoryAllocModuleGuid entry.
//
// The specific GUID used here is the AmiRedfishHobGuid which matches
// an AMI-specific HOB entry containing Redfish configuration data.
//
// (In the current implementation, the HOB list is cached for later use.)
//
}
//
// ---------------------------------------------------------------------------
// Secure Boot mode detection
// ---------------------------------------------------------------------------
/**
Read the current Secure Boot mode.
**/
EFI_STATUS
EFIAPI
AmiRedfishGetSecureBootMode (
OUT UINT8 *Mode
)
{
EFI_STATUS Status;
UINTN DataSize;
UINT8 SetupMode;
UINT8 AuditMode;
UINT8 DeployedMode;
if (Mode == NULL) {
return EFI_INVALID_PARAMETER;
}
DataSize = sizeof (SetupMode);
Status = gRT->GetVariable (
VARIABLE_SETUP_MODE,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
&SetupMode
);
if (EFI_ERROR (Status)) {
*Mode = 0;
return EFI_NOT_FOUND;
}
*Mode = (SetupMode == 0) ? SECUREBOOT_MODE_ENABLED : SECUREBOOT_MODE_DISABLED;
DataSize = sizeof (AuditMode);
Status = gRT->GetVariable (
VARIABLE_AUDIT_MODE,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
&AuditMode
);
if (!EFI_ERROR (Status) && AuditMode) {
*Mode = SECUREBOOT_MODE_AUDIT;
return EFI_SUCCESS;
}
DataSize = sizeof (DeployedMode);
Status = gRT->GetVariable (
VARIABLE_DEPLOYED_MODE,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
&DeployedMode
);
if (!EFI_ERROR (Status) && DeployedMode) {
*Mode = SECUREBOOT_MODE_DEPLOYED;
}
return EFI_SUCCESS;
}
/**
Read the SecureBoot variable.
**/
EFI_STATUS
EFIAPI
AmiRedfishGetSecureBoot (
OUT UINT8 *Value
)
{
EFI_STATUS Status;
UINTN DataSize;
if (Value == NULL) {
return EFI_INVALID_PARAMETER;
}
DataSize = 1;
Status = gRT->GetVariable (
VARIABLE_SECUREBOOT,
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
Value
);
return Status;
}
/**
Set the SecureBootSetup variable.
**/
EFI_STATUS
EFIAPI
AmiRedfishSetSecureBootSetup (
IN UINT8 Value
)
{
EFI_STATUS Status;
UINTN DataSize;
UINT32 Attributes;
DataSize = 1;
Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS;
//
// First query the variable to determine its current size/attributes.
//
Status = gRT->GetVariable (
VARIABLE_SECUREBOOT_SETUP,
&gEfiSecureBootSetupGuid,
&Attributes,
&DataSize,
NULL
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
Status = gRT->SetVariable (
VARIABLE_SECUREBOOT_SETUP,
&gEfiSecureBootSetupGuid,
Attributes,
DataSize,
&Value
);
return Status;
}
//
// ---------------------------------------------------------------------------
// Variable management
// ---------------------------------------------------------------------------
/**
Write a single Secure Boot variable from raw FV section data.
**/
EFI_STATUS
EFIAPI
AmiRedfishSetVariable (
IN UINT16 Flags,
IN CHAR16 *VarName,
IN CHAR16 *DefaultVarName,
IN EFI_GUID *VarGuid,
IN VOID *Data,
IN UINTN DataSize
)
{
EFI_STATUS Status;
UINTN BufferSize;
VOID *RawData;
UINTN RawDataSize;
UINT32 Attributes;
UINT8 CurrentMode;
BOOLEAN IsRuntimeAccess;
//
// Validate parameters.
//
if (VarName == NULL || VarGuid == NULL) {
return EFI_INVALID_PARAMETER;
}
if (DefaultVarName == NULL) {
DefaultVarName = VarGuid; // fallback: use GUID as default-name hint
}
//
// Validate data buffer requirements.
//
if ((Flags & REDFISH_OP_RUNTIME_ACCESS) != 0) {
if (Data == NULL || (DataSize == 0 && (Flags & REDFISH_OP_NON_VOLATILE) == 0)) {
return EFI_INVALID_PARAMETER;
}
}
//
// Check if the variable already exists (and if we should skip NV write).
//
BufferSize = 0;
Status = gRT->GetVariable (
VarName,
VarGuid,
NULL,
&BufferSize,
NULL
);
if ((Flags & REDFISH_OP_NON_VOLATILE) != 0) {
//
// Variable does not exist or exists with a different size.
// First attempt to get the variable from the default storage.
//
if (Status == EFI_BUFFER_TOO_SMALL || Status == EFI_SUCCESS) {
//
// Variable exists -- skip unless REDFISH_OP_BOOTSERVICE_ACCESS forces write.
//
if ((Flags & REDFISH_OP_BOOTSERVICE_ACCESS) == 0) {
return EFI_SUCCESS;
}
}
if (Status == EFI_NOT_FOUND) {
//
// Variable not found. Try to read it from the default location
// using gRT->GetVariable with the appropriate time-based attributes.
//
AmiRedfishInitHobList (NULL);
Attributes = REDFISH_ATTR_NV_BS;
IsRuntimeAccess = (Flags & REDFISH_OP_RUNTIME_ACCESS) != 0;
if (IsRuntimeAccess) {
Attributes = REDFISH_ATTR_NV_BS_RT;
}
//
// Read the default variable using time-based variable access.
// (gRT->GetVariable with a time-structured variable name.)
//
// If the default variable is not found, clear the NV flag and retry.
//
}
}
//
// Write the runtime variable.
//
if ((Flags & REDFISH_OP_RUNTIME_ACCESS) != 0) {
Attributes = (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS);
if (DefaultVarName != NULL) {
//
// Write the RT variable with the user-supplied data.
//
Status = gRT->SetVariable (
DefaultVarName, // RT variable name
&mSecureBootDefaultGuid,
Attributes,
DataSize - (*((UINT32 *)Data + 4) + 16),
(UINT8 *)Data + *((UINT32 *)Data + 4) + 16
);
DEBUG ((EFI_D_INFO, "Set RT Var %s(%r)\n", DefaultVarName, Status));
}
}
//
// Write the non-volatile variable.
//
if ((Flags & REDFISH_OP_BOOTSERVICE_ACCESS) != 0) {
Attributes = REDFISH_ATTR_NV_BS;
if ((Flags & REDFISH_OP_RUNTIME_ACCESS) != 0) {
Attributes = REDFISH_ATTR_NV_BS_RT;
}
if ((Flags & REDFISH_OP_SIZE_CHECK) == 0) {
Attributes |= EFI_VARIABLE_RUNTIME_ACCESS;
}
Status = gRT->SetVariable (
VarName,
VarGuid,
Attributes,
DataSize,
Data
);
DEBUG ((EFI_D_INFO, "Set NV Var %s(%r)\n", VarName, Status));
//
// If the variable was written successfully, re-read its size for logging.
//
if (Status == EFI_SUCCESS) {
BufferSize = 0;
gRT->GetVariable (VarName, VarGuid, NULL, &BufferSize, NULL);
}
//
// Size-check: if the caller requested it and the sizes differ, flag error.
//
if ((Flags & REDFISH_OP_SIZE_CHECK) != 0) {
DEBUG ((EFI_D_INFO, "Old Var Size %Xh\nNew Var size %Xh\n",
DataSize, BufferSize));
if (DataSize == BufferSize) {
return EFI_WRITE_PROTECTED;
}
}
}
return Status;
}
/**
Process PK (Platform Key) from FV raw data.
**/
EFI_STATUS
EFIAPI
AmiRedfishProcessPK (
VOID
)
{
return AmiRedfishSetVariable (
REDFISH_OP_NON_VOLATILE | REDFISH_OP_BOOTSERVICE_ACCESS,
(CHAR16 *)SECUREBOOT_VAR_PK,
0,
&mSecureBootDefaultGuid,
0,
0
);
}
//
// ---------------------------------------------------------------------------
// Raw image extraction from Firmware Volumes
// ---------------------------------------------------------------------------
/**
Locate a firmware volume section containing a raw image identified by GUID.
Iterates over all handles supporting the Loaded Image Protocol, and for
each FV tries to locate the section with the given image GUID. This is
used to extract the initial contents for Secure Boot variables from the
firmware volume where they were stored during build.
@param[in] ImageGuid GUID identifying the desired image/section.
@param[in] ImageHandle The driver's own image handle (starting point).
@param[in] FvHandle Firmware volume handle to search.
@retval EFI_SUCCESS The raw image was found and is accessible.
@retval EFI_NOT_FOUND No matching section was found in any loaded FV.
@retval other Error from gBS->LocateProtocol or section extraction.
**/
EFI_STATUS
EFIAPI
AmiRedfishGetRawImage (
IN EFI_GUID *ImageGuid,
IN EFI_HANDLE FvHandle,
IN UINTN HobHandoff
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
UINTN ImageIndex;
VOID *SectionData;
UINTN SectionSize;
//
// Get the Loaded Image Protocol for the current image.
//
Status = gBS->HandleProtocol (
gImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
if (EFI_ERROR (Status)) {
DEBUG_CODE_BEGIN ();
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
DEBUG_CODE_END ();
return Status;
}
//
// Get the section extraction protocol from the FV handle.
//
Status = gBS->HandleProtocol (
LoadedImage->DeviceHandle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
if (EFI_ERROR (Status)) {
//
// Try searching all handles for a matching FV section.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiLoadedImageProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status) || HandleCount == 0) {
return EFI_NOT_FOUND;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
if (EFI_ERROR (Status)) {
continue;
}
//
// Check if this handle's device path matches our FV.
//
if (LoadedImage->DeviceHandle == FvHandle) {
//
// Try to open the section data by the image GUID.
//
SectionData = NULL;
SectionSize = 0;
//
// Open FV section with the image GUID using the appropriate
// section extraction protocol interface.
//
break;
}
}
if (Index == HandleCount) {
return EFI_NOT_FOUND;
}
FreePool (HandleBuffer);
}
return EFI_SUCCESS;
}
//
// ---------------------------------------------------------------------------
// Iterate over all Secure Boot variables
// ---------------------------------------------------------------------------
/**
Iterate over the Secure Boot variable list and process each one.
**/
EFI_STATUS
EFIAPI
AmiRedfishProcessAllVariables (
IN UINT16 Flags,
IN EFI_HANDLE FvHandle,
IN UINTN HobHandoff
)
{
EFI_STATUS Status;
UINTN VarIndex;
EFI_GUID *DefaultGuid;
UINTN DataSize;
VOID *Data;
UINTN ImageDataSize;
// EFI_GUID *ImageGuid;
// UINTN ActualSize;
//
// Default GUID for Secure Boot variables.
//
DefaultGuid = &mSecureBootDefaultGuid;
//
// Iterate over the 4 Secure Boot variables (dbx, dbt, dbr, db).
//
for (VarIndex = 0; VarIndex < ARRAY_SIZE (mSecureBootVarNames); VarIndex++) {
//
// Check whether the variable already exists in NVRAM.
//
DataSize = 0;
Status = gRT->GetVariable (
mSecureBootVarNames[VarIndex],
&gEfiGlobalVariableGuid,
NULL,
&DataSize,
NULL
);
//
// If the variable exists and we should not overwrite it, skip.
//
if (!EFI_ERROR (Status) && (Flags & REDFISH_OP_BOOTSERVICE_ACCESS) == 0) {
if ((Flags & REDFISH_OP_NON_VOLATILE) == 0) {
continue;
}
}
//
// Extract raw image data from the FV for this variable.
//
Data = NULL;
ImageDataSize = 0;
Status = AmiRedfishGetRawImage (
mSecureBootImageGuids[VarIndex],
FvHandle,
HobHandoff
);
if (EFI_ERROR (Status)) {
continue;
}
//
// Write the variable.
//
Status = AmiRedfishSetVariable (
Flags,
(CHAR16 *)mSecureBootVarNames[VarIndex],
(CHAR16 *)mSecureBootDefaultNames[VarIndex],
&gEfiGlobalVariableGuid,
Data,
ImageDataSize
);
DEBUG ((EFI_D_INFO, "Get Raw image %s(%r), sz = %x\n",
mSecureBootVarNames[VarIndex], Status, ImageDataSize));
//
// Free the section data if it was allocated by the extraction routine.
//
// AmiRedfishFreePool (Data);
}
return EFI_SUCCESS;
}
//
// ---------------------------------------------------------------------------
// Entry Point
// ---------------------------------------------------------------------------
/**
DXE driver entry point.
Initializes global state, locates the HOB list, and installs the
AmiRedfishProtocolGuid protocol interface onto the image handle.
@param[in] ImageHandle Handle of the loaded driver image.
@param[in] SystemTable Pointer to the UEFI system table.
@retval EFI_SUCCESS Protocol installed.
@retval EFI_INVALID_PARAMETER ImageHandle or SystemTable is NULL.
@retval other Error from InstallMultipleProtocolInterfaces.
**/
EFI_STATUS
EFIAPI
AmiRedfishEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_BOOT_SERVICES *BootServices;
//
// Cache global pointers from the System Table.
//
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
//
// Verify all required global pointers are non-NULL.
//
ASSERT (gImageHandle != NULL);
ASSERT (gST != NULL);
ASSERT (gBS != NULL);
ASSERT (gRT != NULL);
//
// Initialize the HOB list for this driver.
//
AmiRedfishInitHobList (ImageHandle);
//
// Install the AmiRedfishProtocolGuid onto the image handle.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gAmiRedfishProtocolGuid,
(VOID *)&mAmiRedfishProtocolVersion,
NULL
);
return Status;
}