| /** @file | |
| This is a simple fault tolerant write driver that is intended to use in the SMM environment. | |
| This boot service protocol only provides fault tolerant write capability for | |
| block devices. The protocol has internal non-volatile intermediate storage | |
| of the data and private information. It should be able to recover | |
| automatically from a critical fault, such as power failure. | |
| The implementation uses an FTW (Fault Tolerant Write) Work Space. | |
| This work space is a memory copy of the work space on the Working Block, | |
| the size of the work space is the FTW_WORK_SPACE_SIZE bytes. | |
| The work space stores each write record as EFI_FTW_RECORD structure. | |
| The spare block stores the write buffer before write to the target block. | |
| The write record has three states to specify the different phase of write operation. | |
| 1) WRITE_ALLOCATED is that the record is allocated in write space. | |
| The information of write operation is stored in write record structure. | |
| 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup. | |
| 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block. | |
| This driver operates the data as the whole size of spare block. | |
| It first read the SpareAreaLength data from the target block into the spare memory buffer. | |
| Then copy the write buffer data into the spare memory buffer. | |
| Then write the spare memory buffer into the spare block. | |
| Final copy the data from the spare block to the target block. | |
| To make this drive work well, the following conditions must be satisfied: | |
| 1. The write NumBytes data must be fit within Spare area. | |
| Offset + NumBytes <= SpareAreaLength | |
| 2. The whole flash range has the same block size. | |
| 3. Working block is an area which contains working space in its last block and has the same size as spare block. | |
| 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on. | |
| 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on. | |
| 6. Any write data area (SpareAreaLength Area) which the data will be written into must be | |
| in the single one Firmware Volume Block range which FVB protocol is produced on. | |
| 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged. | |
| The spare area must be enough large to store the write data before write them into the target range. | |
| If one of them is not satisfied, FtwWrite may fail. | |
| Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1. | |
| Caution: This module requires additional review when modified. | |
| This driver need to make sure the CommBuffer is not in the SMRAM range. | |
| Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <PiSmm.h> | |
| #include <Library/SmmServicesTableLib.h> | |
| #include <Library/SmmMemLib.h> | |
| #include <Protocol/SmmSwapAddressRange.h> | |
| #include "FaultTolerantWrite.h" | |
| #include "FaultTolerantWriteSmmCommon.h" | |
| #include <Protocol/SmmEndOfDxe.h> | |
| EFI_EVENT mFvbRegistration = NULL; | |
| EFI_FTW_DEVICE *mFtwDevice = NULL; | |
| /// | |
| /// The flag to indicate whether the platform has left the DXE phase of execution. | |
| /// | |
| BOOLEAN mEndOfDxe = FALSE; | |
| /** | |
| Retrieve the SMM FVB protocol interface by HANDLE. | |
| @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for | |
| reading, writing, and erasing the target block. | |
| @param[out] FvBlock The interface of SMM FVB protocol | |
| @retval EFI_SUCCESS The interface information for the specified protocol was returned. | |
| @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol. | |
| @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. | |
| **/ | |
| EFI_STATUS | |
| FtwGetFvbByHandle ( | |
| IN EFI_HANDLE FvBlockHandle, | |
| OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock | |
| ) | |
| { | |
| // | |
| // To get the SMM FVB protocol interface on the handle | |
| // | |
| return gSmst->SmmHandleProtocol ( | |
| FvBlockHandle, | |
| &gEfiSmmFirmwareVolumeBlockProtocolGuid, | |
| (VOID **) FvBlock | |
| ); | |
| } | |
| /** | |
| Retrieve the SMM Swap Address Range protocol interface. | |
| @param[out] SarProtocol The interface of SMM SAR protocol | |
| @retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol. | |
| @retval EFI_NOT_FOUND The SMM SAR protocol instance was not found. | |
| @retval EFI_INVALID_PARAMETER SarProtocol is NULL. | |
| **/ | |
| EFI_STATUS | |
| FtwGetSarProtocol ( | |
| OUT VOID **SarProtocol | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Locate Smm Swap Address Range protocol | |
| // | |
| Status = gSmst->SmmLocateProtocol ( | |
| &gEfiSmmSwapAddressRangeProtocolGuid, | |
| NULL, | |
| SarProtocol | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Function returns an array of handles that support the SMM FVB protocol | |
| in a buffer allocated from pool. | |
| @param[out] NumberHandles The number of handles returned in Buffer. | |
| @param[out] Buffer A pointer to the buffer to return the requested | |
| array of handles that support SMM FVB protocol. | |
| @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of | |
| handles in Buffer was returned in NumberHandles. | |
| @retval EFI_NOT_FOUND No SMM FVB handle was found. | |
| @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. | |
| @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. | |
| **/ | |
| EFI_STATUS | |
| GetFvbCountAndBuffer ( | |
| OUT UINTN *NumberHandles, | |
| OUT EFI_HANDLE **Buffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| if ((NumberHandles == NULL) || (Buffer == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| BufferSize = 0; | |
| *NumberHandles = 0; | |
| *Buffer = NULL; | |
| Status = gSmst->SmmLocateHandle ( | |
| ByProtocol, | |
| &gEfiSmmFirmwareVolumeBlockProtocolGuid, | |
| NULL, | |
| &BufferSize, | |
| *Buffer | |
| ); | |
| if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| *Buffer = AllocatePool (BufferSize); | |
| if (*Buffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = gSmst->SmmLocateHandle ( | |
| ByProtocol, | |
| &gEfiSmmFirmwareVolumeBlockProtocolGuid, | |
| NULL, | |
| &BufferSize, | |
| *Buffer | |
| ); | |
| *NumberHandles = BufferSize / sizeof(EFI_HANDLE); | |
| if (EFI_ERROR(Status)) { | |
| *NumberHandles = 0; | |
| FreePool (*Buffer); | |
| *Buffer = NULL; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Get the handle of the SMM FVB protocol by the FVB base address and attributes. | |
| @param[in] Address The base address of SMM FVB protocol. | |
| @param[in] Attributes The attributes of the SMM FVB protocol. | |
| @param[out] SmmFvbHandle The handle of the SMM FVB protocol. | |
| @retval EFI_SUCCESS The FVB handle is found. | |
| @retval EFI_ABORTED The FVB protocol is not found. | |
| **/ | |
| EFI_STATUS | |
| GetFvbByAddressAndAttribute ( | |
| IN EFI_PHYSICAL_ADDRESS Address, | |
| IN EFI_FVB_ATTRIBUTES_2 Attributes, | |
| OUT EFI_HANDLE *SmmFvbHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE *HandleBuffer; | |
| UINTN HandleCount; | |
| UINTN Index; | |
| EFI_PHYSICAL_ADDRESS FvbBaseAddress; | |
| EFI_FVB_ATTRIBUTES_2 FvbAttributes; | |
| EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; | |
| HandleBuffer = NULL; | |
| // | |
| // Locate all handles of SMM Fvb protocol. | |
| // | |
| Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Find the proper SMM Fvb handle by the address and attributes. | |
| // | |
| for (Index = 0; Index < HandleCount; Index++) { | |
| Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb); | |
| if (EFI_ERROR (Status)) { | |
| break; | |
| } | |
| // | |
| // Compare the address. | |
| // | |
| Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| if (Address != FvbBaseAddress) { | |
| continue; | |
| } | |
| // | |
| // Compare the attribute. | |
| // | |
| Status = Fvb->GetAttributes (Fvb, &FvbAttributes); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| if (Attributes != FvbAttributes) { | |
| continue; | |
| } | |
| // | |
| // Found the proper FVB handle. | |
| // | |
| *SmmFvbHandle = HandleBuffer[Index]; | |
| FreePool (HandleBuffer); | |
| return EFI_SUCCESS; | |
| } | |
| FreePool (HandleBuffer); | |
| return EFI_ABORTED; | |
| } | |
| /** | |
| Communication service SMI Handler entry. | |
| This SMI handler provides services for the fault tolerant write wrapper driver. | |
| Caution: This function requires additional review when modified. | |
| This driver need to make sure the CommBuffer is not in the SMRAM range. | |
| Also in FTW_FUNCTION_GET_LAST_WRITE case, check SmmFtwGetLastWriteHeader->Data + | |
| SmmFtwGetLastWriteHeader->PrivateDataSize within communication buffer. | |
| @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). | |
| @param[in] RegisterContext Points to an optional handler context which was specified when the | |
| handler was registered. | |
| @param[in, out] CommBuffer A pointer to a collection of data in memory that will be conveyed | |
| from a non-SMM environment into an SMM environment. | |
| @param[in, out] CommBufferSize The size of the CommBuffer. | |
| @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers | |
| should still be called. | |
| @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should | |
| still be called. | |
| @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still | |
| be called. | |
| @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmFaultTolerantWriteHandler ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *RegisterContext, | |
| IN OUT VOID *CommBuffer, | |
| IN OUT UINTN *CommBufferSize | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| SMM_FTW_COMMUNICATE_FUNCTION_HEADER *SmmFtwFunctionHeader; | |
| SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *SmmGetMaxBlockSizeHeader; | |
| SMM_FTW_ALLOCATE_HEADER *SmmFtwAllocateHeader; | |
| SMM_FTW_WRITE_HEADER *SmmFtwWriteHeader; | |
| SMM_FTW_RESTART_HEADER *SmmFtwRestartHeader; | |
| SMM_FTW_GET_LAST_WRITE_HEADER *SmmFtwGetLastWriteHeader; | |
| VOID *PrivateData; | |
| EFI_HANDLE SmmFvbHandle; | |
| UINTN InfoSize; | |
| UINTN CommBufferPayloadSize; | |
| UINTN PrivateDataSize; | |
| UINTN Length; | |
| UINTN TempCommBufferSize; | |
| // | |
| // If input is invalid, stop processing this SMI | |
| // | |
| if (CommBuffer == NULL || CommBufferSize == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| TempCommBufferSize = *CommBufferSize; | |
| if (TempCommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) { | |
| DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE; | |
| if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) { | |
| DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer; | |
| if (mEndOfDxe) { | |
| // | |
| // It will be not safe to expose the operations after End Of Dxe. | |
| // | |
| DEBUG ((EFI_D_ERROR, "SmmFtwHandler: Not safe to do the operation: %x after End Of Dxe, so access denied!\n", SmmFtwFunctionHeader->Function)); | |
| SmmFtwFunctionHeader->ReturnStatus = EFI_ACCESS_DENIED; | |
| return EFI_SUCCESS; | |
| } | |
| switch (SmmFtwFunctionHeader->Function) { | |
| case FTW_FUNCTION_GET_MAX_BLOCK_SIZE: | |
| if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) { | |
| DEBUG ((EFI_D_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data; | |
| Status = FtwGetMaxBlockSize ( | |
| &mFtwDevice->FtwInstance, | |
| &SmmGetMaxBlockSizeHeader->BlockSize | |
| ); | |
| break; | |
| case FTW_FUNCTION_ALLOCATE: | |
| if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) { | |
| DEBUG ((EFI_D_ERROR, "Allocate: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data; | |
| Status = FtwAllocate ( | |
| &mFtwDevice->FtwInstance, | |
| &SmmFtwAllocateHeader->CallerId, | |
| SmmFtwAllocateHeader->PrivateDataSize, | |
| SmmFtwAllocateHeader->NumberOfWrites | |
| ); | |
| break; | |
| case FTW_FUNCTION_WRITE: | |
| if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) { | |
| DEBUG ((EFI_D_ERROR, "Write: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data; | |
| Length = SmmFtwWriteHeader->Length; | |
| PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize; | |
| if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) || | |
| ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length)) { | |
| // | |
| // Prevent InfoSize overflow | |
| // | |
| Status = EFI_ACCESS_DENIED; | |
| break; | |
| } | |
| InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize; | |
| // | |
| // SMRAM range check already covered before | |
| // | |
| if (InfoSize > CommBufferPayloadSize) { | |
| DEBUG ((EFI_D_ERROR, "Write: Data size exceed communication buffer size limit!\n")); | |
| Status = EFI_ACCESS_DENIED; | |
| break; | |
| } | |
| if (PrivateDataSize == 0) { | |
| PrivateData = NULL; | |
| } else { | |
| PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length]; | |
| } | |
| Status = GetFvbByAddressAndAttribute ( | |
| SmmFtwWriteHeader->FvbBaseAddress, | |
| SmmFtwWriteHeader->FvbAttributes, | |
| &SmmFvbHandle | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| Status = FtwWrite( | |
| &mFtwDevice->FtwInstance, | |
| SmmFtwWriteHeader->Lba, | |
| SmmFtwWriteHeader->Offset, | |
| Length, | |
| PrivateData, | |
| SmmFvbHandle, | |
| SmmFtwWriteHeader->Data | |
| ); | |
| } | |
| break; | |
| case FTW_FUNCTION_RESTART: | |
| if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) { | |
| DEBUG ((EFI_D_ERROR, "Restart: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data; | |
| Status = GetFvbByAddressAndAttribute ( | |
| SmmFtwRestartHeader->FvbBaseAddress, | |
| SmmFtwRestartHeader->FvbAttributes, | |
| &SmmFvbHandle | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| Status = FtwRestart (&mFtwDevice->FtwInstance, SmmFvbHandle); | |
| } | |
| break; | |
| case FTW_FUNCTION_ABORT: | |
| Status = FtwAbort (&mFtwDevice->FtwInstance); | |
| break; | |
| case FTW_FUNCTION_GET_LAST_WRITE: | |
| if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) { | |
| DEBUG ((EFI_D_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n")); | |
| return EFI_SUCCESS; | |
| } | |
| SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data; | |
| PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize; | |
| if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){ | |
| // | |
| // Prevent InfoSize overflow | |
| // | |
| Status = EFI_ACCESS_DENIED; | |
| break; | |
| } | |
| InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize; | |
| // | |
| // SMRAM range check already covered before | |
| // | |
| if (InfoSize > CommBufferPayloadSize) { | |
| DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n")); | |
| Status = EFI_ACCESS_DENIED; | |
| break; | |
| } | |
| Status = FtwGetLastWrite ( | |
| &mFtwDevice->FtwInstance, | |
| &SmmFtwGetLastWriteHeader->CallerId, | |
| &SmmFtwGetLastWriteHeader->Lba, | |
| &SmmFtwGetLastWriteHeader->Offset, | |
| &SmmFtwGetLastWriteHeader->Length, | |
| &PrivateDataSize, | |
| (VOID *)SmmFtwGetLastWriteHeader->Data, | |
| &SmmFtwGetLastWriteHeader->Complete | |
| ); | |
| SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize; | |
| break; | |
| default: | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| SmmFtwFunctionHeader->ReturnStatus = Status; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| SMM Firmware Volume Block Protocol notification event handler. | |
| @param[in] Protocol Points to the protocol's unique identifier | |
| @param[in] Interface Points to the interface instance | |
| @param[in] Handle The handle on which the interface was installed | |
| @retval EFI_SUCCESS SmmEventCallback runs successfully | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvbNotificationEvent ( | |
| IN CONST EFI_GUID *Protocol, | |
| IN VOID *Interface, | |
| IN EFI_HANDLE Handle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; | |
| EFI_HANDLE SmmFtwHandle; | |
| EFI_HANDLE FtwHandle; | |
| // | |
| // Just return to avoid install SMM FaultTolerantWriteProtocol again | |
| // if SMM Fault Tolerant Write protocol had been installed. | |
| // | |
| Status = gSmst->SmmLocateProtocol ( | |
| &gEfiSmmFaultTolerantWriteProtocolGuid, | |
| NULL, | |
| (VOID **) &FtwProtocol | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Found proper FVB protocol and initialize FtwDevice for protocol installation | |
| // | |
| Status = InitFtwProtocol (mFtwDevice); | |
| if (EFI_ERROR(Status)) { | |
| return Status; | |
| } | |
| // | |
| // Install protocol interface | |
| // | |
| Status = gSmst->SmmInstallProtocolInterface ( | |
| &mFtwDevice->Handle, | |
| &gEfiSmmFaultTolerantWriteProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &mFtwDevice->FtwInstance | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| /// | |
| /// Register SMM FTW SMI handler | |
| /// | |
| Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Notify the Ftw wrapper driver SMM Ftw is ready | |
| // | |
| FtwHandle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &FtwHandle, | |
| &gEfiSmmFaultTolerantWriteProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| SMM END_OF_DXE protocol notification event handler. | |
| @param Protocol Points to the protocol's unique identifier | |
| @param Interface Points to the interface instance | |
| @param Handle The handle on which the interface was installed | |
| @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmEndOfDxeCallback ( | |
| IN CONST EFI_GUID *Protocol, | |
| IN VOID *Interface, | |
| IN EFI_HANDLE Handle | |
| ) | |
| { | |
| mEndOfDxe = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function is the entry point of the Fault Tolerant Write driver. | |
| @param[in] ImageHandle A handle for the image that is initializing this driver | |
| @param[in] SystemTable A pointer to the EFI system table | |
| @retval EFI_SUCCESS The initialization finished successfully. | |
| @retval EFI_OUT_OF_RESOURCES Allocate memory error | |
| @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmFaultTolerantWriteInitialize ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *SmmEndOfDxeRegistration; | |
| // | |
| // Allocate private data structure for SMM FTW protocol and do some initialization | |
| // | |
| Status = InitFtwDevice (&mFtwDevice); | |
| if (EFI_ERROR(Status)) { | |
| return Status; | |
| } | |
| // | |
| // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function. | |
| // | |
| Status = gSmst->SmmRegisterProtocolNotify ( | |
| &gEfiSmmEndOfDxeProtocolGuid, | |
| SmmEndOfDxeCallback, | |
| &SmmEndOfDxeRegistration | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Register FvbNotificationEvent () notify function. | |
| // | |
| Status = gSmst->SmmRegisterProtocolNotify ( | |
| &gEfiSmmFirmwareVolumeBlockProtocolGuid, | |
| FvbNotificationEvent, | |
| &mFvbRegistration | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| FvbNotificationEvent (NULL, NULL, NULL); | |
| return EFI_SUCCESS; | |
| } |