//-------------------------------------------------------------------------
// SmmLockBox.c - SMM LockBox Driver for HR650X (AMI UEFI firmware)
// Source: MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
// MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
// Build: DEBUG_VS2015 X64
//
// This SMM driver provides LockBox save/restore services within SMM.
// It registers an SMI handler that processes LockBox commands sent
// via the SMM Communication Buffer protocol.
//
// Address Range: 0x2C0 - 0x16C0 (26 functions)
//-------------------------------------------------------------------------
#include "SmmLockBox.h"
//-------------------------------------------------------------------------
// External Protocol GUIDs (defined in .rdata at 0x2540-0x2590)
//-------------------------------------------------------------------------
extern EFI_GUID gSmmBase2ProtocolGuid; // {f4ccbfb7-...}
extern EFI_GUID gAmiSmmCommunicationProtocolGuid; // {bd445d79-...}
extern EFI_GUID gAmiSmmSwDispatch2ProtocolGuid; // {2a3cfebd-...}
extern EFI_GUID gAmiSmmCpuIoProtocolGuid; // {441ffa18-...}
//-------------------------------------------------------------------------
// Global Variables (defined in .data segment)
//-------------------------------------------------------------------------
EFI_SYSTEM_TABLE *gSystemTable; // 0x25B8
EFI_BOOT_SERVICES *gBootServices; // 0x25C0
EFI_HANDLE gImageHandle; // 0x25C8
EFI_RUNTIME_SERVICES *gRuntimeServices; // 0x25D0
UINT64 gSmst; // 0x25D8
UINT64 gSmmDebug2; // 0x25E0 (SMM Debug2 protocol)
UINT64 gSmmBufferValidation; // 0x25E8 (AMI SMM Buffer Validation)
UINT8 gLocked; // 0x25B0 (boolean, set by LockBox lock)
UINT8 gContextInstalled; // 0x25F0 (boolean)
UINT64 gModuleStatus; // 0x26F8 (module init status)
LOCK_BOX_CONTEXT gLockBoxContext; // 0x2700
//-------------------------------------------------------------------------
// Forward Declarations
//-------------------------------------------------------------------------
EFI_STATUS
EFIAPI
SmmLockBoxHandler(
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *CommunicationBuffer OPTIONAL,
IN OUT UINTN *CommunicationBufferSize OPTIONAL
);
EFI_STATUS
LockBoxLock(
VOID
);
EFI_STATUS
LockBoxSave(
IN EFI_GUID *Guid,
IN VOID *Buffer,
IN UINTN Length
);
EFI_STATUS
LockBoxUpdate(
IN EFI_GUID *Guid,
IN VOID *Buffer,
IN UINTN Length,
IN UINTN Offset
);
EFI_STATUS
LockBoxRestore(
IN EFI_GUID *Guid,
IN OUT VOID *Buffer OPTIONAL,
IN OUT UINTN *Length OPTIONAL
);
EFI_STATUS
LockBoxSetAttributes(
IN EFI_GUID *Guid,
IN UINT64 Attributes
);
EFI_STATUS
LockBoxRestoreAllInPlace(
VOID
);
//=========================================================================
// Module Entry Point
//=========================================================================
EFI_STATUS
EFIAPI
ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
//
// Flow:
// 1. Process library constructors (sub_540)
// 2. Set gModuleStatus to EFI_SUCCESS (initial)
// 3. Acquire lock (unlikely to fail at init)
// 4. Register SMI handler (sub_C7C)
// 5. Update gModuleStatus on failure
// 6. Release lock
// 7. If module init failed, call destructor
//
{
EFI_STATUS Status;
// Process all library constructors (UEFI Boot/Runtime/SMM services tables)
ProcessLibraryConstructorList(ImageHandle, SystemTable);
gModuleStatus = EFI_SUCCESS;
if (!AcquireLock(&gLockBoxContext)) {
Status = RegisterSmmLockBoxHandler(ImageHandle);
if (EFI_ERROR(Status) || EFI_ERROR(gModuleStatus)) {
gModuleStatus = Status;
}
ReleaseLock(&gLockBoxContext);
RestoreLock(&gLockBoxContext, (UINTN)-1);
}
if (EFI_ERROR(gModuleStatus)) {
SmmLockBoxDestructor();
}
return gModuleStatus;
}
//=========================================================================
// ProcessLibraryConstructorList (sub_540)
//=========================================================================
EFI_STATUS
ProcessLibraryConstructorList(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
//
// Initializes all library global pointers:
// gImageHandle, gSystemTable, gBootServices, gRuntimeServices
// Then locates SMM Base2 Protocol and SMM Buffer Validation Protocol.
//
{
EFI_STATUS Status;
VOID *Interface;
gImageHandle = ImageHandle;
ASSERT(gImageHandle != NULL);
gSystemTable = (UINT64)(UINTN)SystemTable;
ASSERT(gSystemTable != NULL);
gBootServices = (UINT64)(UINTN)SystemTable->BootServices;
ASSERT(gBootServices != NULL);
gRuntimeServices = (UINT64)(UINTN)SystemTable->RuntimeServices;
ASSERT(gRuntimeServices != NULL);
// Locate SMM Base2 Protocol
Status = SystemTable->BootServices->LocateProtocol(
&gSmmBase2ProtocolGuid,
NULL,
&Interface
);
ASSERT_EFI_ERROR(Status);
ASSERT(Interface != NULL);
// Get SMM System Table from SMM Base2 Protocol
((EFI_SMM_BASE2_PROTOCOL *)Interface)->GetSmstLocation(
Interface,
&gSmst
);
ASSERT(gSmst != NULL);
// Locate AMI SMM Buffer Validation Protocol
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmLocateProtocol(
&gAmiSmmBufferValidationProtocolGuid,
NULL,
&gSmmBufferValidation
);
if (EFI_ERROR(Status)) {
gSmmBufferValidation = 0;
}
// Install LockBox Communication Configuration Table
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
if (LockBoxContextGet() != NULL) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
return EFI_SUCCESS;
}
gLockBoxContext.Signature = LOCK_BOX_SIGNATURE;
gLockBoxContext.LockBoxQueue.Flink = &gLockBoxContext.LockBoxQueue;
gLockBoxContext.LockBoxQueue.Blink = &gLockBoxContext.LockBoxQueue;
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmInstallConfigurationTable(
gSmst,
&gAmiSmmCommunicationProtocolGuid,
&gLockBoxContext,
sizeof(gLockBoxContext)
);
ASSERT_EFI_ERROR(Status);
gContextInstalled = TRUE;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", &gLockBoxContext));
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", &gLockBoxContext.LockBoxQueue));
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
return Status;
}
//=========================================================================
// Get LockBox Context
//=========================================================================
LOCK_BOX_CONTEXT *
LockBoxContextGet(
VOID
)
//
// Searches the SMM configuration table for the LockBox context.
// Returns NULL if not installed.
//
{
EFI_SMM_SYSTEM_TABLE2 *Smst;
UINTN Index;
Smst = (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst;
if (Smst == NULL || Smst->NumberOfTableEntries == 0) {
return NULL;
}
for (Index = 0; Index < Smst->NumberOfTableEntries; Index++) {
if (CompareGuid(&Smst->SmmConfigurationTable[Index].VendorGuid,
&gAmiSmmCommunicationProtocolGuid)) {
return (LOCK_BOX_CONTEXT *)Smst->SmmConfigurationTable[Index].VendorTable;
}
}
return NULL;
}
//=========================================================================
// Register SMI Handler (sub_C7C)
//=========================================================================
EFI_STATUS
RegisterSmmLockBoxHandler(
IN EFI_HANDLE ImageHandle
)
//
// Registers SmmLockBoxHandler as the SMI handler for the
// AMI SMM Communication protocol, plus a SW dispatch callback
// (LockBoxLock) and installs the protocol.
//
{
EFI_STATUS Status;
EFI_HANDLE DispatchHandle;
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
// Register the main communication handler via SMM Base2
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmiHandlerRegister(
SmmLockBoxHandler,
&gAmiSmmCommunicationProtocolGuid,
&CommunicationHandle
);
ASSERT_EFI_ERROR(Status);
// Register the lock callback via SW dispatch
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmRegisterProtocolNotify(
&gAmiSmmSwDispatch2ProtocolGuid,
LockBoxLock,
&SwContext
);
ASSERT_EFI_ERROR(Status);
// Install protocol to make the interface available
DispatchHandle = NULL;
Status = gBootServices->InstallProtocolInterface(
&DispatchHandle,
&gAmiSmmCommunicationProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR(Status);
return Status;
}
//=========================================================================
// SmmLockBoxHandler (sub_988)
//=========================================================================
EFI_STATUS
EFIAPI
SmmLockBoxHandler(
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *CommunicationBuffer OPTIONAL,
IN OUT UINTN *CommunicationBufferSize OPTIONAL
)
//
// Main SMI handler for LockBox commands.
// Dispatches to sub-handlers based on Command field:
// 1 -> SaveLockBox
// 2 -> UpdateLockBox
// 3 -> RestoreLockBox
// 4 -> SetLockBoxAttributes
// 5 -> RestoreAllLockBoxInPlace
//
// CommunicationBuffer layout:
// +0x00: UINT32 Command
// +0x04: UINT32 Pad
// +0x08: EFI_GUID Guid
// +0x18: UINT64 Length
// +0x20: UINT64 Offset/RestoreBuffer
// +0x28: UINT64 Buffer (pointer to data, validated)
//
{
LOCK_BOX_PARAMETER_HEADER *Header;
UINTN BufferSize;
EFI_STATUS ReturnStatus;
DEBUG((EFI_D_INFO, "SmmLockBox SmmLockBoxHandler Enter\n"));
if (CommunicationBuffer == NULL || CommunicationBufferSize == NULL) {
return EFI_INVALID_PARAMETER;
}
Header = (LOCK_BOX_PARAMETER_HEADER *)CommunicationBuffer;
BufferSize = *CommunicationBufferSize;
// Validate minimum buffer size
if (BufferSize < sizeof(LOCK_BOX_PARAMETER_HEADER)) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));
goto ErrorExit;
}
// Validate buffer is not in SMRAM or overflow
if (SmmBufferValidation(
CommunicationBuffer,
BufferSize
) < 0) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));
goto ErrorExit;
}
// Default return status
Header->ReturnStatus = (UINT64)-1;
DEBUG((EFI_D_INFO, "SmmLockBox LockBoxParameterHeader - %x\n", Header));
DEBUG((EFI_D_INFO, "SmmLockBox Command - %x\n", Header->Command));
switch (Header->Command) {
case LOCK_BOX_COMMAND_SAVE:
if (BufferSize < 0x30) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));
break;
}
if (gLocked) {
DEBUG((EFI_D_ERROR, "SmmLockBox Locked!\n"));
ReturnStatus = LOCK_BOX_STATUS_LOCKED;
} else {
LOCK_BOX_PARAMETER_HEADER LocalCopy;
CopyMem(&LocalCopy, Header, sizeof(LOCK_BOX_PARAMETER_HEADER));
if (SmmBufferValidation(LocalCopy.Buffer, LocalCopy.Length) >= 0) {
ReturnStatus = SmmLockBoxSaveLockBox(
&LocalCopy.Guid,
LocalCopy.Buffer,
LocalCopy.Length
);
} else {
DEBUG((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));
ReturnStatus = LOCK_BOX_STATUS_LOCKED;
}
}
break;
case LOCK_BOX_COMMAND_UPDATE:
if (BufferSize < 0x38) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));
break;
}
if (gLocked) {
DEBUG((EFI_D_ERROR, "SmmLockBox Locked!\n"));
ReturnStatus = LOCK_BOX_STATUS_LOCKED;
} else {
LOCK_BOX_PARAMETER_HEADER LocalCopy;
CopyMem(&LocalCopy, Header, sizeof(LOCK_BOX_PARAMETER_HEADER));
if (SmmBufferValidation(LocalCopy.Buffer, LocalCopy.Length) >= 0) {
ReturnStatus = SmmLockBoxUpdateLockBox(
&LocalCopy.Guid,
LocalCopy.Buffer,
LocalCopy.Length,
LocalCopy.Offset
);
} else {
DEBUG((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));
ReturnStatus = LOCK_BOX_STATUS_LOCKED;
}
}
break;
case LOCK_BOX_COMMAND_RESTORE:
if (BufferSize < 0x30) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));
break;
}
{
LOCK_BOX_PARAMETER_HEADER LocalCopy;
CopyMem(&LocalCopy, Header, sizeof(LOCK_BOX_PARAMETER_HEADER));
if (LocalCopy.Buffer == NULL && LocalCopy.Length == 0) {
ReturnStatus = SmmLockBoxRestoreLockBox(
&LocalCopy.Guid,
NULL,
NULL
);
} else if (SmmBufferValidation(LocalCopy.Buffer, LocalCopy.Length) >= 0) {
ReturnStatus = SmmLockBoxRestoreLockBox(
&LocalCopy.Guid,
LocalCopy.Buffer,
&LocalCopy.Length
);
} else {
DEBUG((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));
ReturnStatus = LOCK_BOX_STATUS_LOCKED;
}
}
break;
case LOCK_BOX_COMMAND_SET_ATTRIBUTES:
if (BufferSize < 0x28) {
DEBUG((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));
break;
}
ReturnStatus = SmmLockBoxSetLockBoxAttributes(Header);
break;
case LOCK_BOX_COMMAND_RESTORE_ALL:
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
ReturnStatus = SmmLockBoxRestoreAllLockBoxInPlace();
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", ReturnStatus));
Header->ReturnStatus = 0;
break;
default:
DEBUG((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));
break;
}
ExitHandler:
Header->Command = (UINT32)-1; // Mark as processed
DEBUG((EFI_D_INFO, "SmmLockBox SmmLockBoxHandler Exit\n"));
return EFI_SUCCESS;
}
//=========================================================================
// SmmLockBoxSaveLockBox (sub_1128)
//=========================================================================
EFI_STATUS
SmmLockBoxSaveLockBox(
IN EFI_GUID *Guid,
IN VOID *Buffer,
IN UINTN Length
)
//
// Saves a data buffer into SMRAM as a new LockBox entry.
//
// Flow:
// 1. Check if entry with this GUID already exists -> EFI_ALREADY_STARTED
// 2. Allocate SMRAM pages for the data buffer
// 3. Allocate SMRAM pool for the LOCK_BOX_ENTRY structure (72 bytes)
// 4. Copy data to SMRAM buffer
// 5. Initialize entry fields
// 6. Insert entry into the LockBox queue (linked list)
//
{
LOCK_BOX_ENTRY *NewEntry;
EFI_PHYSICAL_ADDRESS SmramBuffer;
UINTN Pages;
EFI_STATUS Status;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
if (Guid == NULL || Buffer == NULL || Length == 0) {
return EFI_INVALID_PARAMETER;
}
// Check if already exists
NewEntry = InternalFindLockBoxEntry(Guid);
if (NewEntry != NULL) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
return EFI_ALREADY_STARTED;
}
// Allocate SMRAM pages for the data
Pages = EFI_SIZE_TO_PAGES(Length);
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmAllocatePages(
AllocateAnyPages,
EfiRuntimeServicesData,
Pages,
&SmramBuffer
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
return EFI_OUT_OF_RESOURCES;
}
// Allocate the entry structure
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmAllocatePool(
EfiRuntimeServicesData,
sizeof(LOCK_BOX_ENTRY),
&NewEntry
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmFreePages(SmramBuffer, Pages);
return EFI_OUT_OF_RESOURCES;
}
// Copy data to SMRAM
CopyMem((VOID *)(UINTN)SmramBuffer, Buffer, Length);
// Initialize entry
NewEntry->Signature = LOCK_BOX_SIGNATURE;
CopyGuid(&NewEntry->Guid, Guid);
NewEntry->SmramBuffer = SmramBuffer;
NewEntry->Length = Length;
NewEntry->Attributes = 0;
NewEntry->Pages = Pages;
DEBUG((EFI_D_INFO, "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n",
Guid, SmramBuffer, Length));
// Insert into queue
InsertTailList(&LockBoxContextGet()->LockBoxQueue, &NewEntry->Link);
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
return EFI_SUCCESS;
}
//=========================================================================
// SmmLockBoxUpdateLockBox (sub_135C)
//=========================================================================
EFI_STATUS
SmmLockBoxUpdateLockBox(
IN EFI_GUID *Guid,
IN VOID *Buffer,
IN UINTN Length,
IN UINTN Offset
)
//
// Updates a portion of an existing LockBox entry at a given offset.
//
// Flow:
// 1. Find existing entry by GUID
// 2. Validate offset + length does not exceed original size
// 3. Copy data to SMRAM buffer at offset
//
{
LOCK_BOX_ENTRY *Entry;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
if (Guid == NULL || Buffer == NULL || Length == 0) {
return EFI_INVALID_PARAMETER;
}
Entry = InternalFindLockBoxEntry(Guid);
if (Entry == NULL) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
return EFI_NOT_FOUND;
}
if (Entry->Length < Offset + Length) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
return EFI_BUFFER_TOO_SMALL;
}
ASSERT((UINTN)Entry->SmramBuffer <= (MAX_UINTN - Offset));
CopyMem(
(VOID *)((UINTN)Entry->SmramBuffer + Offset),
Buffer,
Length
);
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
return EFI_SUCCESS;
}
//=========================================================================
// SmmLockBoxRestoreLockBox (sub_1468)
//=========================================================================
EFI_STATUS
SmmLockBoxRestoreLockBox(
IN EFI_GUID *Guid,
IN OUT VOID *Buffer OPTIONAL,
IN OUT UINTN *Length OPTIONAL
)
//
// Restores data from a LockBox entry back to a caller-provided buffer.
//
// Flow:
// 1. Find existing entry by GUID
// 2. If caller passes Length == NULL, query restore-in-place attribute
// and use the saved SmramBuffer address (restore-in-place)
// 3. If caller provides a buffer, copy data out of SMRAM
// 4. Return the required buffer size via Length
//
{
LOCK_BOX_ENTRY *Entry;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
if (Guid == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Buffer == NULL && Length != NULL) {
return EFI_INVALID_PARAMETER;
}
if (Buffer != NULL && Length == NULL) {
return EFI_INVALID_PARAMETER;
}
Entry = InternalFindLockBoxEntry(Guid);
if (Entry == NULL) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
return EFI_NOT_FOUND;
}
// Restore-in-place: caller wants to use SMRAM buffer directly
if (Buffer == NULL) {
if ((Entry->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
return EFI_BUFFER_TOO_SMALL;
}
Buffer = (VOID *)(UINTN)Entry->SmramBuffer;
}
// Report required size
if (Length != NULL) {
if (*Length < Entry->Length) {
*Length = Entry->Length;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
return EFI_BUFFER_TOO_SMALL;
}
}
// Copy data out of SMRAM
if (Entry->Length > 0) {
CopyMem(Buffer, (VOID *)(UINTN)Entry->SmramBuffer, Entry->Length);
}
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
return EFI_SUCCESS;
}
//=========================================================================
// SmmLockBoxSetLockBoxAttributes (sub_8AC)
//=========================================================================
EFI_STATUS
SmmLockBoxSetLockBoxAttributes(
IN LOCK_BOX_PARAMETER_HEADER *Header
)
//
// Sets the attributes on an existing LockBox entry.
// The only currently supported attribute is bit 0:
// LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE (0x1)
//
// Flow:
// 1. Parse GUID and Attributes from Header
// 2. Copy header locally (since buffer may be in non-SMRAM)
// 3. Validate attributes (only bit 0 allowed)
// 4. Find entry by GUID
// 5. Update attributes in entry
//
{
LOCK_BOX_PARAMETER_HEADER LocalCopy;
LOCK_BOX_ENTRY *Entry;
UINT64 Attributes;
if (gLocked) {
DEBUG((EFI_D_ERROR, "SmmLockBox Locked!\n"));
Header->ReturnStatus = LOCK_BOX_STATUS_LOCKED;
return LOCK_BOX_STATUS_LOCKED;
}
CopyMem(&LocalCopy, Header, 40); // Copy header (0x28 bytes)
Attributes = LocalCopy.Attributes;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
// Validate attributes (only bit 0 is valid)
if ((Attributes & ~LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
Header->ReturnStatus = EFI_INVALID_PARAMETER;
return EFI_INVALID_PARAMETER;
}
Entry = InternalFindLockBoxEntry(&LocalCopy.Guid);
if (Entry == NULL) {
Header->ReturnStatus = EFI_NOT_FOUND;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", Header->ReturnStatus));
return EFI_NOT_FOUND;
}
Entry->Attributes = Attributes;
Header->ReturnStatus = EFI_SUCCESS;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", Header->ReturnStatus));
return EFI_SUCCESS;
}
//=========================================================================
// SmmLockBoxRestoreAllLockBoxInPlace (from sub_988[command=5])
//=========================================================================
EFI_STATUS
SmmLockBoxRestoreAllLockBoxInPlace(
VOID
)
//
// Iterates the LockBox queue and for each entry with the
// RESTORE_IN_PLACE attribute, copies the SMRAM data to the
// original buffer address (stored in the entry).
//
{
LIST_ENTRY *ListHead;
LOCK_BOX_ENTRY *Entry;
LIST_ENTRY *Node;
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
ListHead = &LockBoxContextGet()->LockBoxQueue;
ASSERT(ListHead != NULL);
for (Node = ListHead->Flink; Node != ListHead; Node = Node->Flink) {
Entry = CR(Node, LOCK_BOX_ENTRY, Link, LOCK_BOX_SIGNATURE);
if ((Entry->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
if (Entry->Length > 0) {
CopyMem(
(VOID *)(UINTN)Entry->SmramBuffer,
// Note: The 'SmramBuffer' here doubles as the original
// address when restore-in-place was requested
(VOID *)(UINTN)Entry->SmramBuffer, // Actually saved destination
Entry->Length
);
}
}
}
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
return EFI_SUCCESS;
}
//=========================================================================
// InternalFindLockBoxEntry (sub_10B0)
//=========================================================================
LOCK_BOX_ENTRY *
InternalFindLockBoxEntry(
IN EFI_GUID *Guid
)
//
// Walks the LockBox queue searching for an entry with matching GUID.
// Returns pointer to the entry, or NULL if not found.
//
{
LIST_ENTRY *ListHead;
LIST_ENTRY *Node;
ListHead = &LockBoxContextGet()->LockBoxQueue;
ASSERT(ListHead != NULL);
for (Node = ListHead->Flink; Node != ListHead; Node = Node->Flink) {
LOCK_BOX_ENTRY *Entry;
Entry = CR(Node, LOCK_BOX_ENTRY, Link, LOCK_BOX_SIGNATURE);
if (CompareGuid(&Entry->Guid, Guid)) {
return Entry;
}
}
return NULL;
}
//=========================================================================
// InternalBaseLibIsListValid (sub_15C8)
//=========================================================================
BOOLEAN
InternalBaseLibIsListValid(
IN LIST_ENTRY *ListHead
)
//
// Validates a linked list has non-null forward/back links.
//
{
ASSERT(ListHead != NULL);
ASSERT(ListHead->Flink != NULL);
ASSERT(ListHead->Blink != NULL);
return TRUE;
}
//=========================================================================
// InsertTailList (sub_1634)
//=========================================================================
VOID
InsertTailList(
IN LIST_ENTRY *ListHead,
IN LIST_ENTRY *Entry
)
//
// Standard doubly-linked list insert at tail.
//
{
LIST_ENTRY *Blink;
ASSERT(InternalBaseLibIsListValid(ListHead));
Blink = ListHead->Blink;
Entry->Flink = ListHead;
Entry->Blink = Blink;
Blink->Flink = Entry;
ListHead->Blink = Entry;
}
//=========================================================================
// CompareGuid (sub_1560)
//=========================================================================
BOOLEAN
CompareGuid(
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
//
// Compares two EFI_GUID structures.
//
{
UINT64 *Data1;
UINT64 *Data2;
Data1 = (UINT64 *)Guid1;
Data2 = (UINT64 *)Guid2;
Data1 = (UINT64 *)ReadUnaligned64(Guid1);
Data2 = (UINT64 *)ReadUnaligned64(Guid2);
return Data1[0] == Data2[0] && Data1[1] == Data2[1];
}
//=========================================================================
// ReadUnaligned64 (sub_1688)
//=========================================================================
UINT64
ReadUnaligned64(
IN CONST VOID *Buffer
)
//
// Reads a 64-bit value from a potentially unaligned address.
//
{
ASSERT(Buffer != NULL);
return *(UINT64 *)Buffer;
}
//=========================================================================
// Buffer Validation (sub_F98)
//=========================================================================
EFI_STATUS
SmmBufferValidation(
IN CONST VOID *Buffer,
IN UINTN Length
)
//
// Validates that Buffer+Length is NOT in SMRAM and does not overflow.
// Uses the AMI SMM Buffer Validation Protocol if available.
//
{
if (gSmmBufferValidation == 0) {
return EFI_NOT_FOUND;
}
return ((AMI_SMM_BUFFER_VALIDATION_PROTOCOL *)(UINTN)gSmmBufferValidation)
->IsBufferOutsideValid(Buffer, Length);
}
//=========================================================================
// LockBoxLock (sub_C70)
//=========================================================================
EFI_STATUS
LockBoxLock(
VOID
)
//
// Sets the gLocked flag, preventing any further SAVE/UPDATE operations.
// This is called when a SW dispatch event fires (S3 resume, etc.)
//
{
gLocked = TRUE;
return EFI_SUCCESS;
}
//=========================================================================
// Log Messages (sub_DE8 - DEBUG wrapper)
//=========================================================================
VOID
EFIAPI
LogMessage(
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
//
// Wraps DEBUG print via SMM Debug2 protocol.
// Checks CMOS 0x4C for debug level filtering.
//
{
VA_LIST Marker;
UINT8 DebugLevel;
if (gSmmDebug2 == 0) {
return;
}
// Check CMOS for debug level
IoWrite8(0x70, IoRead8(0x70) & 0x80 | 0x4C);
DebugLevel = IoRead8(0x71);
if (DebugLevel > 0x03) {
if (DebugLevel == 0) {
DebugLevel = (MmioRead8(0xFEDAF0490) & 2) | 1;
}
}
if ((DebugLevel - 1) <= 0xFD) {
// Use the SMM Debug2 protocol to print
VA_START(Marker, Format);
((SMM_DEBUG2_PROTOCOL *)(UINTN)gSmmDebug2)->DebugPrint(
ErrorLevel,
Format,
Marker
);
VA_END(Marker);
}
}
//=========================================================================
// ASSERT_EFI_ERROR helper
//=========================================================================
VOID
EFIAPI
AssertEfiError(
IN EFI_STATUS Status
)
//
// Logs an assertion failure when Status is an error.
//
{
if (EFI_ERROR(Status)) {
LogMessage(EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
}
}
//=========================================================================
// SmmLockBoxDestructor (sub_824)
//=========================================================================
VOID
SmmLockBoxDestructor(
VOID
)
//
// Uninstalls the LockBox communication configuration table.
// Called on module exit/destruction.
//
{
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n"));
if (gContextInstalled) {
EFI_STATUS Status;
Status = ((EFI_SMM_SYSTEM_TABLE2 *)(UINTN)gSmst)->SmmInstallConfigurationTable(
gSmst,
&gAmiSmmCommunicationProtocolGuid,
NULL,
0
);
ASSERT_EFI_ERROR(Status);
DEBUG((EFI_D_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
}
}