Home | History | Annotate | Download | only in FlashDeviceLib
      1 /** @file
      2 
      3   Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials are licensed and made available under
      7   the terms and conditions of the BSD License that accompanies this distribution.
      9   The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php.
     13 
     15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     17   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     21 
     23 
     24 **/
     25 
     26 #include <PiDxe.h>
     27 
     28 #include <Library/FlashDeviceLib.h>
     29 #include <Library/DebugLib.h>
     30 #include <Library/BaseLib.h>
     31 #include <Library/UefiBootServicesTableLib.h>
     32 #include <Library/UefiRuntimeServicesTableLib.h>
     33 #include <Library/BaseMemoryLib.h>
     34 #include <Library/UefiRuntimeLib.h>
     35 #include <Protocol/SmmBase2.h>
     36 #include <Guid/EventGroup.h>
     37 #include "SpiChipDefinitions.h"
     38 
     39 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS;
     40 
     41 EFI_SPI_PROTOCOL *mSpiProtocol = NULL;
     42 
     43 EFI_STATUS
     44 SpiFlashErase (
     45   UINT8 *BaseAddress,
     46   UINTN NumBytes
     47   )
     48 {
     49   EFI_STATUS          Status = EFI_SUCCESS;
     50   UINT32              SectorSize;
     51   UINT32              SpiAddress;
     52 
     53   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
     54   SectorSize = SECTOR_SIZE_4KB;
     55   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
     56     Status = mSpiProtocol->Execute (
     57                              mSpiProtocol,
     58                              SPI_SERASE,
     59                              SPI_WREN,
     60                              FALSE,
     61                              TRUE,
     62                              FALSE,
     63                              (UINT32) SpiAddress,
     64                              0,
     65                              NULL,
     66                              EnumSpiRegionBios
     67                              );
     68     if (EFI_ERROR (Status)) {
     69       break;
     70     }
     71     SpiAddress += SectorSize;
     72     NumBytes   -= SectorSize;
     73   }
     74 
     75   return Status;
     76 }
     77 
     78 
     79 EFI_STATUS
     80 SpiFlashBlockErase (
     81   UINT8 *BaseAddress,
     82   UINTN NumBytes
     83   )
     84 {
     85   EFI_STATUS          Status = EFI_SUCCESS;
     86   UINT32              SectorSize;
     87   UINT32              SpiAddress;
     88 
     89   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
     90   SectorSize = SECTOR_SIZE_64KB;
     91   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
     92     Status = mSpiProtocol->Execute (
     93                              mSpiProtocol,
     94                              SPI_BERASE,
     95                              SPI_WREN,
     96                              FALSE,
     97                              TRUE,
     98                              FALSE,
     99                              (UINT32) SpiAddress,
    100                              0,
    101                              NULL,
    102                              EnumSpiRegionBios
    103                              );
    104     if (EFI_ERROR (Status)) {
    105       break;
    106     }
    107     SpiAddress += SectorSize;
    108     NumBytes   -= SectorSize;
    109   }
    110 
    111   return Status;
    112 }
    113 
    114 
    115 static
    116 EFI_STATUS
    117 SpiFlashWrite (
    118   UINT8 *DstBufferPtr,
    119   UINT8 *Byte,
    120   IN  UINTN Length
    121   )
    122 {
    123   EFI_STATUS                Status;
    124   UINT32                    NumBytes = (UINT32)Length;
    125   UINT8*                    pBuf8 = Byte;
    126   UINT32                    SpiAddress;
    127 
    128   SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase;
    129   Status = mSpiProtocol->Execute (
    130                            mSpiProtocol,
    131                            SPI_PROG,
    132                            SPI_WREN,
    133                            TRUE,
    134                            TRUE,
    135                            TRUE,
    136                            (UINT32)SpiAddress,
    137                            NumBytes,
    138                            pBuf8,
    139                            EnumSpiRegionBios
    140                            );
    141   return Status;
    142 }
    143 
    144 /**
    145   Read the Serial Flash Status Registers.
    146 
    147   @param  SpiStatus         Pointer to a caller-allocated UINT8. On successful return, it contains the
    148                             status data read from the Serial Flash Status Register.
    149 
    150 
    151   @retval EFI_SUCCESS       Operation success, status is returned in SpiStatus.
    152   @retval EFI_DEVICE_ERROR  The block device is not functioning correctly and the operation failed.
    153 
    154 **/
    155 EFI_STATUS
    156 ReadStatusRegister (
    157   UINT8   *SpiStatus
    158   )
    159 {
    160   EFI_STATUS          Status;
    161 
    162   Status = mSpiProtocol->Execute (
    163              mSpiProtocol,
    164              SPI_RDSR,
    165              SPI_WREN,
    166              TRUE,
    167              FALSE,
    168              FALSE,
    169              0,
    170              1,
    171              SpiStatus,
    172              EnumSpiRegionBios
    173              );
    174   return Status;
    175 }
    176 
    177 EFI_STATUS
    178 SpiFlashLock (
    179     IN  UINT8  *BaseAddress,
    180     IN  UINTN  NumBytes,
    181     IN  BOOLEAN  Lock
    182   )
    183 {
    184   EFI_STATUS          Status;
    185   UINT8               SpiData;
    186   UINT8               SpiStatus;
    187 
    188   if (Lock) {
    189     SpiData = SF_SR_WPE;
    190   } else {
    191     SpiData = 0;
    192   }
    193 
    194   //
    195   // Always disable block protection to workaround tool issue.
    196   // Feature may be re-enabled in a future bios.
    197   //
    198   SpiData = 0;
    199   Status = mSpiProtocol->Execute (
    200                            mSpiProtocol,
    201                            SPI_WRSR,
    202                            SPI_EWSR,
    203                            TRUE,
    204                            TRUE,
    205                            TRUE,
    206                            0,
    207                            1,
    208                            &SpiData,
    209                            EnumSpiRegionBios
    210                            );
    211   if (EFI_ERROR (Status)) {
    212     return Status;
    213   }
    214 
    215   Status = ReadStatusRegister (&SpiStatus);
    216   if (EFI_ERROR (Status)) {
    217     return Status;
    218   }
    219 
    220   if ((SpiStatus & SpiData) != SpiData) {
    221     Status = EFI_DEVICE_ERROR;
    222   }
    223 
    224   return Status;
    225 }
    226 
    227 
    228 /**
    229   Read NumBytes bytes of data from the address specified by
    230   PAddress into Buffer.
    231 
    232   @param[in]      PAddress          The starting physical address of the read.
    233   @param[in,out]  NumBytes          On input, the number of bytes to read. On output, the number
    234                                     of bytes actually read.
    235   @param[out]     Buffer            The destination data buffer for the read.
    236 
    237   @retval         EFI_SUCCESS.      Opertion is successful.
    238   @retval         EFI_DEVICE_ERROR  If there is any device errors.
    239 
    240 **/
    241 EFI_STATUS
    242 EFIAPI
    243 LibFvbFlashDeviceRead (
    244   IN      UINTN                           PAddress,
    245   IN  OUT UINTN                           *NumBytes,
    246       OUT UINT8                           *Buffer
    247   )
    248 {
    249   CopyMem(Buffer, (VOID*)PAddress, *NumBytes);
    250   return EFI_SUCCESS;
    251 }
    252 
    253 
    254 /**
    255   Write NumBytes bytes of data from Buffer to the address specified by
    256   PAddresss.
    257 
    258   @param[in]      PAddress          The starting physical address of the write.
    259   @param[in,out]  NumBytes          On input, the number of bytes to write. On output,
    260                                     the actual number of bytes written.
    261   @param[in]      Buffer            The source data buffer for the write.
    262 
    263   @retval         EFI_SUCCESS.      Opertion is successful.
    264   @retval         EFI_DEVICE_ERROR  If there is any device errors.
    265 
    266 **/
    267 EFI_STATUS
    268 EFIAPI
    269 LibFvbFlashDeviceWrite (
    270   IN        UINTN                           PAddress,
    271   IN OUT    UINTN                           *NumBytes,
    272   IN        UINT8                           *Buffer
    273   )
    274 {
    275 EFI_STATUS Status;
    276   Status =  SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes);
    277  return Status;
    278 }
    279 
    280 
    281 /**
    282   Erase the block staring at PAddress.
    283 
    284   @param[in]  PAddress          The starting physical address of the block to be erased.
    285                                 This library assume that caller garantee that the PAddress
    286                                 is at the starting address of this block.
    287   @param[in]  LbaLength         The length of the logical block to be erased.
    288 
    289   @retval     EFI_SUCCESS.      Opertion is successful.
    290   @retval     EFI_DEVICE_ERROR  If there is any device errors.
    291 
    292 **/
    293 EFI_STATUS
    294 EFIAPI
    295 LibFvbFlashDeviceBlockErase (
    296   IN    UINTN                     PAddress,
    297   IN    UINTN                     LbaLength
    298   )
    299 {
    300   EFI_STATUS Status;
    301   Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength);
    302 
    303   return Status;
    304 }
    305 
    306 
    307 /**
    308   Lock or unlock the block staring at PAddress.
    309 
    310   @param[in]  PAddress        The starting physical address of region to be (un)locked.
    311   @param[in]  LbaLength       The length of the logical block to be erased.
    312   @param[in]  Lock            TRUE to lock. FALSE to unlock.
    313 
    314   @retval     EFI_SUCCESS.      Opertion is successful.
    315   @retval     EFI_DEVICE_ERROR  If there is any device errors.
    316 
    317 **/
    318 EFI_STATUS
    319 EFIAPI
    320 LibFvbFlashDeviceBlockLock (
    321   IN    UINTN                          PAddress,
    322   IN    UINTN                          LbaLength,
    323   IN    BOOLEAN                        Lock
    324   )
    325 {
    326   EFI_STATUS Status;
    327 
    328     Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock);
    329   return Status;
    330 }
    331 
    332 VOID
    333 EFIAPI
    334 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent (
    335   IN EFI_EVENT        Event,
    336   IN VOID             *Context
    337   )
    338 {
    339   gRT->ConvertPointer (0, (VOID **) &mSpiProtocol);
    340   gRT->ConvertPointer (0, (VOID **) &FlashDeviceBase);
    341 }
    342 
    343 
    344 /**
    345   The library constructuor.
    346 
    347   The function does the necessary initialization work for this library
    348   instance. Please put all initialization works in it.
    349 
    350   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
    351   @param[in]  SystemTable       A pointer to the EFI system table.
    352 
    353   @retval     EFI_SUCCESS       The function always return EFI_SUCCESS for now.
    354                                 It will ASSERT on error for debug version.
    355   @retval     EFI_ERROR         Please reference LocateProtocol for error code details.
    356 
    357 **/
    358 EFI_STATUS
    359 EFIAPI
    360 LibFvbFlashDeviceSupportInit (
    361   IN EFI_HANDLE         ImageHandle,
    362   IN EFI_SYSTEM_TABLE   *SystemTable
    363   )
    364 {
    365   EFI_STATUS Status;
    366   EFI_EVENT  Event;
    367   UINT8                         SfId[3];
    368   UINT8                         FlashIndex;
    369   UINT8                         SpiReadError;
    370   UINT8                         SpiNotMatchError;
    371   EFI_SMM_BASE2_PROTOCOL       *SmmBase;
    372   BOOLEAN                       InSmm;
    373 
    374   SpiReadError     = 0x00;
    375   SpiNotMatchError = 0x00;
    376 
    377   InSmm = FALSE;
    378   Status = gBS->LocateProtocol (
    379                   &gEfiSmmBase2ProtocolGuid,
    380                   NULL,
    381                   (void **)&SmmBase
    382                   );
    383   if (!EFI_ERROR(Status)) {
    384     Status = SmmBase->InSmm(SmmBase, &InSmm);
    385     if (EFI_ERROR(Status)) {
    386       InSmm = FALSE;
    387     }
    388   }
    389 
    390   if (!InSmm) {
    391     Status = gBS->LocateProtocol (
    392                   &gEfiSpiProtocolGuid,
    393                   NULL,
    394                   (VOID **)&mSpiProtocol
    395                   );
    396     ASSERT_EFI_ERROR (Status);
    397 
    398     Status = gBS->CreateEventEx (
    399                   EVT_NOTIFY_SIGNAL,
    400                   TPL_NOTIFY,
    401                   LibFvbFlashDeviceVirtualAddressChangeNotifyEvent,
    402                   NULL,
    403                   &gEfiEventVirtualAddressChangeGuid,
    404                   &Event
    405                   );
    406     ASSERT_EFI_ERROR (Status);
    407   } else {
    408     Status = gBS->LocateProtocol (
    409                     &gEfiSmmSpiProtocolGuid,
    410                     NULL,
    411                     (VOID **)&mSpiProtocol
    412                     );
    413     ASSERT_EFI_ERROR (Status);
    414   }
    415 
    416 
    417   for (FlashIndex = EnumSpiFlashW25Q64; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
    418     Status = mSpiProtocol->Init (mSpiProtocol, &(mInitTable[FlashIndex]));
    419     if (!EFI_ERROR (Status)) {
    420       //
    421       // Read Vendor/Device IDs to check if the driver supports the Serial Flash device.
    422       //
    423       Status = mSpiProtocol->Execute (
    424                                mSpiProtocol,
    425                                SPI_READ_ID,
    426                                SPI_WREN,
    427                                TRUE,
    428                                FALSE,
    429                                FALSE,
    430                                0,
    431                                3,
    432                                SfId,
    433                                EnumSpiRegionAll
    434                                );
    435       if (!EFI_ERROR (Status)) {
    436         if ((SfId[0] == mInitTable[FlashIndex].VendorId)  &&
    437             (SfId[1] == mInitTable[FlashIndex].DeviceId0) &&
    438             (SfId[2] == mInitTable[FlashIndex].DeviceId1)) {
    439             //
    440             // Found a matching SPI device, FlashIndex now contains flash device.
    441             //
    442             DEBUG ((EFI_D_ERROR, "OK - Found SPI Flash Type in SPI Flash Driver, Device Type ID 0 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId0));
    443             DEBUG ((EFI_D_ERROR, "Device Type ID 1 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId1));
    444 
    445             if (mInitTable[FlashIndex].BiosStartOffset == (UINTN) (-1)) {
    446               DEBUG ((EFI_D_ERROR, "ERROR - The size of BIOS image is bigger than SPI Flash device!\n"));
    447               CpuDeadLoop ();
    448             }
    449             break;
    450         } else {
    451           SpiNotMatchError++;
    452         }
    453       } else {
    454         SpiReadError++;
    455       }
    456     }
    457   }
    458 
    459   DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
    460 
    461   if (FlashIndex < EnumSpiFlashMax)  {
    462     return EFI_SUCCESS;
    463   } else {
    464   if (SpiReadError != 0) {
    465       DEBUG ((EFI_D_ERROR, "ERROR - SPI Read ID execution failed! Error Count = %d\n", SpiReadError));
    466    }
    467     else {
    468       if (SpiNotMatchError != 0) {
    469         DEBUG ((EFI_D_ERROR, "ERROR - No supported SPI flash chip found! Error Count = %d\n", SpiNotMatchError));
    470         DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
    471       }
    472     }
    473     return EFI_UNSUPPORTED;
    474   }
    475 }
    476 
    477