]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Vlv2TbltDevicePkg/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
Vlv2TbltDevicePkg/PlatformFlashAccessLib: Add error return
[mirror_edk2.git] / Vlv2TbltDevicePkg / Feature / Capsule / Library / PlatformFlashAccessLib / PlatformFlashAccessLib.c
index efa1dca66e98455b25a0754467fb7c5ff385dc61..079c3ef2d68e975227bc472c03acc7c8b77cce2d 100644 (file)
@@ -1,16 +1,11 @@
 /** @file\r
   Platform Flash Access library.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
+#include <Uefi.h>\r
 \r
 #include <PiDxe.h>\r
 \r
 #include <Library/DebugLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/PlatformFlashAccessLib.h>\r
-#include <Library/FlashDeviceLib.h>\r
+//#include <Library/FlashDeviceLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Protocol/Spi.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include "PchAccess.h"\r
+#include <Library/IoLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+//#define SECTOR_SIZE_64KB  0x10000      // Common 64kBytes sector size\r
+//#define ALINGED_SIZE  SECTOR_SIZE_64KB\r
+\r
+#define BLOCK_SIZE 0x1000\r
+#define ALINGED_SIZE BLOCK_SIZE\r
 \r
-#define SECTOR_SIZE_64KB  0x10000      // Common 64kBytes sector size\r
-#define ALINGED_SIZE  SECTOR_SIZE_64KB\r
+#define R_PCH_LPC_BIOS_CNTL                       0xDC\r
+#define B_PCH_LPC_BIOS_CNTL_SMM_BWP               0x20            ///< SMM BIOS write protect disable\r
+\r
+//\r
+// Prefix Opcode Index on the host SPI controller\r
+//\r
+typedef enum {\r
+  SPI_WREN,             // Prefix Opcode 0: Write Enable\r
+  SPI_EWSR,             // Prefix Opcode 1: Enable Write Status Register\r
+} PREFIX_OPCODE_INDEX;\r
+//\r
+// Opcode Menu Index on the host SPI controller\r
+//\r
+typedef enum {\r
+  SPI_READ_ID,        // Opcode 0: READ ID, Read cycle with address\r
+  SPI_READ,           // Opcode 1: READ, Read cycle with address\r
+  SPI_RDSR,           // Opcode 2: Read Status Register, No address\r
+  SPI_WRDI_SFDP,      // Opcode 3: Write Disable or Discovery Parameters, No address\r
+  SPI_SERASE,         // Opcode 4: Sector Erase (4KB), Write cycle with address\r
+  SPI_BERASE,         // Opcode 5: Block Erase (32KB), Write cycle with address\r
+  SPI_PROG,           // Opcode 6: Byte Program, Write cycle with address\r
+  SPI_WRSR,           // Opcode 7: Write Status Register, No address\r
+} SPI_OPCODE_INDEX;\r
 \r
 STATIC EFI_PHYSICAL_ADDRESS     mInternalFdAddress;\r
 \r
+EFI_SPI_PROTOCOL  *mSpiProtocol;\r
+\r
+/**\r
+  Read NumBytes bytes of data from the address specified by\r
+  PAddress into Buffer.\r
+\r
+  @param[in]      Address       The starting physical address of the read.\r
+  @param[in,out]  NumBytes      On input, the number of bytes to read. On output, the number\r
+                                of bytes actually read.\r
+  @param[out]     Buffer        The destination data buffer for the read.\r
+\r
+  @retval         EFI_SUCCESS       Opertion is successful.\r
+  @retval         EFI_DEVICE_ERROR  If there is any device errors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SpiFlashRead (\r
+  IN     UINTN     Address,\r
+  IN OUT UINT32    *NumBytes,\r
+     OUT UINT8     *Buffer\r
+  )\r
+{\r
+  EFI_STATUS    Status = EFI_SUCCESS;\r
+  UINTN         Offset = 0;\r
+\r
+  ASSERT ((NumBytes != NULL) && (Buffer != NULL));\r
+\r
+\r
+  //if (Address >= (UINTN)PcdGet32 (PcdGbeRomBase) && Address < (UINTN)PcdGet32 (PcdPDRRomBase)) {\r
+    Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);\r
+\r
+    Status = mSpiProtocol->Execute (\r
+                               mSpiProtocol,\r
+                               1, //SPI_READ,\r
+                               0, //SPI_WREN,\r
+                               TRUE,\r
+                               TRUE,\r
+                               FALSE,\r
+                               Offset,\r
+                               BLOCK_SIZE,\r
+                               Buffer,\r
+                               EnumSpiRegionAll\r
+                               );\r
+    return Status;\r
+}\r
+\r
+/**\r
+  Write NumBytes bytes of data from Buffer to the address specified by\r
+  PAddresss.\r
+\r
+  @param[in]      Address         The starting physical address of the write.\r
+  @param[in,out]  NumBytes        On input, the number of bytes to write. On output,\r
+                                  the actual number of bytes written.\r
+  @param[in]      Buffer          The source data buffer for the write.\r
+\r
+  @retval         EFI_SUCCESS       Opertion is successful.\r
+  @retval         EFI_DEVICE_ERROR  If there is any device errors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SpiFlashWrite (\r
+  IN     UINTN     Address,\r
+  IN OUT UINT32    *NumBytes,\r
+  IN     UINT8     *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Offset;\r
+  UINT32                    Length;\r
+  UINT32                    RemainingBytes;\r
+\r
+  ASSERT ((NumBytes != NULL) && (Buffer != NULL));\r
+  ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));\r
+\r
+  Offset    = Address - (UINTN)PcdGet32 (PcdFlashChipBase);\r
+\r
+  ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));\r
+\r
+  Status = EFI_SUCCESS;\r
+  RemainingBytes = *NumBytes;\r
+\r
+  while (RemainingBytes > 0) {\r
+    if (RemainingBytes > SIZE_4KB) {\r
+      Length = SIZE_4KB;\r
+    } else {\r
+      Length = RemainingBytes;\r
+    }\r
+    Status = mSpiProtocol->Execute (\r
+                             mSpiProtocol,\r
+                             SPI_PROG,\r
+                             SPI_WREN,\r
+                             TRUE,\r
+                             TRUE,\r
+                             TRUE,\r
+                             (UINT32) Offset,\r
+                             Length,\r
+                             Buffer,\r
+                             EnumSpiRegionAll\r
+                             );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    RemainingBytes -= Length;\r
+    Offset += Length;\r
+    Buffer += Length;\r
+  }\r
+\r
+  //\r
+  // Actual number of bytes written\r
+  //\r
+  *NumBytes -= RemainingBytes;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+InternalReadBlock (\r
+  IN  EFI_PHYSICAL_ADDRESS  BaseAddress,\r
+  OUT VOID                  *ReadBuffer\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINT32        BlockSize;\r
+\r
+  BlockSize = BLOCK_SIZE;\r
+\r
+  Status = SpiFlashRead ((UINTN) BaseAddress, &BlockSize, ReadBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Erase the block starting at Address.\r
+\r
+  @param[in]  Address         The starting physical address of the block to be erased.\r
+                              This library assume that caller garantee that the PAddress\r
+                              is at the starting address of this block.\r
+  @param[in]  NumBytes        On input, the number of bytes of the logical block to be erased.\r
+                              On output, the actual number of bytes erased.\r
+\r
+  @retval     EFI_SUCCESS.      Opertion is successful.\r
+  @retval     EFI_DEVICE_ERROR  If there is any device errors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SpiFlashBlockErase (\r
+  IN UINTN    Address,\r
+  IN UINTN    *NumBytes\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINTN               Offset;\r
+  UINTN               RemainingBytes;\r
+\r
+  ASSERT (NumBytes != NULL);\r
+  ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));\r
+\r
+  Offset    = Address - (UINTN)PcdGet32 (PcdFlashChipBase);\r
+\r
+  ASSERT ((*NumBytes % SIZE_4KB) == 0);\r
+  ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));\r
+\r
+  Status = EFI_SUCCESS;\r
+  RemainingBytes = *NumBytes;\r
+\r
+  //\r
+  // To adjust the Offset with Bios/Gbe\r
+  //\r
+//  if (Address >= (UINTN)PcdGet32 (PcdFlashChipBase)) {\r
+//    Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);\r
+\r
+    while (RemainingBytes > 0) {\r
+      Status = mSpiProtocol->Execute (\r
+                               mSpiProtocol,\r
+                               SPI_SERASE,\r
+                               SPI_WREN,\r
+                               FALSE,\r
+                               TRUE,\r
+                               FALSE,\r
+                               (UINT32) Offset,\r
+                               0,\r
+                               NULL,\r
+                               EnumSpiRegionAll\r
+                               );\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      RemainingBytes -= SIZE_4KB;\r
+      Offset         += SIZE_4KB;\r
+    }\r
+//  }\r
+\r
+  //\r
+  // Actual number of bytes erased\r
+  //\r
+  *NumBytes -= RemainingBytes;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+Routine Description:\r
+\r
+  Erase the whole block.\r
+\r
+Arguments:\r
+\r
+  BaseAddress  - Base address of the block to be erased.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - The command completed successfully.\r
+  Other       - Device error or wirte-locked, operation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalEraseBlock (\r
+  IN  EFI_PHYSICAL_ADDRESS BaseAddress\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   NumBytes;\r
+\r
+  NumBytes = BLOCK_SIZE;\r
+\r
+  Status = SpiFlashBlockErase ((UINTN) BaseAddress, &NumBytes);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+InternalCompareBlock (\r
+  IN  EFI_PHYSICAL_ADDRESS        BaseAddress,\r
+  IN  UINT8                       *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  VOID                                    *CompareBuffer;\r
+  UINT32                                  NumBytes;\r
+  INTN                                    CompareResult;\r
+\r
+  NumBytes = BLOCK_SIZE;\r
+  CompareBuffer = AllocatePool (NumBytes);\r
+  if (CompareBuffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  Status = SpiFlashRead ((UINTN) BaseAddress, &NumBytes, CompareBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  CompareResult = CompareMem (CompareBuffer, Buffer, BLOCK_SIZE);\r
+  if (CompareResult != 0) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+Done:\r
+  if (CompareBuffer != NULL) {\r
+    FreePool (CompareBuffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+Routine Description:\r
+\r
+  Write a block of data.\r
+\r
+Arguments:\r
+\r
+  BaseAddress  - Base address of the block.\r
+  Buffer       - Data buffer.\r
+  BufferSize   - Size of the buffer.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The command completed successfully.\r
+  EFI_INVALID_PARAMETER - Invalid parameter, can not proceed.\r
+  Other                 - Device error or wirte-locked, operation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalWriteBlock (\r
+  IN  EFI_PHYSICAL_ADDRESS        BaseAddress,\r
+  IN  UINT8                       *Buffer,\r
+  IN  UINT32                      BufferSize\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  Status = SpiFlashWrite ((UINTN) BaseAddress, &BufferSize, Buffer);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((DEBUG_ERROR, "\nFlash write error."));\r
+    return Status;\r
+  }\r
+\r
+  WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, BLOCK_SIZE);\r
+\r
+  Status = InternalCompareBlock (BaseAddress, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((DEBUG_ERROR, "\nError when writing to BaseAddress %x with different at offset %x.", BaseAddress, Status));\r
+  } else {\r
+    DEBUG((DEBUG_INFO, "\nVerified data written to Block at %x is correct.", BaseAddress));\r
+  }\r
+\r
+  return Status;\r
+\r
+}\r
+\r
 /**\r
-  Perform flash write opreation.\r
+  Perform flash write operation with progress indicator.  The start and end\r
+  completion percentage values are passed into this function.  If the requested\r
+  flash write operation is broken up, then completion percentage between the\r
+  start and end values may be passed to the provided Progress function.  The\r
+  caller of this function is required to call the Progress function for the\r
+  start and end completion percentage values.  This allows the Progress,\r
+  StartPercentage, and EndPercentage parameters to be ignored if the requested\r
+  flash write operation can not be broken up\r
 \r
   @param[in] FirmwareType      The type of firmware.\r
   @param[in] FlashAddress      The address of flash device to be accessed.\r
   @param[in] FlashAddressType  The type of flash device address.\r
   @param[in] Buffer            The pointer to the data buffer.\r
   @param[in] Length            The length of data buffer in bytes.\r
+  @param[in] Progress          A function used report the progress of the\r
+                               firmware update.  This is an optional parameter\r
+                               that may be NULL.\r
+  @param[in] StartPercentage   The start completion percentage value that may\r
+                               be used to report progress during the flash\r
+                               write operation.\r
+  @param[in] EndPercentage     The end completion percentage value that may\r
+                               be used to report progress during the flash\r
+                               write operation.\r
 \r
   @retval EFI_SUCCESS           The operation returns successfully.\r
   @retval EFI_WRITE_PROTECTED   The flash device is read only.\r
@@ -43,50 +406,174 @@ STATIC EFI_PHYSICAL_ADDRESS     mInternalFdAddress;
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-PerformFlashWrite (\r
-  IN PLATFORM_FIRMWARE_TYPE       FirmwareType,\r
-  IN EFI_PHYSICAL_ADDRESS         FlashAddress,\r
-  IN FLASH_ADDRESS_TYPE           FlashAddressType,\r
-  IN VOID                         *Buffer,\r
-  IN UINTN                        Length\r
+PerformFlashWriteWithProgress (\r
+  IN PLATFORM_FIRMWARE_TYPE                         FirmwareType,\r
+  IN EFI_PHYSICAL_ADDRESS                           FlashAddress,\r
+  IN FLASH_ADDRESS_TYPE                             FlashAddressType,\r
+  IN VOID                                           *Buffer,\r
+  IN UINTN                                          Length,\r
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,        OPTIONAL\r
+  IN UINTN                                          StartPercentage,\r
+  IN UINTN                                          EndPercentage\r
   )\r
 {\r
-  EFI_STATUS          Status;\r
+  EFI_STATUS            Status = EFI_SUCCESS;\r
+  UINTN               Index;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  UINTN                 CountOfBlocks;\r
+  EFI_TPL               OldTpl;\r
+  BOOLEAN               FlashError;\r
+  UINT8                 *Buf;\r
+  UINTN                 LpcBaseAddress;\r
+  UINT8                 Data8Or;\r
+  UINT8                 Data8And;\r
+  UINT8                 BiosCntl;\r
+\r
+  Index             = 0;\r
+  Address           = 0;\r
+  CountOfBlocks     = 0;\r
+  FlashError        = FALSE;\r
+  Buf               = Buffer;\r
 \r
-  DEBUG((DEBUG_INFO, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));\r
+  DEBUG((DEBUG_INFO | DEBUG_ERROR, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));\r
   if (FlashAddressType == FlashAddressTypeRelativeAddress) {\r
     FlashAddress = FlashAddress + mInternalFdAddress;\r
   }\r
 \r
-  DEBUG((DEBUG_INFO, "                  - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));\r
-  LibFvbFlashDeviceBlockLock(FlashAddress, Length, FALSE);\r
+  CountOfBlocks = (UINTN) (Length / BLOCK_SIZE);\r
+  Address = FlashAddress;\r
 \r
-  //\r
-  // Erase & Write\r
-  //\r
-  Status = LibFvbFlashDeviceBlockErase((UINTN)FlashAddress, Length);\r
-  ASSERT_EFI_ERROR(Status);\r
-  if (EFI_ERROR(Status)) {\r
-    LibFvbFlashDeviceBlockLock(FlashAddress, Length, TRUE);\r
-    DEBUG((DEBUG_ERROR, "Flash Erase error\n"));\r
-    return Status;\r
+  LpcBaseAddress = MmPciAddress (0,\r
+                    DEFAULT_PCI_BUS_NUMBER_PCH,\r
+                    PCI_DEVICE_NUMBER_PCH_LPC,\r
+                    PCI_FUNCTION_NUMBER_PCH_LPC,\r
+                    0\r
+                    );\r
+  BiosCntl = MmioRead8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL);\r
+  if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {\r
+    ///\r
+    /// Clear SMM_BWP bit (D31:F0:RegDCh[5])\r
+    ///\r
+    Data8And  = (UINT8) ~B_PCH_LPC_BIOS_CNTL_SMM_BWP;\r
+    Data8Or   = 0x00;\r
+\r
+    MmioAndThenOr8 (\r
+      LpcBaseAddress + R_PCH_LPC_BIOS_CNTL,\r
+      Data8And,\r
+      Data8Or\r
+      );\r
+    DEBUG((DEBUG_INFO, "PerformFlashWrite Clear SMM_BWP bit\n"));\r
   }\r
 \r
-  Status = LibFvbFlashDeviceWrite((UINTN)FlashAddress, &Length, Buffer);\r
-  ASSERT_EFI_ERROR(Status);\r
-  if (EFI_ERROR(Status)) {\r
-    LibFvbFlashDeviceBlockLock(FlashAddress, Length, TRUE);\r
-    DEBUG((DEBUG_ERROR, "Flash write error\n"));\r
-    return Status;\r
+    //\r
+    // Raise TPL to TPL_NOTIFY to block any event handler,\r
+    // while still allowing RaiseTPL(TPL_NOTIFY) within\r
+    // output driver during Print()\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    for (Index = 0; Index < CountOfBlocks; Index++) {\r
+      if (Progress != NULL) {\r
+        Progress (StartPercentage + ((Index * (EndPercentage - StartPercentage)) / CountOfBlocks));\r
+      }\r
+      //\r
+      // Handle block based on address and contents.\r
+      //\r
+      if (!EFI_ERROR (InternalCompareBlock (Address, Buf))) {\r
+        DEBUG((DEBUG_INFO, "Skipping block at 0x%lx (already programmed)\n", Address));\r
+      } else {\r
+        //\r
+        // Make updating process uninterruptable,\r
+        // so that the flash memory area is not accessed by other entities\r
+        // which may interfere with the updating process\r
+        //\r
+        Status  = InternalEraseBlock (Address);\r
+        if (EFI_ERROR(Status)) {\r
+          gBS->RestoreTPL (OldTpl);\r
+          FlashError = TRUE;\r
+          goto Done;\r
+        }\r
+        Status = InternalWriteBlock (\r
+                  Address,\r
+                  Buf,\r
+                  (UINT32)(Length > BLOCK_SIZE ? BLOCK_SIZE : Length)\r
+                  );\r
+        if (EFI_ERROR(Status)) {\r
+          gBS->RestoreTPL (OldTpl);\r
+          FlashError = TRUE;\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Move to next block to update.\r
+      //\r
+      Address += BLOCK_SIZE;\r
+      Buf += BLOCK_SIZE;\r
+      if (Length > BLOCK_SIZE) {\r
+        Length -= BLOCK_SIZE;\r
+      } else {\r
+        Length = 0;\r
+      }\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
+Done:\r
+  if ((BiosCntl & B_PCH_LPC_BIOS_CNTL_SMM_BWP) == B_PCH_LPC_BIOS_CNTL_SMM_BWP) {\r
+    //\r
+    // Restore original control setting\r
+    //\r
+    MmioWrite8 (LpcBaseAddress + R_PCH_LPC_BIOS_CNTL, BiosCntl);\r
+  }\r
+\r
+  if (Progress != NULL) {\r
+    Progress (EndPercentage);\r
   }\r
 \r
-  LibFvbFlashDeviceBlockLock(FlashAddress, Length, TRUE);\r
+  if (FlashError) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Perform microcode write opreation.\r
+  Perform flash write operation.\r
+\r
+  @param[in] FirmwareType      The type of firmware.\r
+  @param[in] FlashAddress      The address of flash device to be accessed.\r
+  @param[in] FlashAddressType  The type of flash device address.\r
+  @param[in] Buffer            The pointer to the data buffer.\r
+  @param[in] Length            The length of data buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS           The operation returns successfully.\r
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.\r
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.\r
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PerformFlashWrite (\r
+  IN PLATFORM_FIRMWARE_TYPE       FirmwareType,\r
+  IN EFI_PHYSICAL_ADDRESS         FlashAddress,\r
+  IN FLASH_ADDRESS_TYPE           FlashAddressType,\r
+  IN VOID                         *Buffer,\r
+  IN UINTN                        Length\r
+  )\r
+{\r
+  return PerformFlashWriteWithProgress (\r
+           FirmwareType,\r
+           FlashAddress,\r
+           FlashAddressType,\r
+           Buffer,\r
+           Length,\r
+           NULL,\r
+           0,\r
+           0\r
+           );\r
+}\r
+\r
+/**\r
+  Perform microcode write operation.\r
 \r
   @param[in] FlashAddress      The address of flash device to be accessed.\r
   @param[in] Buffer            The pointer to the data buffer.\r
@@ -146,10 +633,10 @@ MicrocodeFlashWrite (
     // Save original buffer\r
     //\r
     if (OffsetHead != 0) {\r
-      CopyMem((UINT8 *)AlignedBuffer, (VOID *)AlignedFlashAddress, OffsetHead);\r
+      CopyMem((UINT8 *)AlignedBuffer, (VOID *)(UINTN)AlignedFlashAddress, OffsetHead);\r
     }\r
     if (OffsetTail != 0) {\r
-      CopyMem((UINT8 *)AlignedBuffer + OffsetHead + Length, (VOID *)(AlignedFlashAddress + OffsetHead + Length), OffsetTail);\r
+      CopyMem((UINT8 *)AlignedBuffer + OffsetHead + Length, (VOID *)(UINTN)(AlignedFlashAddress + OffsetHead + Length), OffsetTail);\r
     }\r
     //\r
     // Override new buffer\r
@@ -183,8 +670,16 @@ PerformFlashAccessLibConstructor (
   VOID\r
   )\r
 {\r
+  EFI_STATUS Status;\r
   mInternalFdAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32(PcdFlashAreaBaseAddress);\r
   DEBUG((DEBUG_INFO, "PcdFlashAreaBaseAddress - 0x%x\n", mInternalFdAddress));\r
 \r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiSpiProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mSpiProtocol\r
+                  );\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
   return EFI_SUCCESS;\r
 }\r