// NvramSmm.c - NVRAM SMM Driver
// Source: AmiModulePkg/NVRAM/NvramSmm/NvramSmm.c
// Related sources: AmiModulePkg/NVRAM/NvramSmm/NvramDxeCommon.c, AmiModulePkg/NVRAM/NvramSmm/NvramSmi.c, AmiModulePkg/NVRAM/NvramSmm/AuthService.c
#include "NvramSmm.h"
// ========================================================================
// Global State (from .data section)
// ========================================================================
EFI_HANDLE gImageHandle = NULL; // 0x11670
EFI_SYSTEM_TABLE *gST = NULL; // 0x11660
EFI_BOOT_SERVICES *gBS = NULL; // 0x11668
EFI_RUNTIME_SERVICES *gRT = NULL; // 0x11678
EFI_SMM_SYSTEM_TABLE2 *gSmst = NULL; // 0x11680
VOID *gDS = NULL; // 0x11758
EFI_SMM_BASE2_PROTOCOL *gSmmBase2; // 0x116F8
VOID *gMmst; // 0x116F0
VOID *gSmmCpuIo = NULL; // 0x11690
VOID *gSmmBufferValidation = NULL; // 0x11750
UINT64 gNvramStoreBase = 0; // 0x115D0
UINT64 gNvramStoreSize = 0; // 0x115D8
UINT32 gVarStoreCount = 0; // 0x11C24
UINT8 gVarStoreInitFlags = 0; // 0x11C20
UINT32 gNvramUpdateDisabled = 0; // 0x11C28
EFI_RUNTIME_SERVICES *gRuntimeServicesOverride = NULL; // 0x116E8
VOID *gDriverNvramBuffer = NULL; // 0x11F10
UINTN gDriverNvramBufferSize = 0; // 0x11F18
VOID *gNvramDmaBuffer = NULL; // 0x11648
UINT64 gMailboxNvramBase = 0; // 0x11F28
UINT64 gMailboxNvramSize = 0; // 0x11F30
UINT32 gMailboxNvramFlags = 0; // 0x11F38
UINT64 gMailboxVarStoreBase = 0; // 0x11F40
UINT64 gMailboxVarStoreSize = 0; // 0x11F48
BOOLEAN gMigrationDone = FALSE; // 0x11609
BOOLEAN gSmiProcessing = FALSE; // 0x11768
UINT8 gSecureBootMode = 0; // 0x11894
VAR_STORE_INFO gVarStoreArray[?]; // 0x11C38
// ========================================================================
// Module Entry Point
// ========================================================================
EFI_STATUS
EFIAPI
ModuleEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
// Initialize all UEFI/SMM plumbing
Status = NvramSmmInit(ImageHandle);
if (EFI_ERROR(Status)) {
return Status;
}
// Global status variable
gBS = gST->BootServices;
gRT = gST->RuntimeServices;
gImageHandle = ImageHandle;
// Locate SmmBase2 protocol
Status = gBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &gSmmBase2);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT: !EFI_ERROR(Status) - SmmServicesTableLib\n"));
return Status;
}
// Get SMM System Table
Status = gSmmBase2->GetSmstLocation(gSmmBase2, &gSmst);
if (EFI_ERROR(Status) || gSmst == NULL) {
DEBUG((EFI_D_ERROR, "ASSERT: gSmst != NULL\n"));
return Status;
}
// Locate SMM memory allocation protocol
Status = gBS->LocateProtocol(&gEfiSmmAccess2ProtocolGuid, NULL, &gSmmMemoryProtocol);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT: !EFI_ERROR(Status) - MemoryAllocationLib\n"));
}
// Get SMRAM ranges
gSmramRanges = AllocateSmramRanges(&gSmramRangeCount);
// Initialize PCIE segment bus table
PcieSegBusTableInit();
// Initialize AmiCryptoLib
AmiCryptoLibConstructor();
// Initialize heap memory manager
SmmHeapInit();
// Locate SMM buffer validation protocol
Status = gMmst->SmmLocateProtocol(&gSmmBufferValidationProtocolGuid, NULL, &gSmmBufferValidation);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT: !EFI_ERROR(Status) - SmmAmiBufferValidationLib\n"));
gSmmBufferValidation = NULL;
}
// Locate DxeServicesTable
Status = gBS->LocateProtocol(&gEfiDxeServicesTableProtocolGuid, NULL, &gDS);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT: !EFI_ERROR(Status) - DxeServicesTableLib\n"));
return Status;
}
// Fall through to SMM protocol install / notification init (returned from Init)
return EFI_SUCCESS;
}
// ========================================================================
// NVRAM Initialization (sub_10F8)
// ========================================================================
EFI_STATUS
NvramCoreInit(
VOID
)
{
EFI_STATUS Status;
UINTN NvramMailBoxSize = 24;
UINT8 MailboxBuffer[24];
EFI_HOB_GUID_TYPE *GuidHob;
VAR_STORE_PTR *VarStoreInfo;
UINT64 StoreBase, StoreSize;
VOID *DmaBuffer;
// Signal that NVRAM store size at least matches HOB pattern
gNvramStoreSize = 1;
// Get NVRAM HOB from HOB list
Status = NvramHobRetrieve();
if (EFI_ERROR(Status)) {
return Status;
}
// Read NvramMailBox variable to get mailbox memory region info
Status = gRT->GetVariable(
L"NvramMailBox",
&gNvramMailboxVariableGuid,
NULL,
&NvramMailBoxSize,
MailboxBuffer
);
if (EFI_ERROR(Status)) {
return Status;
}
// Extract mailbox NVRAM base/size details from the variable
gMailboxNvramBase = *(UINT64 *)(MailboxBuffer + 0); // offset 0
gMailboxNvramSize = *(UINT64 *)(MailboxBuffer + 8); // offset 8
gMailboxNvramFlags = *(UINT32 *)(MailboxBuffer + 60); // offset 60
gMailboxVarStoreBase = *(UINT64 *)(MailboxBuffer + 736); // offset 736
gMailboxVarStoreSize = *(UINT64 *)(MailboxBuffer + 744); // offset 744
// Close the variable
gRT->SetVariable(L"NvramMailBox", &gNvramMailboxVariableGuid, 0, 0, NULL);
// Validate that VarStoreInfo NVRAM sizes match mailbox
if (VarStoreInfo->MemInfo->NvramSize != gMailboxVarStoreSize) {
return EFI_INVALID_PARAMETER;
}
// Copy VarStoreInfo NVRAM data from mailbox into working buffer
CopyMem(VarStoreInfo->MemInfo->Buffer, gMailboxVarStoreBase, gMailboxVarStoreSize);
VarStoreInfo->MemInfo->FlagResets++;
VarStoreInfo->MemInfo->CrcRecalc();
// If simulation mode, also copy NvInfo data from mailbox
if (gVarStoreInitFlags & 8) {
if (VarStoreInfo->NvInfo->NvramSize != gMailboxVarStoreSize) {
return EFI_INVALID_PARAMETER;
}
CopyMem(VarStoreInfo->NvInfo, gMailboxVarStoreBase, gMailboxVarStoreSize);
VarStoreInfo->NvInfo->FlagResets++;
VarStoreInfo->NvInfo->CrcRecalc();
NotifyFlashUpdate();
}
NotifyVarStoreInfoChange();
// Allocate DMA buffer for SMI communication (0x40000 bytes)
Status = gMmst->SmmAllocatePool(EfiRuntimeServicesData, 0x40000, &DmaBuffer);
if (EFI_ERROR(Status)) {
return Status;
}
gNvramDmaBuffer = DmaBuffer;
// Initialize buffer header
*(UINT64 *)DmaBuffer = (UINT64)DmaBuffer + 24; // data starts at +24
*(UINT64 *)((UINT8 *)DmaBuffer + 8) = 0x40000 - 24; // usable size
*(UINT64 *)((UINT8 *)DmaBuffer + 16) = 0;
// Register SMI handler for NVRAM variable access
Status = gMmst->SmiHandlerRegister(
SmiNvramCommHandler,
&gNvramMailboxVariableGuid,
&gSmiNvramCommHandle
);
if (EFI_ERROR(Status)) {
return Status;
}
// Register notification callback on SMM ReadyToLock
Status = gMmst->SmmRegisterProtocolNotify(
&gEfiSmmReadyToLockProtocolGuid,
SmmReadyToLockNotification,
&gSmmReadyToLockNotifyHandle
);
if (EFI_ERROR(Status)) {
return Status;
}
// Override runtime variable services
gRuntimeServicesOverride = gSmmBase2->SmmGetRuntimeServices();
gRuntimeServicesOverride->GetVariable = RuntimeGetVariable;
gRuntimeServicesOverride->SetVariable = RuntimeSetVariable;
gRuntimeServicesOverride->GetNextVariableName = RuntimeGetNextVariableName;
gRuntimeServicesOverride->QueryVariableInfo = RuntimeQueryVariableInfo;
// Register variable change callbacks for variable sync
Status = gMmst->SmmRegisterProtocolNotify(
&gVariableChangeProtocolGuid,
VariableChangeCallback,
&gVariableChangeNotifyHandle
);
// Register additional callbacks for DmiArray variable change
Status = gMmst->SmmRegisterProtocolNotify(
&gNvramMailboxVariableGuid,
NvramMailboxNotify,
&gNvramMailboxNotifyHandle
);
// Register SMM communication protocol for variable sync
Status = gMmst->SmmRegisterProtocolNotify(
&gSmmVariableSyncProtocolGuid,
SmmVariableSyncNotify,
&gSmmVariableSyncNotifyHandle
);
return Status;
}
// ========================================================================
// SMI NVRAM Communication Handler (sub_6AE4)
// ========================================================================
EFI_STATUS
EFIAPI
SmiNvramCommHandler(
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *RegisterContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
UINT64 CommandCode;
UINTN BufferSize;
UINT8 *AlignedBuffer;
UINTN AlignedSize;
EFI_STATUS Status;
BufferSize = *CommBufferSize;
// Validate buffer address with SMM buffer validation protocol
if (gSmmBufferValidation != NULL) {
if (gSmmBufferValidation->ValidateBuffer(CommBuffer, BufferSize) != EFI_SUCCESS) {
DEBUG((EFI_D_ERROR, "[%a]: SMM buffer security violation.\n", __FUNCTION__));
return EFI_ACCESS_DENIED;
}
}
// Align the buffer pointer to 8-byte boundary
AlignedBuffer = (UINT8 *)((UINTN)CommBuffer & ~7);
AlignedSize = BufferSize - ((UINTN)CommBuffer - (UINTN)AlignedBuffer);
if (AlignedSize < 8) {
return EFI_INVALID_PARAMETER;
}
// Set SMI processing flag
gSmiProcessing = TRUE;
// Read command code at offset 0
CommandCode = *(UINT64 *)AlignedBuffer;
switch (CommandCode) {
case SMI_NVRAM_CMD_GET_VARIABLE:
// Type 0: GetVariable operation
// Buffer layout: +0x00: cmd, +0x08: NameSize, +0x10: DataSize
// +0x18: Attributes, +0x20: Name[], +0x30: GUID + Data
if (AlignedSize < 0x30 + 16) goto invalid;
// Nested variable read with sub_5580
Status = RuntimeGetVariable(
(CHAR16 *)(AlignedBuffer + 0x08),
(EFI_GUID *)(AlignedBuffer + 0x18),
(UINT32 *)(AlignedBuffer + 0x10),
(UINTN *)(AlignedBuffer + 0x28),
AlignedBuffer + 0x30
);
break;
case SMI_NVRAM_CMD_SET_VARIABLE:
// Type 1: SetVariable operation
// Buffer layout: +0x00: cmd, +0x08: NameLength, +0x10: DataSize
// +0x18: Attributes, +0x20: Name[], +0x20+NameSize: GUID
// +0x30+NameSize: Data[]
if (AlignedSize < 0x20 + 2) goto invalid;
// sub_5654 handles the actual set
Status = RuntimeSetVariable(
(CHAR16 *)(AlignedBuffer + 0x08),
(EFI_GUID *)(AlignedBuffer + 0x20 + *(UINT16 *)AlignedBuffer & ~1),
*(UINT32 *)(AlignedBuffer + 0x18),
*(UINTN *)(AlignedBuffer + 0x10),
AlignedBuffer + 0x30 + (*(UINT16 *)AlignedBuffer & ~1)
);
break;
case SMI_NVRAM_CMD_GET_NEXT_VARIABLE:
// Type 2: GetNextVariableName
if (AlignedSize < 0x30) goto invalid;
Status = RuntimeGetNextVariableName(
(UINTN *)(AlignedBuffer + 0x28),
(CHAR16 *)(AlignedBuffer + 0x08),
(EFI_GUID *)(AlignedBuffer + 0x18)
);
break;
case SMI_NVRAM_CMD_QUERY_VARIABLE_INFO:
// Type 3: QueryVariableInfo
if (AlignedSize != 40) goto invalid;
Status = RuntimeQueryVariableInfo(
(UINTN *)(AlignedBuffer + 0x10),
(UINTN *)(AlignedBuffer + 0x18),
(UINTN *)(AlignedBuffer + 0x20)
);
break;
case SMI_NVRAM_CMD_TYPE_4:
// Type 4: Variable write with auth
if (AlignedSize < 0x20 + 2) goto invalid;
Status = sub_575C(*(UINT16 *)AlignedBuffer >> 1,
AlignedBuffer + 0x20,
AlignedBuffer + 0x10);
break;
case SMI_NVRAM_CMD_MIGRATION_DONE:
// Migration complete notification
if (AlignedSize == 8) {
gMigrationDone = TRUE;
qword_11618 = 0;
Status = EFI_SUCCESS;
} else {
goto invalid;
}
break;
default:
goto invalid;
}
gSmiProcessing = FALSE;
// Write status back to command code location
if (Status < 0) {
Status |= 0x8000000000000000ULL;
}
*(UINT64 *)AlignedBuffer = Status;
return EFI_SUCCESS;
invalid:
gSmiProcessing = FALSE;
*(UINT64 *)AlignedBuffer = EFI_INVALID_PARAMETER;
return EFI_SUCCESS;
}
// ========================================================================
// SMI NVRAM Update Handler (sub_5FAC and sub_5E44)
// ========================================================================
EFI_STATUS
EFIAPI
SmiNvramUpdateHandler(
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *RegisterContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
VAR_STORE_PTR *StorePtr;
UINTN NvramSize;
UINTN ReadSize;
UINT8 *TempBuffer;
UINTN TempBufferSize;
UINT8 *Source;
UINT8 *Dest;
EFI_STATUS Status;
StorePtr = (VAR_STORE_PTR *)gVarStoreArray[0]; // qword_11F00
// Validate comm buffer
if (CommBuffer == NULL || CommBufferSize == NULL) {
return EFI_INVALID_PARAMETER;
}
// Check size match
NvramSize = StorePtr->NvramSize;
if (*CommBufferSize != NvramSize) {
return EFI_INVALID_PARAMETER;
}
// Check that source buffer has a valid FV header
ReadSize = GetFvHeaderSize(CommBuffer);
if (ReadSize == 0) {
DEBUG((EFI_D_ERROR, "NVRAM: ERROR: AmiNvramUpdate->UpdateNvram failed, invalid FV header.\n"));
return EFI_VOLUME_CORRUPTED;
}
// Check if FV header size is consistent
if (ReadSize && *(UINT64 *)((UINT8 *)CommBuffer + 32) == StorePtr &&
(GetFvHeaderSize(CommBuffer))) {
// Validate the data aligns with store parameters
TempBuffer = NULL;
TempBufferSize = NvramSize;
if (TempBufferSize > StorePtr->StoreSize) {
// Need to allocate bigger temp buffer (3x)
TempBuffer = HeapAlloc(TempBufferSize);
if (TempBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (3 * NvramSize > TempBufferSize) {
HeapFree(gDriverNvramBuffer, gDriverNvramBufferSize);
gDriverNvramBuffer = HeapAlloc(3 * NvramSize);
if (gDriverNvramBuffer == NULL) {
HeapFree(TempBuffer, TempBufferSize);
return EFI_OUT_OF_RESOURCES;
}
TempBufferSize = 3 * NvramSize;
}
}
// Copy source NVRAM data
TempBuffer = AllocateCopyPool(NvramSize, CommBuffer);
if (TempBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Check that data is not all 0xFF (empty erased)
if (!IsBufferErased(TempBuffer, NvramSize)) {
// Check for active NVRAM (FV header + GUID match)
if (!CompareGuid(TempBuffer + 18, &gNvramSignatureGuid, 16)) {
goto cleanup;
}
} else {
goto cleanup;
}
// Check size matches the data in the FV
Source = TempBuffer + ReadSize;
if ((*(UINT32 *)(Source + 20) & 0xFFFFFF) != NvramSize - ReadSize) {
goto cleanup;
}
// Copy from temp to working store
FreePool(TempBuffer);
// Set up store pointers for the migration
StorePtr->VolatileInfo = CommBuffer; // source address
StorePtr->NvInfo = (VOID *)Source; // dest address
// Validate store parameters
Status = ValidateStoreParameters(StorePtr);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ASSERT: !EFI_ERROR\n");
return Status;
}
// F Fill header calculation
UINT32 HeaderSize = GetStoreHeaderSize(StorePtrp->Info);
if (HeaderSize == 0) {
return EFI_DEVICE_ERROR;
}
// Set up the variable enumeration
UINTN FullSize = HeaderSize + 24;
if (ReadSize + 24 == 0) {
return EFI_DEVICE_ERROR;
}
if (StorePtr->NvInfo) {
// Try to find space and move
Status = StorePtr->FlashProtocol->Erase(StorePtr->NvInfo, FullSize);
BOOLEAN CanFit = StorePtr->FlashProtocol->CanFit(StorePtr->NvInfo, FullSize, CommBuffer);
StorePtr->FlashProtocol->Unlock();
if (CanFit) {
StorePtr->FlashProtocol->Write(StorePtr->NvInfo, FullSize, CommBuffer);
return EFI_VOLUME_CORRUPTED;
}
}
// Garbage collection / flush path
Status = StorePtr->FlashProtocol->Erase(gNvramStoreBase, FullSize);
BOOLEAN CanFit2 = StorePtr->FlashProtocol->CanFit(gNvramStoreBase, FullSize, CommBuffer);
StorePtr->FlashProtocol->Unlock();
if (CanFit2) {
StorePtr->FlashProtocol->Write(gNvramStoreBase, FullSize, CommBuffer);
// Mark old store entries
UINTN OldSize = GetFvHeaderSize(CommBuffer);
*(UINT8 *)(OldSize + CommBuffer + 23) = 0xFC; // mark deleted
return EFI_VOLUME_CORRUPTED;
}
// Full GC path
Status = StorePtr->FlashProtocol->Erase(gNvramStoreBase, FullSize);
if (EFI_ERROR(Status)) {
return EFI_VOLUME_CORRUPTED;
}
BOOLEAN CanFit3 = StorePtr->FlashProtocol->CanFit(gNvramStoreBase, FullSize, NULL);
StorePtr->FlashProtocol->Unlock();
if (!CanFit3) {
TempBuffer = NULL;
StorePtr->FlashProtocol->SetMemory(gNvramStoreBase, FullSize, 0xFF);
return EFI_SUCCESS;
// At this point the GC reclaimed space
}
// ... continued
}
cleanup:
if (TempBuffer) {
FreePool(TempBuffer);
}
return Status;
}
// ========================================================================
// Runtime Variable Service Overrides
// ========================================================================
EFI_STATUS
EFIAPI
RuntimeGetVariable(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
// Dispatches to SMI via SMI_NVRAM_CMD_GET_VARIABLE command
// For non-SMM context, sends SMI to enter SMM first.
// Forward declaration: actual implementation at sub_5580.
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
RuntimeSetVariable(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
// Dispatches to SMI via SMI_NVRAM_CMD_SET_VARIABLE command
// Forward declaration: actual implementation at sub_5654.
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
RuntimeGetNextVariableName(
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
)
{
// Dispatches via SMI_NVRAM_CMD_GET_NEXT_VARIABLE
// Forward declaration: actual implementation at sub_F54.
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
EFIAPI
RuntimeQueryVariableInfo(
IN OUT UINTN *MaximumVariableStorageSize,
IN OUT UINTN *RemainingVariableStorageSize,
IN OUT UINTN *MaximumVariableSize
)
{
// Dispatches via SMI_NVRAM_CMD_QUERY_VARIABLE_INFO
// Forward declaration: actual implementation at sub_5D34.
return EFI_INVALID_PARAMETER;
}
// ========================================================================
// SecureBoot Aware Variable Services
// ========================================================================
EFI_STATUS
SecureBootSetVariable(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
UINT8 DataFirstByte;
EFI_STATUS Status;
UINT8 CurrentMode;
// Determine variable type from vendor GUID
UINTN VarType = VAR_TYPE_UNKNOWN;
if (!CompareGuid(VendorGuid, &gSecureBootVarGuid1, 16)) {
VarType = VAR_TYPE_SECURE_BOOT_1;
} else if (!CompareGuid(VendorGuid, &gSecureBootVarGuid2, 16)) {
VarType = VAR_TYPE_SECURE_BOOT_2;
} else if (!CompareGuid(VendorGuid, &gSecureBootVarGuid3, 16)) {
VarType = VAR_TYPE_SECURE_BOOT_3;
}
// Log
DEBUG((
EFI_D_INFO,
"==>Set %s Data[0]=%0X, Size=0x%X, Attr 0x%X, Curr.mSecureBootMode %X\n",
VariableName, DataFirstByte, DataSize, Attributes, gSecureBootMode
));
// Write the variable to the actual NVRAM store
Status = NvramWriteVariable(VariableName, VendorGuid, Attributes, DataSize, Data);
if (EFI_ERROR(Status)) {
return Status;
}
// Handle SecureBootMode transitions
if (IsSecureBootModeManaged()) {
if (VarType == VAR_TYPE_SECURE_BOOT_1) {
// First type: handle PK/KEK changes
if (CheckPhysicalPresence()) {
CurrentMode = gSecureBootMode;
if (CurrentMode == 1) {
// Setup mode -> set to secure boot mode 0
Status = SetSecureBootMode(0);
} else if (CurrentMode == 2) {
// Deployed mode -> set to 3
Status = SetSecureBootMode(3);
} else {
DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode change.\n",
CurrentMode));
}
} else {
// Not physically present
if (gSecureBootMode == 0 || gSecureBootMode == 3) {
// Audit/deployed
Status = SetSecureBootMode(1); // user mode
}
}
}
}
DEBUG((EFI_D_INFO, "<==Set %s: %r\n", VariableName, Status));
return Status;
}
EFI_STATUS
SecureBootGetVariable(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
// For DeploymentModeNv and VendorKeysNv, reject access
if (!CompareGuid(VendorGuid, &gSecureBootVarGuid1, 16) ||
!CompareGuid(VariableName, L"DeploymentModeNv")) {
if (!CompareGuid(VendorGuid, &gSecureBootVarGuid2, 16) ||
!CompareGuid(VendorGuid, &gEfiGlobalVariableGuid, 16) ||
!CompareGuid(VariableName, L"VendorKeysNv")) {
return EFI_NOT_FOUND;
}
}
DEBUG((EFI_D_INFO,
"Set %s, DataSize %X, Data[0]=%X\nWRITE_PROTECTED\n",
VariableName, DataSize, *(UINT8 *)Data));
return EFI_WRITE_PROTECTED;
}
// ========================================================================
// Variable Synchronization Callbacks
// ========================================================================
EFI_STATUS
NvramSyncCallbackSetup(
IN CHAR16 *VariableName,
IN VOID *Data,
IN UINTN DataSize,
IN UINTN ExpectedSize,
IN VOID *Context
)
{
UINT8 DisableSyncFlag = 0;
UINT64 ValueSize = 7;
UINT64 ValueAttr = 1;
// Check disable flag variable
if (gDisableNvramSyncFlag == 1) {
NvramWriteVariable(
L"DisableNvramVariableSyncVar",
&gDisableNvramSyncGuid,
7, 1, &DisableSyncFlag
);
gDisableNvramSyncFlag = 0;
}
// Read disable flag
NvramReadVariable(
L"DisableNvramVariableSyncVar",
&gDisableNvramSyncGuid,
&ValueSize, &ValueAttr, &DisableSyncFlag
);
if (DisableSyncFlag) {
DEBUG((EFI_D_INFO, "DisableNvramVariableSync Value = %x So Stop Syncing\n",
DisableSyncFlag));
return EFI_NOT_FOUND;
}
// Variable sync from Setup to other config variables
if (CompareGuid(Data, &gSetupVariableGuid, 16) &&
!VariableNameMatch(VariableName, L"Setup") &&
ExpectedSize == 814) {
// Sync fields from Setup to variables
SetVariableIntFromSetup(Context, 85);
SetVariableEnumFromSetup(Context, 86);
}
// Sync SocketIioConfig
if (CompareGuid(Data, &gSocketIioConfigGuid, 16) &&
!VariableNameMatch(VariableName, L"SocketIioConfig") &&
ExpectedSize == 6668) {
SyncSocketIioConfig((UINT8 *)Context + 4020);
}
// Sync SRIOVEnable between IntelSetup and Setup
if (CompareGuid(Data, &gIntelSetupGuid, 16) &&
!VariableNameMatch(VariableName, L"IntelSetup") &&
ExpectedSize == 676) {
UINT64 SetupSize = 814;
UINT32 SetupAttr = 7;
UINT8 SetupBuffer[86];
EFI_STATUS Status = NvramReadVariable(
L"Setup",
&gSetupVariableGuid,
&SetupSize, &SetupAttr, SetupBuffer
);
if (!EFI_ERROR(Status) && SetupSize == 814) {
if (Context[262] != SetupBuffer[86]) {
Context[262] = SetupBuffer[86];
DEBUG((EFI_D_INFO, "Updated: *SRIOVEnable %d\n", SetupBuffer[86]));
}
} else {
DEBUG((EFI_D_ERROR,
"AmiSetupVariableSynLib.c: DxeGetVariable(SetupData) Failed\n"));
}
}
return EFI_NOT_FOUND;
}
// ========================================================================
// NVRAM Storage Helper Functions
// ========================================================================
UINTN
GetFvHeaderSize(
IN VOID *Buffer
)
{
// Check for FV header signature at offset 40
if (*(UINT32 *)((UINT8 *)Buffer + 40) != FV_SIGNATURE) {
return 0;
}
// FV header length at offset 48
UINT16 ExtHeaderOffset = *(UINT16 *)((UINT8 *)Buffer + 48);
if (ExtHeaderOffset == 0) {
return FV_HEADER_LENGTH; // basic FV header only
}
// Extended header present at ExtHeaderOffset
UINTN Delta = ExtHeaderOffset - FV_HEADER_LENGTH;
if (Delta > 0x8C) {
return 0;
}
UINT32 ExtHeaderSize = *(UINT32 *)((UINT8 *)Buffer + ExtHeaderOffset + 16);
if (ExtHeaderSize - 20 > 0x8C) {
return 0;
}
// Return aligned total size
UINTN TotalSize = ExtHeaderSize + ExtHeaderOffset;
return (TotalSize + 7) & ~7;
}
VOID
VarStoreInit(
IN OUT VAR_STORE_INFO *Info
)
{
UINT8 *StoreEnd = (UINT8 *)Info->StoreBase + Info->StoreSize;
Info->StoreFlags = 0;
Info->VariableStart = 0;
Info->StoreCurrent = StoreEnd - 16; // start from end, working backwards
Info->StoreEnd = StoreEnd;
Info->VariableStart = Info->StoreBase + Info->StoreFlags; // aligned from flags field
// Attempt to locate existing variable data
UINTN ExistingStart = FindExistingVariableStart();
if (ExistingStart != Info->VariableStart) {
if (ExistingStart != 0) {
Info->VariableStart = ExistingStart;
} else {
// Check for valid flash store
if (!IsValidNvramFlashStore(Info->VariableStart, Info)) {
Info->StoreCurrent = Info->VariableStart; // no existing data
}
}
}
}
// ========================================================================
// NVRAM HOB Retrieval (sub_644C)
// ========================================================================
EFI_STATUS
NvramHobRetrieve(
VOID
)
{
EFI_HOB_GUID_TYPE *GuidHob;
VOID *NvramHobData;
UINTN NvramSize = 0x80000;
EFI_STATUS Status;
UINT8 Mode8;
// Search for NVRAM HOB
GuidHob = GetFirstGuidHob(&gNvramHobGuid);
if (GuidHob == NULL) {
// No HOB found, run in simulation mode
DEBUG((EFI_D_ERROR, "NVRAM: NVRAM HOB not found. Simulation mode.\n"));
NvramSize = 0x80000;
goto setup_simulation;
}
NvramSize = *(UINT32 *)((UINT8 *)GuidHob + 48); // HOB +48 = NVRAM size
VOID *StoreAddr = *(VOID **)((UINT8 *)GuidHob + 24); // HOB +24 = store address
Status = GetGcdDescriptor(StoreAddr, &gNvramStoreBase, &gNvramStoreSize);
if (EFI_ERROR(Status) && gNvramStoreSize == 1) {
// Validate that store fits in the GCD descriptor
UINTN BackupSize = *(UINT32 *)((UINT8 *)GuidHob + 40);
if (StoreAddr + NvramSize <= gNvramStoreBase + gNvramStoreSize &&
StoreAddr + BackupSize + NvramSize <= gNvramStoreBase + gNvramStoreSize) {
goto init_valid;
} else {
DEBUG((EFI_D_ERROR,
"NVRAM: NvramAddress not matching GcdDescriptor!\n"));
}
gNvramStoreBase = 0;
gNvramStoreSize = 0;
}
init_valid:
DEBUG((EFI_D_INFO,
"NVRAM: main store address: %lX; backup store address: %lX\n",
StoreAddr, NvramHobData));
DEBUG((EFI_D_INFO,
"NVRAM: GcdDescriptor BaseAddress: %lX, Length: %lX\n",
gNvramStoreBase, gNvramStoreSize));
setup_simulation:
// Allocate working buffer for NVRAM image
VOID *WorkingBuffer = HeapAlloc(NvramSize);
if (WorkingBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// If no real store, fill with 0xFF (simulation)
if (StoreAddr == NULL) {
SetMem(WorkingBuffer, NvramSize, 0xFF);
gVarStoreInitFlags |= 8; // simulation mode
goto init_store;
}
// Read store from actual flash
Status = gMmst->SmmIo->Read(StoreAddr, NvramSize, WorkingBuffer);
if (EFI_ERROR(Status)) {
return Status;
}
if (gNvramStoreSize == 1) {
// First initialization: discover GCD descriptor
Status = gDS->GetMemorySpaceDescriptor(StoreAddr, &gNvramStoreBase, &gNvramStoreSize);
if (EFI_ERROR(Status)) {
return Status;
}
// Validate boundaries
// ...
}
init_store:
// Setup variable store info from working buffer
Mode8 = (gVarStoreInitFlags >> 3) & 1;
Status = NvramStoreInit(
&gVarStoreArray[gVarStoreCount],
WorkingBuffer,
NvramSize,
Mode8,
&gVarStoreHeaderSize
);
if (EFI_ERROR(Status)) {
return Status;
}
// Store info pointer to the variable store array entry
gVarStoreArray[gVarStoreCount].StoreSize = NvramSize;
gVarStoreArray[gVarStoreCount].StoreCurrent = WorkingBuffer;
gVarStoreArray[...].FlashProtocol = &gAmiNvramNvramProtocol;
gVarStoreArray[...].VendorGuid = &gNvramNvramHobGuid;
// Set up callback table for for for for for for...
StoreInfo->NvNvramramram FlashFlashProprototocolcolcol == &gAmiAmiNvramramUpdateProtocol;
StoreInfo->InitFlags = Mode8;
// Mark as initialized
VarStoreInit(StoreInfo);
gVarStoreCount++;
// Allocate the driver's NVRAM working buffer (3x store size for GC)
gDriverNvramBuffer = HeapAlloc(3 * NvramSize);
if (gDriverNvramBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Process "StdDefaults" if present for first-boot defaults
if (CheckStdDefaults(StoreInfo)) {
// Load default variable values from HOB or FV
LoadDefaultVariables();
gVarStoreInitFlags &= ~2; // clear defaults flag
if (GuidHob) {
*(UINT32 *)((UINT8 *)GuidHob + 48) &= ~2;
}
}
// Apply defaults
ApplyPendingResets(StoreInfo);
// Determine actual maximum NVRAM size across all stores
UINTN MaxSize = NvramSize;
BOOLEAN Resized = FALSE;
for (UINTN i = 0; i < gVarStoreCount; i++) {
if (!(gVarStoreArray[i].StoreFlags & 2) && gVarStoreArray[i].StoreSize > MaxSize) {
MaxSize = gVarStoreArray[i].StoreSize;
Resized = TRUE;
}
}
if (Resized) {
// Re allocate driver buffer with larger size
HeapFree(gDriverNvramramBuffer, gDriverNvramramBufferSize);
gDriverNvramramBuffer = HeapAlloc(3 * MaxSize);
gDriverNvramramBufferSize = 3 * MaxSize;
}
} }
}
// ======================================================================
// NVRAMAM Init (sub_68384)
// ======================================================================
EFI__STATUS
NvramHobFind(
VOID
)
{
EFI_HOB_GUID_TYPE *GuidHob ;
UINT32 HOBList;
UINTN NvramSize = 0x800;
UINT16 *HobPtr;
// Find the NVRAM HOB from HOB list
GuidHob = GetFirstGuidHob(&gNvramHobGuid);
if (GuidHob == NULL) {
NvramSize = 0x8000000;
goto fallback;
}
// Walk HOB list looking for NVRAM HOB data structure
HobPtr = (UINT16 *)GuidHob;
UINT16 TargetTag = L\"(AsciiStrnLenS...) - 1;
while (1) {
if (*HobPtr == TargetTag) {
HobPtr = NULL;
break;
}
HobPtr += *(UINT16 *)((UINT8 *)HobPtr + 2) / 2;
if (*HobPtr == 4) break;
}
if (HobPtr && !CompareGuid((UINT8 *)HobPtr + 8, &gNvramHobGuid, 16)) {
NvramSize = *(UINT32 *)((UINT8 *)HobPtr + 40);
if (NvramSize < 0x80000) {
NvramSize = 0x80000;
}
}
fallback:
// Initialize driver's NVRAM working buffer
SetMem(gVarStoreInitFlagsArea, 768, 0);
gDriverNvramBufferSize = 3 * NvramSize;
gDriverNvramBuffer = HeapAlloc(gDriverNvramBufferSize);
if (gDriverNvramramBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Initialize the store from from HOB
Status = NvramramHobInit(GuidHob, &gDriverNvramramBuffer);
if (EFI_ERROR(Status)) {
return Status;
}
// Set up VarStore array entry
VAR_STORE_INFO *StoreInfo = &gVVarStoreBase + 16 * gVarStoreCount + 4 + 2 * gVarStoreCount;
StoreInfo->NvramBuffer = HeapAlloc(0x80000);
SetMem(StoreInfo->NvramBuffer, 0x80000, 0xFF);
StoreInfo->Flags = 0;
StoreInfo->FlashProtocol = &gAmiNvramUpdateProtocol;
VarStoreInit(StoreInfo);
gVarStoreCount++;
gFirstvarStoreInfo = (UINT64)StoreInfo;
// Allocate working comparison buffer
gNvramStoreBase = HeapAlloc(0x80000);
if (gNvramStoreBase) {
gNvramStoreSize = 0x80000;
gNvramDmaBuffer = &gNvramStoreBase;
NotifyVarStoreInfoChange();
}
// Ensure all stores fit in the working buffer
// ...
return EFI_SUCCESS;
}