Home | History | Annotate | Download | only in RuntimeDxe
      1 /** @file
      2   Handles non-volatile variable store garbage collection, using FTW
      3   (Fault Tolerant Write) protocol.
      4 
      5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Variable.h"
     17 
     18 /**
     19   Gets LBA of block and offset by given address.
     20 
     21   This function gets the Logical Block Address (LBA) of a firmware
     22   volume block containing the given address, and the offset of the
     23   address on the block.
     24 
     25   @param  Address        Address which should be contained
     26                          by returned FVB handle.
     27   @param  Lba            Pointer to LBA for output.
     28   @param  Offset         Pointer to offset for output.
     29 
     30   @retval EFI_SUCCESS    LBA and offset successfully returned.
     31   @retval EFI_NOT_FOUND  Fail to find FVB handle by address.
     32   @retval EFI_ABORTED    Fail to find valid LBA and offset.
     33 
     34 **/
     35 EFI_STATUS
     36 GetLbaAndOffsetByAddress (
     37   IN  EFI_PHYSICAL_ADDRESS   Address,
     38   OUT EFI_LBA                *Lba,
     39   OUT UINTN                  *Offset
     40   )
     41 {
     42   EFI_STATUS                          Status;
     43   EFI_PHYSICAL_ADDRESS                FvbBaseAddress;
     44   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
     45   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
     46   EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;
     47   UINT32                              LbaIndex;
     48 
     49   Fvb     = NULL;
     50   *Lba    = (EFI_LBA) (-1);
     51   *Offset = 0;
     52 
     53   //
     54   // Get the proper FVB protocol.
     55   //
     56   Status = GetFvbInfoByAddress (Address, NULL, &Fvb);
     57   if (EFI_ERROR (Status)) {
     58     return Status;
     59   }
     60 
     61   //
     62   // Get the Base Address of FV.
     63   //
     64   Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
     65   if (EFI_ERROR (Status)) {
     66     return Status;
     67   }
     68 
     69   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
     70 
     71   //
     72   // Get the (LBA, Offset) of Address.
     73   //
     74   if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
     75     //
     76     // BUGBUG: Assume one FV has one type of BlockLength.
     77     //
     78     FvbMapEntry = &FwVolHeader->BlockMap[0];
     79     for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
     80       if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
     81         //
     82         // Found the (Lba, Offset).
     83         //
     84         *Lba    = LbaIndex - 1;
     85         *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
     86         return EFI_SUCCESS;
     87      }
     88     }
     89   }
     90 
     91   return EFI_ABORTED;
     92 }
     93 
     94 /**
     95   Writes a buffer to variable storage space, in the working block.
     96 
     97   This function writes a buffer to variable storage space into a firmware
     98   volume block device. The destination is specified by parameter
     99   VariableBase. Fault Tolerant Write protocol is used for writing.
    100 
    101   @param  VariableBase   Base address of variable to write
    102   @param  VariableBuffer Point to the variable data buffer.
    103 
    104   @retval EFI_SUCCESS    The function completed successfully.
    105   @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.
    106   @retval EFI_ABORTED    The function could not complete successfully.
    107 
    108 **/
    109 EFI_STATUS
    110 FtwVariableSpace (
    111   IN EFI_PHYSICAL_ADDRESS   VariableBase,
    112   IN VARIABLE_STORE_HEADER  *VariableBuffer
    113   )
    114 {
    115   EFI_STATUS                         Status;
    116   EFI_HANDLE                         FvbHandle;
    117   EFI_LBA                            VarLba;
    118   UINTN                              VarOffset;
    119   UINTN                              FtwBufferSize;
    120   EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;
    121 
    122   //
    123   // Locate fault tolerant write protocol.
    124   //
    125   Status = GetFtwProtocol((VOID **) &FtwProtocol);
    126   if (EFI_ERROR (Status)) {
    127     return EFI_NOT_FOUND;
    128   }
    129   //
    130   // Locate Fvb handle by address.
    131   //
    132   Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);
    133   if (EFI_ERROR (Status)) {
    134     return Status;
    135   }
    136   //
    137   // Get LBA and Offset by address.
    138   //
    139   Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
    140   if (EFI_ERROR (Status)) {
    141     return EFI_ABORTED;
    142   }
    143 
    144   FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
    145   ASSERT (FtwBufferSize == VariableBuffer->Size);
    146 
    147   //
    148   // FTW write record.
    149   //
    150   Status = FtwProtocol->Write (
    151                           FtwProtocol,
    152                           VarLba,         // LBA
    153                           VarOffset,      // Offset
    154                           FtwBufferSize,  // NumBytes
    155                           NULL,           // PrivateData NULL
    156                           FvbHandle,      // Fvb Handle
    157                           (VOID *) VariableBuffer // write buffer
    158                           );
    159 
    160   return Status;
    161 }
    162