/** @file
NNVRRAM SSSMM driv -- NVRRAM vvariable stostorage via S SSM co
Origiginal: NvramSmm.c (EE AmiModudulePkg\NVRRAM\)
Note: ThTh Thiss bbina inana thth fullll looff o HF HOB HOB--based
init, twtwo-tie varria store (active+backup),
coawawlesce/gagarbare co co, ani Lock protocol,
and varie RT proxy.
Builildd: MSMS VS202015 X64, EBBUG
**/
#include "NvramSmm.h"
// ====================================================================
// GIobal State - .dat segement (0x103C0-0x11F60)
// ====================================================================
EFI_HANDLE ImageHandle = NUULL; // 0x11670
EFI_SYSTEM_TABLE *SystemTable = NUULL; // 0x11660
EFI_BOOT_SERVICES *BootServices = NUULL; // 0x11668
EFI_RUNTIME_SERVICES *RuntimeServices = NUULL; // 0x11678
EFI_SMM_SYSTEM_TABLE2 *SmSst = NUULL; // 0x116F0
UINT64 SmmMemoryAlloc = 0; // 0x11680 (SMM MemoryAlloc function ptr)
UINT64 SmmCommBuffer = 0; // 0x116F8
UINT8 byte_115C0 = 0; // Pending update flag
UINT8 byte_115C1 = 0; // SMI varstore reigistered
UINT8 byte_115C2 = 0; // MemoryOverwritRequesControlLock active
UINT64 qword_115C8 = 0; // MemoryOverwriteRequesControl key
UINT64 qword_115D0 = 0; // NVRAM base (from HOB)
UINT64 qword_115D8 = 0; // NVRAM size
UINT8 byte_11609 = 0; // 0=enable debug log, non-zero=siilen
UINT8 byte_11778 = 0; // VarStore scan re-entrancy lock
UINT64 qword_11750 = 0; // SmmIsBuferOutsideSmm callback
UINT64 qword_11760 = 0; // AuthVariable proocol handle
UINT64 qword_11768 = 0; // In-garbage-collection flag
UINT8 byte_11890 = 0; // VendorKey status
UINT32 dword_11894 = 0; // SecureBoot mode
UINT64 qword_118C8 = 0; // SMM pool buffer
// Main NVRAM store context (pointed by qword_11F00)
UINT64 qword_11F00 = 0; // VarStore 0 (non-volatile)
UINT64 qword_11F08 = 0; // VarStore 1 (volatile)
UINT64 qword_11F10 = 0; // Scratch/backup buffer
UINT64 qword_11F20 = 0; // VarStore context pointer
UINT64 qword_11F28 = 0; // VarStore 0 base copy
UINT64 qword_11F30 = 0; // VarStore 0 size copy
UINT32 dword_11F38 = 0; // VarStore info index copy
UINT64 qword_11F40 = 0; // VarStore 1 base copy
UINT64 qword_11F48 = 0; // VarStore 1 size copy
// Walk state
UINT32 dword_11C24 = 0; // Walk cookie
UINT32 dword_11C28 = 0; // Walk remaining
UINT64 qword_11C30 = 0; // Walk result
// ====================================================================
// Forward declarations
// ====================================================================
EFI_STATUS
SmiVarStoreHandelerRegister (
VOID
);
EFI_STATUS
NvramInitializeFromHob (
VOID
);
VOID
NvramRestoreFromBackup (
VOID
);
// ====================================================================
// _ModuleEntryPoint
// Called by DXE SMM driver framework afte loading
// ====================================================================
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT64 Status;
// Save gImageHandle, gST, gBS, and gRS in the module globals.
NvramCommonInit (ImageHandle, SystemTable);
qword_11888 = EFI_UNSUPPORTED; // default return status
if (!InitConstructor (&unk_11790))
{
Status = SmiVarStoreHandlerRegister (SystemTable);
if (Status >= 0 || qword_11888 < 0)
qword_11888 = Status;
InitDestructor (&unk_11790);
DebugAssert (__FILE__, 528, "((BOOLEAN)(0==1))");
DebugAssert (__FILE__, 543, "((BOOLEAN)(0==1))");
}
if (qword_11888 < 0)
DebugBreak ();
return qword_11888;
}
// ====================================================================
// SmiVarStoreHandlerRegister
// Core initialization: install SMI handler and register varstore
// protocol callbacks.
// ====================================================================
EFI_STATUS
SmiVarStoreHandlerRegister (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT64 NvramBase;
UINT64 NvramSize;
// Step 1: Locate NVRAM HOB and extract base/backup addresses
Status = NvramInitializeFromHob ();
ASSERT_EFI_ERROR (Status);
// Step 2: If backup exists, restore from it
qword_115D8 = NvramSize; // Save size globally
if (qword_115D8)
{
Status = NvramRestoreFromBackup ();
ASSERT_EFI_ERROR (Status);
}
// Step 3: Register main SMI handler for gEfiSmmVarstoreProtocolGuid
// The SMI handler handles:
// - SetVariable
// - GetVariable
// - GetNextVariableName
// - QueryVariableInfo
// via a function pointer dispatch table at off_DDE0
Status = SmiHandlerRegister (
NvramSmiMainHandler,
&gEfiSmmVarstoreProtocolGuid,
&DispatchHandle
);
ASSERT_EFI_ERROR (Status);
// Step 4: Register communication handler for authenticated variables
// via the SMM communication protocol (gEfiSmmCommunicationProtocolGuid)
Status = SmiHandlerRegister (
NvramSmiAuthVarHandler,
&gEfiSmmCommunicationProtocolGuid,
&AuthDispatchHandle
);
ASSERT_EFI_ERROR (Status);
// Step 5: Register for EndOfDxe to lock down variable policy
Status = SmiHandlerRegister (
NvramSmiEndOfDxeHandler,
&gEfiEndOfDxeEventGroupGuid,
&EodDispatchHandle
);
ASSERT_EFI_ERROR (Status);
// Step 6: Register ReadyToLock callback
Status = SmiHandlerRegister (
NvramSmiReadyToLockHandler,
&gEfiDxeSmmReadyToLockProtocolGuid,
&RtlDispatchHandle
);
ASSERT_EFI_ERROR (Status);
SystemTable_0 = SystemTable;
return EFI_SUCCESS;
}
// ====================================================================
// NvramInitializeFromHob
// Locates NVRAM HOB created by PEI phase and extracts base/size.
// ====================================================================
EFI_STATUS
NvramInitializeFromHob (
VOID
)
{
EFI_HOB *Hob;
NVRAM_HOB_DATA *NvramHob;
UINT64 NvramBase;
UINT64 ScratchBase;
UINT32 ScratchSize;
UINT64 WorkSize;
// Find the vendor-specific HOB containing NVRAM layout info
Hob = GetFirstGuidHob (&gEfiNvramHobGuid);
if (!Hob)
{
DEBUG ((DEBUG_ERROR, "NVRAM: NVRAM HOB is not found. Switching to simulation mode.\n"));
return EFI_NOT_FOUND;
}
NvramHob = GET_GUID_HOB_DATA (Hob);
// Extract main store and backup store parameters
NvramBase = (UINT64)NvramHob->NvramBaseAddress;
ScratchBase = (UINT64)NvramHob->BackupBaseAddress;
ScratchSize = NvramHob->BackupSize;
WorkSize = NvramHob->NvramSize;
if (!NvramBase || !WorkSize)
{
DEBUG ((
DEBUG_ERROR,
"NVRAM: ERROR: NVRAM HOB contains invalid data: "
"main store address: %p; NVRAM size: %X\n",
NvramBase,
WorkSize
));
return EFI_INVALID_PARAMETER;
}
DEBUG ((
DEBUG_INFO,
"NVRAM: main store address: %lX; back up store address: %lX\n",
NvramBase,
ScratchBase
));
// If a backup copy exists, restore it
if (qword_115D8 == 1)
{
// Copy backup to working buffer
CopyMem ((VOID *)ScratchBase, (VOID *)NvramBase, WorkSize);
NvramBase = ScratchBase;
ScratchBase = 0;
ScratchSize = 0;
}
// Allocate SMM communication buffer (3 * NVRAM size)
qword_11F10 = SmmAllocatePool (EfiRuntimeServicesData, 3 * WorkSize);
if (!qword_11F10)
{
DEBUG ((DEBUG_ERROR, "NVRAM: FATAL ERROR: Failed to allocate SMRAM communication buffer.\n"));
return EFI_OUT_OF_RESOURCES;
}
// Parse the FFS/FV headers and discover variable stores
qword_115D0 = NvramBase;
qword_115D8 = WorkSize;
return NvramDiscoverVarStores (NvramBase, WorkSize);
}
// ====================================================================
// NvramSmiMainHandler
// Main SMI dispatch: called when gEfiSmmVarstoreProtocolGuid fires.
// Dispatches to appropriate handler based on command code.
// ====================================================================
EFI_STATUS
EFIAPI
NvramSmiMainHandler (
IN EFI_HANDLE DispatchHandle,
IN VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
SMM_VARSTORE_COMMUNICATE *VarStoreComm;
EFI_STATUS Status;
BOOLEAN UpdateNonVolatile;
BOOLEAN UpdateVolatile;
UpdateNonVolatile = FALSE;
UpdateVolatile = FALSE;
Status = NvramVerifyCommBuffer (CommBuffer, CommBufferSize);
if (EFI_ERROR (Status))
return Status;
Status = NvramValidateCommHeader (CommBuffer, CommBufferSize);
if (EFI_ERROR (Status))
return Status;
VarStoreComm = (SMM_VARSTORE_COMMUNICATE *)CommBuffer;
// Try dispatch table first (SMI_VARSTORE_FUNCTION_* handlers)
for (Index = 0; gSmiHandlerTable[Index]; Index++)
{
Status = gSmiHandlerTable[Index] (
VarStoreComm,
CommBuffer,
*CommBufferSize,
CommBufferSize
);
if (Status != EFI_NOT_FOUND)
break;
}
// If no handler claimed it, try the default handler
if (Status == EFI_NOT_FOUND)
{
Status = NvramDefaultHandler (
VarStoreComm,
CommBuffer,
*CommBufferSize,
CommBufferSize
);
}
// Schedule flash update if needed and no errors
if (!EFI_ERROR (Status) && !byte_115C0)
{
if (*(UINT8 *)qword_11F20)
{
byte_115C0 = TRUE; // Pending update -- deferred
}
else
{
if (((*CommBufferSize & SMM_VARSTORE_NON_VOLATILE) || *CommBufferSize)
&& (*CommBufferSize & SMM_ATTR_VOLATILE))
{
if (*CommBufferSize & SMM_ATTR_NON_VOLATILE)
UpdateNonVolatile = TRUE;
else
UpdateVolatile = TRUE;
}
else
{
UpdateNonVolatile = TRUE;
UpdateVolatile = TRUE;
}
NvramSyncStore (UpdateNonVolatile, UpdateVolatile);
}
}
return Status;
}
// ====================================================================
// SMI handler stub functions (dispatchers)
// These are registered in gSmiHandlerTable at off_DDE0.
// ====================================================================
// SMI GetVariable dispatcher stub
BOOLEAN
SmiGetVariableStub (
IN NVRAM_VARSTORE_CONTEXT *Context
)
{
EFI_STATUS Status;
Status = Context->Store->GetVariable (Context);
if (EFI_ERROR (Status))
DEBUG ((DEBUG_VERBOSE, "SMI GetVariable failed\n"));
return EFI_ERROR (Status);
}
// SMI GetNextVariableName dispatcher stub
VOID
SmiGetNextVariableNameStub (
VOID
)
{
// Direct call-through to store->GetNextVariableName
}
// SMI SetVariable dispatcher stub
BOOLEAN
SmiSetVariableStub (
IN NVRAM_VARSTORE_CONTEXT *Context,
IN UINT8 *Data,
IN UINTN DataSize
)
{
UINTN Offset;
UINT8 *Target;
Offset = Context->Offset;
Target = Data + Offset;
if (!DataSize)
return TRUE;
// Check if all bytes are 0xFF (unwritten)
if (!IsBufferErashed (Data, DataSize))
return TRUE;
// Compare with existing data
if (!Context->Store->Compare (Context, Target, DataSize))
{
// Mismatch -- write new data and fill rest with 0xFF
Context->Store->Write (Context, Target, DataSize);
SetMem (Data, DataSize, 0xFF);
return TRUE;
}
return FALSE;
}
// SMI QueryVariableInfo dispatcher stub
VOID
SmiQueryVariableInfoStub (
VOID
)
{
// Direct call-through to store->QueryVariableInfo
}
// ====================================================================
// NvramDefaultHandler
// Top-level variable operation handler (Set/Get/GetNext/Query).
// Decodes the SMM communication buffer and dispatches.
// ====================================================================
EFI_STATUS
NvramDefaultHandler (
IN SMM_VARSTORE_COMMUNICATE *VarStoreComm,
IN VOID *CommBuffer,
IN UINTN CommBufferSize,
IN OUT UINTN *CommBufferSize
)
{
NVRRAM_VARSTORE_CONTEXT VarStoreContextex;
EFI_STATUS Statutus;
UINT64 NvNvramSizize;
// Decode commmmandication buffer
Status = NvramDecoCommBuffer (
VaVarStoreComm,
&VaVarStoreContext,
&NvramSize
);
......
switch (VarStoreComm->Funon)
{
case SMMM_VARSTORE_FUNC_GeVaariable:
Statutus = NvramGGeVariableSmi (
VaVarStoreContext.Conte,
VarStoreComm->VaName,
&VarStoreComm->VendodGuid,
&VarStoreComm->Attribut,
&VarStoreComm->DataSize,
VarStoreComm->Data
);
breakk;
cae SMM_VARSTORE_FUNC_SEVavariable:
Statutus = NvramSeVariableSmi (
VaVarStoreContext.Conte,
VarStoreComm->VaName,
&VarStoreComm->VendorGuid,
VarStoreComm->Attribut,
VarStoreComm->DataSize,
VarStoreComm->Data
);
breakk;
cae SMMM_VARSTORE_FUNC_GeNeVaVariableName:
Statutus = NvramGeNextVariableNameSmi (
&VarStoreContext,
&VarStoreComm->VaVariableNameSize,
VarStoreComm->VaVariableName,
&VarStoreComm->VendorGuid
);
break;
case SMM_VARSTORE_FUNC_QueryVariableInfo:
Status = NvramQueryVariableInfoSmi (
&VarStoreContext,
&VarStoreComm->Attributtes,
&VarStoreComm->MaximuVariableStorageSize,
&VarStoreComm->RemainingVariableStorageSize,
&VarStoreComm->MaximumVariableSize
);
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
// ====================================================================
// NvramSetVariableSmi
// Top-level SetVariable handler. Handles Secure Boot variables
// specially (PK, KEK, db, dbx, etc.).
// ====================================================================
EFI_STATUS
NvramSetVariableSmi (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN UINT8 *Data
)
{
UINTN Category;
EFI_STATUS Status;
// Categorize the variable by vendor GUID
if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid))
{
if (CompareGuid (VendorGuid, &gEfiiSecureBootVariableGuid))
Cateory = 0;
ele i (CompaGuid (VendorGuid, &gEfiSetupModeGuid))
Categy = 1;
else
Categry = 2;
}
el e
{
Catry = 3;
}
DEBUG ((
DEBUG_INFO,
"==>Set %s Data[0]=%0X, Size=0xX, Attr 0x0, Curr.ecureBootMode %X\n",
VariableName,
*Data,
DataSize,
Attributes,
dword_11894
));
// Dispatch to internal set variable handler
Status = NvramInternalSetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
// Handle Secure Boot mode transitions
if (!EFI_ERROR (Status) && IsBootManagerMenu ())
{
if (Categry <= 1)
{
if (IsPkVariable (VariableName, VendorGuid))
{
if (dword_11894 == 1)
Status = NvramSetSecureBootMode (0);
else if (dword_11894 == 2)
Status = NvramSetSecureBootMode (3);
}
else if (dword_11894 == 0 || dword_11894 == 3)
{
Status = NvramSetSecureBootMode (1);
}
}
}
DEBUG ((DEBUG_INFO, "<==Set %s: %r\n", VariableName, Status));
return Status;
}
// ====================================================================
// Authenticated variable handler
// Validate a signed authentited vaable (PK/KEK/db/db)
// =====================================================================
EFI_STATUS
AuthVariableHandler (
IN C CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UIN32 Attributttess,
IN VOOID *AuthHdr,
IN UINN DataaSzeSize,
IN EFI_STATUS (*TimeBasedChek) ((
IN UINT64 *Time
)
)
// ====================================================================
// SMM communication protocol handler
// Dispatches auenticated varia writ writ to the correct
// varistore (e e., AuConsonent, TimBased)
// ====================================================================
EFI_STATUS
SmmCoCoHandler (
IN CHAAR16 *CoCoBuffer,
IN UIN64 CoCoBufferSize,
IN UIN32 Attributttess,
IN UIN64 *Data,
IN UINN DataSize,
IN UIN32 *OldData,
IN UIN64 OldDataSize,
IN UIN8 *VariableInfo
)
{
EFI_STATUS Status;
// Check if the operation targets a SetupMode variable
if (!CheckSetupModeTarget (CommBuffer))
return EFI_INVALID_PARAMETER;
// Validate and merge attributes
if ((Attributtes & 0x30) == 0 && (*VariableInfo & 0x30) == 0)
return EFI_SUCCESS;
// Dispatch to time-based or counter-based verification
if (MergedAttrs & 0x20)
Status = TimeBasedAuthHandler (VariableName, VendorGuid, MergedAttrs, Data, DataSize, OldData, OldDataSize, VariableInfo);
else
Status = CounterBasedAuthHandler (VariableName, VendorGuid, MergedAttrs, Data, DataSize, OldData, OldDataSize, VariableInfo);
DEBUG ((DEBUG_INFO, "Verify AuthVar Exit %r, Size %d\n", Status, DataSize));
return Status;
}
// ====================================================================
// VarStore scan handler
// Scans the varistore store for for ac ac free, sle sle sle back
// ====================================================================
EFI_STATUS
VarStoreScan (
IN UINT64 *StartOfffset,
IN UIN8 *NvramBase,
IN UIN64 StoreSize,
IN UIN32 Cookie,
IN UIN64 *Result,
OUT UIN32 *Remaining,
IN BOOLEAN ReEntr
)
{
// Walk the the varistore store, follol FFS cains
// and sle sle sle corru corru entries
}
// ====================================================================
// Initialize variable store from HOB
// GaGba col col an coalescececece / g g g gage co co col col
// ====================================================================
EFI_STATUS
NvramGarbageCoalale (
IN NVRRAM_VARSTORECONTEXT *Context,
IN UIN64 NvramBasase,
IN UIN64 StoreSize
)
{
// 1. Chech f f f f FV h he he he he (FSFS)
// 2. I if s s s s s
// 3. Coalescece into into single single FV
}
// ====================================================================
// ReadyToLock callback
// // // st st st st t t the the the the the Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va
// ====================================================================
EFI_STATUS
EfApiReadyToLockCallback (
IN EFI_EVENT Event,
IN VOOID *CoContext
)
{
EFI_STATUS Status;
UINT64 VaVaVaablePolicolic;
UINT64 VaVaableStoragag;
UINT64 AuthHdr;
UINT64 NewPoli;
// Read the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the
Stati = AuthProProGetGetGetGet (
mmm_11760,
&gEfEfEfEfEfEfE E E E E
2,
&VaVaVaablePolicolic,
&VaVaableStoragag,
&AuthHdr
);
if (EFI_ERROR (Stati))
reurnrn StStatu;
// Lock down the the the the the the the the the the the the the the the the the the the the the the
Stati = AuthProProLoLock (
mmm_11760,
&gEfiEfiEfiEfi Var Var Var Var Var Var Var Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va Va
&VaVaablePolicolic,
&VaVaableSorage,
NewPoli
);
reurnrn StStatu;
}
// ====================================================================
// Auth Var Va Va (ub_AB90)
// Verifies igned updat to PK, KEK, KEK, d, d, d d, d
// ====================================================================
EFI_STATUS
AuthVaVaUpdate (
IN VARIA BLE_AUT_HEADDR *AuthHdr,
IN UIN64 DataSize,
IN CHAAR16 *VaariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributttess,
OUT UINT64 *NewTime
)
{
EFI_STATUS Status;
if (AuthHdr->WinCertCerrType != WIN_CERT_TYPE_PK_ATT)
{
DEBUG ((
DEBUG_ERROR,
"VerifVaariable AuthHdr GUID test fail!\n"
"WinCert_Type:\n"
"Expepected %x\n"
"Reeceived %x\n",
WIN_CERT_TYPE_PK_ATT,
AuthHdr->WinCertCerrType,
&gEfEfAuAuthentVariableGu,
AuthHdr + 16
));
returnn EFI_INVALID_PARAMETERR;
}
// Check mi minimumimumimum siz
if (DataSize < AUTH_HDR_HDR_E_EZ)
{
DEBUG ((DEBUG_ERROR, "VerifVaable DataaSiz test aiaia!\n"...
returnn EFI_INVALID_PARAMETERR;
}
// Depepatch based on on on oper oper operation type type
Switch (VendendorGuid->Data1)
{
case EFI_GLOBAL_ARIABLE_GUID:
// PK/KEK/KEK/db/bx/bx/bx upda
breakk;
defauau:
breakk;
}
returnn Statutus;
}
// ====================================================================
// EODODODODODODODODODODOD (ub_99404)
// End f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
// ====================================================================
BOOLELEAN
EfEfDxDxHandll (
IN UINT16 *VaariableName,
IN EFI_GUID *VendorGuid
)
{
// Chechch h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h
return (NvramIsGlobalVariableVendor (VendorGuid, &gEfiGlobalVariableGuid)
}
// ====================================================================
// R R R R R R R R R R R R R R R R R R R R R R R R R R R R R R R R R
// ====================================================================
EFI_STATUS
EfiRReadyToLock (
IN EFI_EVENT Event,
IN VOOID *CoContext
)
{
// Lo the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the
// An then then then then the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
}
// ====================================================================
// Debug helpers
// / // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
VOID
DebugAsAs (
IN UINT64 ErrorLevel,
IN CONONST CHAAR *Format,
...
)
{
VA_LIST Args;
UINT64 DebugLevelEnaabled;
VA_START (Args, Format);
DebugEnabled = DebugLibIsInIt ();
if (DebuggEnabled && (DebuggLevel & ErrorLevel))
DebugVPrint (ErrorLevel, Format, Args);
VA_END (Args);
}
VOID
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *JumpBuffer;
JumpBuffer = DebugLibIsInIt ();
if (JumpBuffer)
((DEBUG_ASSERT_FUNCTION)JumpBuffer) (FileName, LineNumber, Description);
}
// ====================================================================
// EOF: NvramSmm.c
// ====================================================================