Home | History | Annotate | Download | only in X64
      1 /*++
      2 
      3 Copyright (c) 2005 - 2008, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14     Fvb.c
     15 
     16 Abstract:
     17 
     18   Firmware Volume Block Protocol Runtime Abstraction
     19 
     20   mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the
     21   index in the mFvbEntry array. This should be the same sequence as the FVB's
     22   were described in the HOB. We have to remember the handle so we can tell if
     23   the protocol has been reinstalled and it needs updateing.
     24 
     25   If you are using any of these lib functions.you must first call FvbInitialize ().
     26 
     27 Key:
     28   FVB - Firmware Volume Block
     29 
     30 --*/
     31 
     32 #include "Tiano.h"
     33 #include "EfiRuntimeLib.h"
     34 #include EFI_PROTOCOL_DEFINITION (FirmwareVolumeBlock)
     35 #include EFI_PROTOCOL_DEFINITION (FvbExtension)
     36 
     37 //
     38 // Lib will ASSERT if more FVB devices than this are added to the system.
     39 //
     40 UINTN             mFvbCount;
     41 VOID              *mFvbRegistration;
     42 VOID              *mFvbExtRegistration;
     43 //static EFI_EVENT  mEfiFvbVirtualNotifyEvent;
     44 BOOLEAN           gEfiFvbInitialized = FALSE;
     45 EFI_EVENT         mFvbEvent;
     46 
     47 BOOLEAN
     48 IsMemoryRuntime (
     49   IN VOID   *Address
     50   )
     51 /*++
     52 
     53 Routine Description:
     54   Check whether an address is runtime memory or not.
     55 
     56 Arguments:
     57 
     58   Address - The Address being checked.
     59 
     60 Returns:
     61   TRUE    - The address is runtime memory.
     62   FALSE   - The address is not runtime memory.
     63 
     64 --*/
     65 {
     66   EFI_STATUS                           Status;
     67   UINT8                                TmpMemoryMap[1];
     68   UINTN                                MapKey;
     69   UINTN                                DescriptorSize;
     70   UINT32                               DescriptorVersion;
     71   UINTN                                MemoryMapSize;
     72   EFI_MEMORY_DESCRIPTOR                *MemoryMap;
     73   EFI_MEMORY_DESCRIPTOR                *MemoryMapPtr;
     74   BOOLEAN                              IsRuntime;
     75   UINTN                                Index;
     76 
     77   IsRuntime = FALSE;
     78 
     79   //
     80   // Get System MemoryMapSize
     81   //
     82   MemoryMapSize = 1;
     83   Status = gBS->GetMemoryMap (
     84                   &MemoryMapSize,
     85                   (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
     86                   &MapKey,
     87                   &DescriptorSize,
     88                   &DescriptorVersion
     89                   );
     90   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
     91   //
     92   // Enlarge space here, because we will allocate pool now.
     93   //
     94   MemoryMapSize += EFI_PAGE_SIZE;
     95   Status = gBS->AllocatePool (
     96                   EfiBootServicesData,
     97                   MemoryMapSize,
     98                   (VOID**)&MemoryMap
     99                   );
    100   ASSERT_EFI_ERROR (Status);
    101 
    102   //
    103   // Get System MemoryMap
    104   //
    105   Status = gBS->GetMemoryMap (
    106                   &MemoryMapSize,
    107                   MemoryMap,
    108                   &MapKey,
    109                   &DescriptorSize,
    110                   &DescriptorVersion
    111                   );
    112   ASSERT_EFI_ERROR (Status);
    113 
    114   MemoryMapPtr = MemoryMap;
    115   //
    116   // Search the request Address
    117   //
    118   for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
    119     if (((EFI_PHYSICAL_ADDRESS)(UINTN)Address >= MemoryMap->PhysicalStart) &&
    120         ((EFI_PHYSICAL_ADDRESS)(UINTN)Address < MemoryMap->PhysicalStart
    121                                               + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) {
    122       //
    123       // Found it
    124       //
    125       if (MemoryMap->Attribute & EFI_MEMORY_RUNTIME) {
    126         IsRuntime = TRUE;
    127       }
    128       break;
    129     }
    130     //
    131     // Get next item
    132     //
    133     MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
    134   }
    135 
    136   //
    137   // Done
    138   //
    139   gBS->FreePool (MemoryMapPtr);
    140 
    141   return IsRuntime;
    142 }
    143 
    144 VOID
    145 EFIAPI
    146 FvbNotificationFunction (
    147   IN  EFI_EVENT       Event,
    148   IN  VOID            *Context
    149   )
    150 /*++
    151 
    152 Routine Description:
    153   Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is
    154   reinstalled.
    155 
    156 Arguments:
    157 
    158   Event   - The Event that is being processed
    159 
    160   Context - Event Context
    161 
    162 Returns:
    163   None
    164 
    165 --*/
    166 {
    167   EFI_STATUS                         Status;
    168   UINTN                              BufferSize;
    169   EFI_HANDLE                         Handle;
    170   UINTN                              Index;
    171   UINTN                              UpdateIndex;
    172   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
    173   EFI_FVB_EXTENSION_PROTOCOL         *FvbExtension;
    174 
    175   while (TRUE) {
    176     BufferSize = sizeof (Handle);
    177     Status = gBS->LocateHandle (
    178                     ByRegisterNotify,
    179                     &gEfiFirmwareVolumeBlockProtocolGuid,
    180                     mFvbRegistration,
    181                     &BufferSize,
    182                     &Handle
    183                     );
    184     if (EFI_ERROR (Status)) {
    185       //
    186       // Exit Path of While Loop....
    187       //
    188       break;
    189     }
    190 
    191     UpdateIndex = MAX_FVB_COUNT;
    192     for (Index = 0; Index < mFvbCount; Index++) {
    193       if (mFvbEntry[Index].Handle == Handle) {
    194         //
    195         //  If the handle is already in the table just update the protocol
    196         //
    197         UpdateIndex = Index;
    198         break;
    199       }
    200     }
    201 
    202     if (UpdateIndex == MAX_FVB_COUNT) {
    203       //
    204       // Use the next free slot for a new entry
    205       //
    206       UpdateIndex                   = mFvbCount;
    207     }
    208     //
    209     // The array does not have enough entries
    210     //
    211     ASSERT (UpdateIndex < MAX_FVB_COUNT);
    212 
    213     //
    214     //  Get the interface pointer and if it's ours, skip it.
    215     //  We check Runtime here, because it has no reason to register
    216     //  a boot time FVB protocol.
    217     //
    218     Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb);
    219     ASSERT_EFI_ERROR (Status);
    220     if (IsMemoryRuntime (Fvb)) {
    221       //
    222       // Increase mFvbCount if we need to add a new entry
    223       //
    224       if (UpdateIndex == mFvbCount) {
    225         mFvbCount++;
    226       }
    227       mFvbEntry[UpdateIndex].Handle       = Handle;
    228       mFvbEntry[UpdateIndex].Fvb          = Fvb;
    229       mFvbEntry[UpdateIndex].FvbExtension = NULL;
    230 
    231       Status = gBS->HandleProtocol (Handle, &gEfiFvbExtensionProtocolGuid, (VOID **) &FvbExtension);
    232       if ((Status == EFI_SUCCESS) && IsMemoryRuntime (FvbExtension)) {
    233         mFvbEntry[UpdateIndex].FvbExtension = FvbExtension;
    234       }
    235     }
    236   }
    237 }
    238 
    239 EFI_STATUS
    240 EfiFvbInitialize (
    241   VOID
    242   )
    243 /*++
    244 
    245 Routine Description:
    246   Initialize globals and register Fvb Protocol notification function.
    247 
    248 Arguments:
    249   None
    250 
    251 Returns:
    252   EFI_SUCCESS - Fvb is successfully initialized
    253   others                - Fail to initialize
    254 
    255 --*/
    256 {
    257   UINTN Status;
    258   mFvbCount = 0;
    259 
    260   Status = gBS->AllocatePool (
    261                   EfiRuntimeServicesData,
    262                   (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT,
    263                   (VOID *) &mFvbEntry
    264                   );
    265 
    266   if (EFI_ERROR (Status)) {
    267     return Status;
    268   }
    269 
    270   EfiZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT);
    271 
    272   mFvbEvent = RtEfiLibCreateProtocolNotifyEvent (
    273     &gEfiFirmwareVolumeBlockProtocolGuid,
    274     EFI_TPL_CALLBACK,
    275     FvbNotificationFunction,
    276     NULL,
    277     &mFvbRegistration
    278     );
    279 
    280   //
    281   // Register SetVirtualAddressMap () notify function
    282   //
    283   //  Status = gBS->CreateEvent (
    284   //                EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
    285   //                EFI_TPL_NOTIFY,
    286   //                EfiRuntimeLibFvbVirtualNotifyEvent,
    287   //                NULL,
    288   //                &mEfiFvbVirtualNotifyEvent
    289   //                );
    290   //  ASSERT_EFI_ERROR (Status);
    291   //
    292   gEfiFvbInitialized = TRUE;
    293 
    294   return EFI_SUCCESS;
    295 }
    296 
    297 EFI_STATUS
    298 EfiFvbShutdown (
    299   VOID
    300   )
    301 /*++
    302 
    303 Routine Description:
    304   Release resources allocated in EfiFvbInitialize.
    305 
    306 Arguments:
    307   None
    308 
    309 Returns:
    310   EFI_SUCCESS
    311 
    312 --*/
    313 {
    314   gBS->FreePool ((VOID *) mFvbEntry);
    315 
    316   gBS->CloseEvent (mFvbEvent);
    317 
    318   gEfiFvbInitialized = FALSE;
    319 
    320   return EFI_SUCCESS;
    321 }
    322 
    323 //
    324 // The following functions wrap Fvb protocol in the Runtime Lib functions.
    325 // The Instance translates into Fvb instance. The Fvb order defined by HOBs and
    326 // thus the sequence of FVB protocol addition define Instance.
    327 //
    328 // EfiFvbInitialize () must be called before any of the following functions
    329 // must be called.
    330 //
    331 
    332 EFI_STATUS
    333 EfiFvbReadBlock (
    334   IN UINTN                                        Instance,
    335   IN EFI_LBA                                      Lba,
    336   IN UINTN                                        Offset,
    337   IN OUT UINTN                                    *NumBytes,
    338   IN UINT8                                        *Buffer
    339   )
    340 /*++
    341 
    342 Routine Description:
    343   Reads specified number of bytes into a buffer from the specified block
    344 
    345 Arguments:
    346   Instance              - The FV instance to be read from
    347   Lba                   - The logical block address to be read from
    348   Offset                - Offset into the block at which to begin reading
    349   NumBytes              - Pointer that on input contains the total size of
    350                           the buffer. On output, it contains the total number
    351                           of bytes read
    352   Buffer                - Pointer to a caller allocated buffer that will be
    353                           used to hold the data read
    354 
    355 Returns:
    356 
    357   Status code
    358 
    359   EFI_INVALID_PARAMETER - invalid parameter
    360 
    361 --*/
    362 {
    363   if (Instance >= mFvbCount) {
    364     return EFI_INVALID_PARAMETER;
    365   }
    366 
    367   return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);
    368 }
    369 
    370 EFI_STATUS
    371 EfiFvbWriteBlock (
    372   IN UINTN                                        Instance,
    373   IN EFI_LBA                                      Lba,
    374   IN UINTN                                        Offset,
    375   IN OUT UINTN                                    *NumBytes,
    376   IN UINT8                                        *Buffer
    377   )
    378 /*++
    379 
    380 Routine Description:
    381   Writes specified number of bytes from the input buffer to the block
    382 
    383 Arguments:
    384   Instance              - The FV instance to be written to
    385   Lba                   - The starting logical block index to write to
    386   Offset                - Offset into the block at which to begin writing
    387   NumBytes              - Pointer that on input contains the total size of
    388                           the buffer. On output, it contains the total number
    389                           of bytes actually written
    390   Buffer                - Pointer to a caller allocated buffer that contains
    391                           the source for the write
    392 
    393 Returns:
    394 
    395   Status code
    396 
    397   EFI_INVALID_PARAMETER - invalid parameter
    398 
    399 --*/
    400 {
    401   if (Instance >= mFvbCount) {
    402     return EFI_INVALID_PARAMETER;
    403   }
    404 
    405   return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);
    406 }
    407 
    408 EFI_STATUS
    409 EfiFvbEraseBlock (
    410   IN UINTN                                Instance,
    411   IN EFI_LBA                              Lba
    412   )
    413 /*++
    414 
    415 Routine Description:
    416   Erases and initializes a firmware volume block
    417 
    418 Arguments:
    419   Instance              - The FV instance to be erased
    420   Lba                   - The logical block index to be erased
    421 
    422 Returns:
    423 
    424   Status code
    425 
    426   EFI_INVALID_PARAMETER - invalid parameter
    427 
    428 --*/
    429 {
    430   if (Instance >= mFvbCount) {
    431     return EFI_INVALID_PARAMETER;
    432   }
    433 
    434   return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, -1);
    435 }
    436 
    437 EFI_STATUS
    438 EfiFvbGetVolumeAttributes (
    439   IN UINTN                                Instance,
    440   OUT EFI_FVB_ATTRIBUTES                  *Attributes
    441   )
    442 /*++
    443 
    444 Routine Description:
    445   Retrieves attributes, insures positive polarity of attribute bits, returns
    446   resulting attributes in output parameter
    447 
    448 Arguments:
    449   Instance              - The FV instance whose attributes is going to be
    450                           returned
    451   Attributes            - Output buffer which contains attributes
    452 
    453 Returns:
    454   Status code
    455 
    456   EFI_INVALID_PARAMETER - invalid parameter
    457 
    458 --*/
    459 {
    460   if (Instance >= mFvbCount) {
    461     return EFI_INVALID_PARAMETER;
    462   }
    463 
    464   return mFvbEntry[Instance].Fvb->GetVolumeAttributes (mFvbEntry[Instance].Fvb, Attributes);
    465 }
    466 
    467 EFI_STATUS
    468 EfiFvbSetVolumeAttributes (
    469   IN UINTN                                Instance,
    470   IN EFI_FVB_ATTRIBUTES                   Attributes
    471   )
    472 /*++
    473 
    474 Routine Description:
    475   Modifies the current settings of the firmware volume according to the
    476   input parameter.
    477 
    478 Arguments:
    479   Instance              - The FV instance whose attributes is going to be
    480                           modified
    481   Attributes            - It is a pointer to EFI_FVB_ATTRIBUTES
    482                           containing the desired firmware volume settings.
    483 
    484 Returns:
    485   Status code
    486 
    487   EFI_INVALID_PARAMETER - invalid parameter
    488 
    489 --*/
    490 {
    491   if (Instance >= mFvbCount) {
    492     return EFI_INVALID_PARAMETER;
    493   }
    494 
    495   return mFvbEntry[Instance].Fvb->SetVolumeAttributes (mFvbEntry[Instance].Fvb, &Attributes);
    496 }
    497 
    498 EFI_STATUS
    499 EfiFvbGetPhysicalAddress (
    500   IN UINTN                                Instance,
    501   OUT EFI_PHYSICAL_ADDRESS                *BaseAddress
    502   )
    503 /*++
    504 
    505 Routine Description:
    506   Retrieves the physical address of a memory mapped FV
    507 
    508 Arguments:
    509   Instance              - The FV instance whose base address is going to be
    510                           returned
    511   BaseAddress           - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
    512                           that on successful return, contains the base address
    513                           of the firmware volume.
    514 
    515 Returns:
    516 
    517   Status code
    518 
    519   EFI_INVALID_PARAMETER - invalid parameter
    520 
    521 --*/
    522 {
    523   if (Instance >= mFvbCount) {
    524     return EFI_INVALID_PARAMETER;
    525   }
    526 
    527   return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress);
    528 }
    529 
    530 EFI_STATUS
    531 EfiFvbGetBlockSize (
    532   IN UINTN                                        Instance,
    533   IN EFI_LBA                                      Lba,
    534   OUT UINTN                                       *BlockSize,
    535   OUT UINTN                                       *NumOfBlocks
    536   )
    537 /*++
    538 
    539 Routine Description:
    540   Retrieve the size of a logical block
    541 
    542 Arguments:
    543   Instance              - The FV instance whose block size is going to be
    544                           returned
    545   Lba                   - Indicates which block to return the size for.
    546   BlockSize             - A pointer to a caller allocated UINTN in which
    547                           the size of the block is returned
    548   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
    549                           number of consecutive blocks starting with Lba is
    550                           returned. All blocks in this range have a size of
    551                           BlockSize
    552 
    553 Returns:
    554   EFI_SUCCESS           - The firmware volume was read successfully and
    555                           contents are in Buffer
    556 
    557   EFI_INVALID_PARAMETER - invalid parameter
    558 
    559 --*/
    560 {
    561   if (Instance >= mFvbCount) {
    562     return EFI_INVALID_PARAMETER;
    563   }
    564 
    565   return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks);
    566 }
    567 
    568 EFI_STATUS
    569 EfiFvbEraseCustomBlockRange (
    570   IN UINTN                                Instance,
    571   IN EFI_LBA                              StartLba,
    572   IN UINTN                                OffsetStartLba,
    573   IN EFI_LBA                              LastLba,
    574   IN UINTN                                OffsetLastLba
    575   )
    576 /*++
    577 
    578 Routine Description:
    579   Erases and initializes a specified range of a firmware volume
    580 
    581 Arguments:
    582   Instance              - The FV instance to be erased
    583   StartLba              - The starting logical block index to be erased
    584   OffsetStartLba        - Offset into the starting block at which to
    585                           begin erasing
    586   LastLba               - The last logical block index to be erased
    587   OffsetLastLba         - Offset into the last block at which to end erasing
    588 
    589 Returns:
    590 
    591   Status code
    592 
    593   EFI_INVALID_PARAMETER - invalid parameter
    594 
    595   EFI_UNSUPPORTED       - not support
    596 
    597 --*/
    598 {
    599   if (Instance >= mFvbCount) {
    600     return EFI_INVALID_PARAMETER;
    601   }
    602 
    603   if (!(mFvbEntry[Instance].FvbExtension)) {
    604     return EFI_UNSUPPORTED;
    605   }
    606 
    607   if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) {
    608     return EFI_UNSUPPORTED;
    609   }
    610 
    611   return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock (
    612                                             mFvbEntry[Instance].FvbExtension,
    613                                             StartLba,
    614                                             OffsetStartLba,
    615                                             LastLba,
    616                                             OffsetLastLba
    617                                             );
    618 }
    619