Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15695 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			253 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   This is a simple fault tolerant write driver.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| Copyright (c) 2006 - 2014, 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 "FaultTolerantWrite.h"
 | |
| EFI_EVENT                                 mFvbRegistration = NULL;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Retrive the FVB protocol interface by HANDLE.
 | |
| 
 | |
|   @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for
 | |
|                                 reading, writing, and erasing the target block.
 | |
|   @param[out] FvBlock           The interface of FVB protocol
 | |
| 
 | |
|   @retval EFI_SUCCESS           The interface information for the specified protocol was returned.
 | |
|   @retval EFI_UNSUPPORTED       The device does not support the 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 FVB protocol interface on the handle
 | |
|   //
 | |
|   return gBS->HandleProtocol (
 | |
|                 FvBlockHandle,
 | |
|                 &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                 (VOID **) FvBlock
 | |
|                 );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrive the Swap Address Range protocol interface.
 | |
| 
 | |
|   @param[out] SarProtocol       The interface of SAR protocol
 | |
| 
 | |
|   @retval EFI_SUCCESS           The SAR protocol instance was found and returned in SarProtocol.
 | |
|   @retval EFI_NOT_FOUND         The SAR protocol instance was not found.
 | |
|   @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| FtwGetSarProtocol (
 | |
|   OUT VOID                                **SarProtocol
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
| 
 | |
|   //
 | |
|   // Locate Swap Address Range protocol
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiSwapAddressRangeProtocolGuid, 
 | |
|                   NULL, 
 | |
|                   SarProtocol
 | |
|                   );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Function returns an array of handles that support the 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 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 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;
 | |
| 
 | |
|   //
 | |
|   // Locate all handles of Fvb protocol
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|                   NULL,
 | |
|                   NumberHandles,
 | |
|                   Buffer
 | |
|                   );
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Firmware Volume Block Protocol notification event handler.
 | |
| 
 | |
|   @param[in] Event    Event whose notification function is being invoked.
 | |
|   @param[in] Context  Pointer to the notification function's context.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| FvbNotificationEvent (
 | |
|   IN  EFI_EVENT                           Event,
 | |
|   IN  VOID                                *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_FAULT_TOLERANT_WRITE_PROTOCOL       *FtwProtocol;
 | |
|   EFI_FTW_DEVICE                          *FtwDevice;
 | |
| 
 | |
|   //
 | |
|   // Just return to avoid installing FaultTolerantWriteProtocol again
 | |
|   // if Fault Tolerant Write protocol has been installed.
 | |
|   //  
 | |
|   Status = gBS->LocateProtocol (
 | |
|                   &gEfiFaultTolerantWriteProtocolGuid, 
 | |
|                   NULL, 
 | |
|                   (VOID **) &FtwProtocol
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Found proper FVB protocol and initialize FtwDevice for protocol installation
 | |
|   //
 | |
|   FtwDevice = (EFI_FTW_DEVICE *)Context;
 | |
|   Status = InitFtwProtocol (FtwDevice);
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return ;
 | |
|   }                          
 | |
|     
 | |
|   //
 | |
|   // Install protocol interface
 | |
|   //
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &FtwDevice->Handle,
 | |
|                   &gEfiFaultTolerantWriteProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &FtwDevice->FtwInstance
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   
 | |
|   Status = gBS->CloseEvent (Event);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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
 | |
| FaultTolerantWriteInitialize (
 | |
|   IN EFI_HANDLE                           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE                     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_FTW_DEVICE                          *FtwDevice;
 | |
| 
 | |
|   FtwDevice = NULL;
 | |
| 
 | |
|   //
 | |
|   // Allocate private data structure for FTW protocol and do some initialization
 | |
|   //
 | |
|   Status = InitFtwDevice (&FtwDevice);
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Register FvbNotificationEvent () notify function.
 | |
|   // 
 | |
|   EfiCreateProtocolNotifyEvent (
 | |
|     &gEfiFirmwareVolumeBlockProtocolGuid,
 | |
|     TPL_CALLBACK,
 | |
|     FvbNotificationEvent,
 | |
|     (VOID *)FtwDevice,
 | |
|     &mFvbRegistration
 | |
|     );
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 |