From 99ef2418b47723a2a38a69121b91fd16cafdfdb6 Mon Sep 17 00:00:00 2001 From: zwei4 Date: Mon, 13 Feb 2017 11:08:20 +0800 Subject: Add FirmwareUpdate application Add FirmwareUpdate application for Minnnowboard 3, which is for updating 8MB SPI NOR flash. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: zwei4 --- .../Application/FirmwareUpdate/FirmwareUpdate.c | 927 +++++++++++++++++++++ .../Application/FirmwareUpdate/FirmwareUpdate.h | 190 +++++ .../Application/FirmwareUpdate/FirmwareUpdate.inf | 83 ++ .../FirmwareUpdate/FirmwareUpdateStrings.uni | Bin 0 -> 7480 bytes 4 files changed, 1200 insertions(+) create mode 100644 Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c create mode 100644 Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.h create mode 100644 Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.inf create mode 100644 Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdateStrings.uni (limited to 'Platform') diff --git a/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c new file mode 100644 index 0000000000..b374b983db --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c @@ -0,0 +1,927 @@ +/** @file + +Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that 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 "FirmwareUpdate.h" + +EFI_HII_HANDLE HiiHandle; + + +/* + +MinnowBoard 3 Flash Layout + +Start (hex) End (hex) Length (hex) Area Name +----------- --------- ------------ --------- + +00000000 007FFFFF 00800000 Full Flash Image +00000014 00000017 00000004 FLMAP0 - Flash Map 0 Register +00000018 0000001B 00000004 FLMAP1 - Flash Map 1 Register +0000001C 0000001F 00000004 FLMAP2 - Flash Map 2 Register +00000030 0000003B 0000000C FCBA - Flash Component Registers +00000040 00000043 00000004 FLREG0 - Flash Region 0 (Flash Descriptor) Register +00000044 00000047 00000004 FLREG1 - Flash Region 1 (IFWI) Register +00000048 0000004B 00000004 FLREG2 - Flash Region 2 (Intel(R) TXE) Register +00000050 00000053 00000004 FLREG4 - Flash Region 4 (Platform Data) Register +00000054 00000057 00000004 FLREG5 - Flash Region 5 (Device Expansion) Register +00000060 00000063 00000004 FLREG8 - Flash Region 8 (Embedded Controller) Register +00000080 00000083 00000004 FLMSTR1 - Flash Master 1 (Host CPU/BIOS) +00000084 00000087 00000004 FLMSTR2 - Flash Master 2 (Intel(R) TXE) +00000100 000002FF 00000200 FPSBA - SoC Straps (Including Padding) +000003EC 0000046B 00000080 FPSBA - SoC Straps (Including Padding) +00000DF0 00000EFF 00000110 VSCC Table +00000DF0 00000DF7 00000008 VsccEntry0 +00001000 00241FFF 00241000 Boot Partition 1 +00001000 000F9FFF 000F9000 Primary Boot Partition +00001200 0000120F 00000010 IFP Overrides Partition +00001210 00001317 00000108 Unified Emulation Partition (UEP) +00002000 00005FFF 00004000 OEM SMIP Partition +00006000 0000FFFF 0000A000 CSE RBE Partition +00010000 0001FFFF 00010000 PMCP +00020000 0007BFFF 0005C000 CSE BUP Partition +0007C000 0007FFFF 00004000 uCode Partition +00080000 000F7FFF 00078000 IBB Partition +000F8000 000F9FFF 00002000 Debug Token Partition +000FA000 00241FFF 00148000 Secondary Boot Partition +000FB000 0013AFFF 00040000 ISHC Partition +0013B000 0023FFFF 00105000 CSE Main Partition +00240000 00241FFF 00002000 IUnit Partition +00242000 0065BFFF 0041A000 Secondary Boot Partition +00242000 0065BFFF 0041A000 Boot Partition 2 +00381000 0065BFFF 002DB000 OBB Partition +0065C000 006FF000 000A3001 TXE Data Region +*/ + +FV_REGION_INFO mRegionInfo[] = { + {0xFF800000, 0x00001000, TRUE}, + {0xFF801000, 0x0037F000, TRUE}, + {0xFFB80000, 0x0037F000, TRUE}, + {0xFFEFF000, 0x00100000, TRUE}, +}; + +UINTN mRegionInfoCount = sizeof (mRegionInfo) / sizeof (mRegionInfo[0]); + +FV_INPUT_DATA mInputData = {0}; + +SC_SPI_PROTOCOL *mSpiProtocol; + +EFI_STATUS +GetRegionIndex ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT UINTN *RegionIndex + ) +{ + UINTN Index; + + for (Index = 0; Index < mRegionInfoCount; Index++) { + if (Address >= mRegionInfo[Index].Base && + Address < (mRegionInfo[Index].Base + mRegionInfo[Index].Size) + ) { + break; + } + } + + *RegionIndex = Index; + if (Index >= mRegionInfoCount) { + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +BOOLEAN +UpdateBlock ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + EFI_STATUS Status; + UINTN Index; + + if (mInputData.FullFlashUpdate) { + // + // Apollo Lake Workaround: 0xFFFFF000 - 0xFFFFFFFF region (Top 4KB bwlow 4G) could not be access by SPI protocol. + // + if (Address >= 0xFFFFF000) { + return FALSE; + } + + return TRUE; + } + + Status = GetRegionIndex (Address, &Index); + if ((!EFI_ERROR(Status)) && mRegionInfo[Index].Update) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +MarkRegionState ( + IN EFI_PHYSICAL_ADDRESS Address, + IN BOOLEAN Update + ) +{ + EFI_STATUS Status; + UINTN Index; + + Status = GetRegionIndex (Address, &Index); + if (!EFI_ERROR(Status)) { + mRegionInfo[Index].Update = Update; + } + + return Status; +} + +UINTN +InternalPrintToken ( + IN CONST CHAR16 *Format, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console, + IN VA_LIST Marker + ) +{ + EFI_STATUS Status; + UINTN Return; + CHAR16 *Buffer; + UINTN BufferSize; + + ASSERT (Format != NULL); + ASSERT (((UINTN) Format & BIT0) == 0); + ASSERT (Console != NULL); + + BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16); + + Buffer = (CHAR16 *) AllocatePool(BufferSize); + ASSERT (Buffer != NULL); + + Return = UnicodeVSPrint (Buffer, BufferSize, Format, Marker); + + if (Console != NULL && Return > 0) { + // + // To be extra safe make sure Console has been initialized. + // + Status = Console->OutputString (Console, Buffer); + if (EFI_ERROR (Status)) { + Return = 0; + } + } + + FreePool (Buffer); + + return Return; +} + +UINTN +EFIAPI +PrintToken ( + IN UINT16 Token, + IN EFI_HII_HANDLE Handle, + ... + ) +{ + VA_LIST Marker; + UINTN Return; + CHAR16 *Format; + + VA_START (Marker, Handle); + + Format = HiiGetString (Handle, Token, NULL); + ASSERT (Format != NULL); + + Return = InternalPrintToken (Format, gST->ConOut, Marker); + + FreePool (Format); + + VA_END (Marker); + + return Return; +} + +EFI_STATUS +ParseCommandLine ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + EFI_STATUS Status; + UINTN Index; + + // + // Check to make sure that the command line has enough arguments for minimal + // operation. The minimum is just the file name. + // + if (Argc < 2 || Argc > 4) { + return EFI_INVALID_PARAMETER; + } + + // + // Loop through command line arguments. + // + for (Index = 1; Index < Argc; Index++) { + // + // Make sure the string is valid. + // + if (StrLen (Argv[Index]) == 0) {; + PrintToken (STRING_TOKEN (STR_FWUPDATE_ZEROLENGTH_ARG), HiiHandle); + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if this is an option or the file name. + // + if ((Argv[Index])[0] == L'-' || (Argv[Index])[0] == L'/') { + // + // Parse the arguments. + // + if ((StrCmp (Argv[Index], L"-h") == 0) || + (StrCmp (Argv[Index], L"--help") == 0) || + (StrCmp (Argv[Index], L"/?") == 0) || + (StrCmp (Argv[Index], L"/h") == 0)) { + // + // Print Help Information. + // + return EFI_INVALID_PARAMETER; + } else if (StrCmp (Argv[Index], L"-m") == 0) { + // + // Parse the MAC address here. + // + Status = ConvertMac(Argv[Index+1]); + if (EFI_ERROR(Status)) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_INVAILD_MAC), HiiHandle); + return Status; + } + + // + // Save the MAC address to mInputData.MacValue. + // + mInputData.UpdateMac= TRUE; + Index++; + } else { + // + // Invalid option was provided. + // + return EFI_INVALID_PARAMETER; + } + } + if ((Index == Argc - 1) && (StrCmp (Argv[Index - 1], L"-m") != 0)) { + // + // The only parameter that is not an option is the firmware image. Check + // to make sure that the file exists. + // + Status = ShellIsFile (Argv[Index]); + if (EFI_ERROR (Status)) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_FILE_NOT_FOUND_ERROR), HiiHandle, Argv[Index]); + return EFI_INVALID_PARAMETER; + } + if (StrLen (Argv[Index]) > INPUT_STRING_LEN) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_PATH_ERROR), HiiHandle, Argv[Index]); + return EFI_INVALID_PARAMETER; + } + StrCpy (mInputData.FileName, Argv[Index]); + mInputData.UpdateFromFile = TRUE; + } + } + + return EFI_SUCCESS; +} + +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT32 FileSize; + UINT32 BufferSize; + UINT8 *FileBuffer; + UINT8 *Buffer; + EFI_PHYSICAL_ADDRESS Address; + UINTN CountOfBlocks; + EFI_TPL OldTpl; + BOOLEAN ResetRequired; + BOOLEAN FlashError; + + Index = 0; + FileSize = 0; + BufferSize = 0; + FileBuffer = NULL; + Buffer = NULL; + Address = 0; + CountOfBlocks = 0; + ResetRequired = FALSE; + FlashError = FALSE; + + Status = EFI_SUCCESS; + + mInputData.FullFlashUpdate = TRUE; + + // + // Publish our HII data. + // + HiiHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + NULL, + FirmwareUpdateStrings, + NULL + ); + if (HiiHandle == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Locate the SPI protocol. + // + Status = gBS->LocateProtocol ( + &gScSpiProtocolGuid, + NULL, + (VOID **)&mSpiProtocol + ); + if (EFI_ERROR (Status)) { + PrintToken (STRING_TOKEN (STR_SPI_NOT_FOUND), HiiHandle); + return EFI_DEVICE_ERROR; + } + + // + // Parse the command line. + // + Status = ParseCommandLine (Argc, Argv); + if (EFI_ERROR (Status)) { + PrintHelpInfo (); + Status = EFI_SUCCESS; + goto Done; + } + + // + // Display sign-on information. + // + PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle); + + // + // Test to see if the firmware needs to be updated. + // + if (mInputData.UpdateFromFile) { + // + // Get the file to use in the update. + // + PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE), HiiHandle, mInputData.FileName); + Status = ReadFileData (mInputData.FileName, &FileBuffer, &FileSize); + if (EFI_ERROR (Status)) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE_ERROR), HiiHandle, mInputData.FileName); + goto Done; + } + + // + // Check that the file and flash sizes match. + // + if (FileSize != PcdGet32 (PcdFlashAreaSize)) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_SIZE), HiiHandle); + Status = EFI_UNSUPPORTED; + goto Done; + } + + // + // Display flash update information. + // + PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATING_FIRMWARE), HiiHandle); + + // + // Update it. + // + Buffer = FileBuffer; + BufferSize = FileSize; + Address = PcdGet32 (PcdFlashAreaBaseAddress); + CountOfBlocks = (UINTN) (BufferSize / BLOCK_SIZE); + + // + // Raise TPL to TPL_NOTIFY to block any event handler, + // while still allowing RaiseTPL(TPL_NOTIFY) within + // output driver during Print(). + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Index = 0; Index < CountOfBlocks; Index++) { + // + // Handle block based on address and contents. + // + if (!UpdateBlock (Address)) { + DEBUG((EFI_D_INFO, "Skipping block at 0x%lx\n", Address)); + } else if (!EFI_ERROR (InternalCompareBlock (Address, Buffer))) { + DEBUG((EFI_D_INFO, "Skipping block at 0x%lx (already programmed)\n", Address)); + } else { + // + // Display a dot for each block being updated. + // + Print (L"."); + + // + // Flag that the flash image will be changed and the system must be rebooted + // to use the change. + // + ResetRequired = TRUE; + + // + // Make updating process uninterruptable, + // so that the flash memory area is not accessed by other entities + // which may interfere with the updating process. + // + Status = InternalEraseBlock (Address); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + FlashError = TRUE; + goto Done; + } + Status = InternalWriteBlock ( + Address, + Buffer, + (BufferSize > BLOCK_SIZE ? BLOCK_SIZE : BufferSize) + ); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + FlashError = TRUE; + goto Done; + } + } + + // + // Move to next block to update. + // + Address += BLOCK_SIZE; + Buffer += BLOCK_SIZE; + if (BufferSize > BLOCK_SIZE) { + BufferSize -= BLOCK_SIZE; + } else { + BufferSize = 0; + } + } + gBS->RestoreTPL (OldTpl); + + // + // Print result of update. + // + if (!FlashError) { + if (ResetRequired) { + Print (L"\n"); + PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_SUCCESS), HiiHandle); + } else { + PrintToken (STRING_TOKEN (STR_FWUPDATE_NO_RESET), HiiHandle); + } + } else { + goto Done; + } + } + + // + // All flash updates are done so see if the system needs to be reset. + // + if (ResetRequired && !FlashError) { + // + // Update successful. + // + for (Index = 5; Index > 0; Index--) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_SHUTDOWN), HiiHandle, Index); + gBS->Stall (1000000); + } + + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + PrintToken (STRING_TOKEN (STR_FWUPDATE_MANUAL_RESET), HiiHandle); + CpuDeadLoop (); + } + +Done: + // + // Print flash update failure message if error is detected. + // + if (FlashError) { + PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_FAILED), HiiHandle, Index); + } + + // + // Do cleanup. + // + if (HiiHandle != NULL) { + HiiRemovePackages (HiiHandle); + } + if (FileBuffer) { + gBS->FreePool (FileBuffer); + } + + return Status; +} + +/*++ + + Erase the whole block. + + @param[in] BaseAddress Base address of the block to be erased. + + @retval EFI_SUCCESS The command completed successfully. + @retval Other Device error or wirte-locked, operation failed. + +--*/ +STATIC +EFI_STATUS +InternalEraseBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +{ + EFI_STATUS Status; + UINTN NumBytes; + + NumBytes = BLOCK_SIZE; + + Status = SpiFlashBlockErase ((UINTN) BaseAddress, &NumBytes); + + return Status; +} + +STATIC +EFI_STATUS +InternalCompareBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + VOID *CompareBuffer; + UINT32 NumBytes; + INTN CompareResult; + + NumBytes = BLOCK_SIZE; + CompareBuffer = AllocatePool (NumBytes); + if (CompareBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = SpiFlashRead ((UINTN) BaseAddress, &NumBytes, CompareBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + CompareResult = CompareMem (CompareBuffer, Buffer, BLOCK_SIZE); + if (CompareResult != 0) { + Status = EFI_VOLUME_CORRUPTED; + } + +Done: + if (CompareBuffer != NULL) { + FreePool (CompareBuffer); + } + + return Status; +} + +/*++ + Write a block of data. + + @param[in] BaseAddress Base address of the block. + @param[in] Buffer Data buffer. + @param[in] BufferSize Size of the buffer. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter, can not proceed. + @retval Other Device error or wirte-locked, operation failed. + +--*/ +STATIC +EFI_STATUS +InternalWriteBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT8 *Buffer, + IN UINT32 BufferSize + ) +{ + EFI_STATUS Status; + + Status = SpiFlashWrite ((UINTN) BaseAddress, &BufferSize, Buffer); + + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "\nFlash write error.")); + return Status; + } + + //Workaround: WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, BLOCK_SIZE); + + Status = InternalCompareBlock (BaseAddress, Buffer); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "\nError when writing to BaseAddress %lx with different at offset %x.", BaseAddress, Status)); + } else { + DEBUG((EFI_D_INFO, "\nVerified data written to Block at %lx is correct.", BaseAddress)); + } + + return Status; + +} + +STATIC +EFI_STATUS +ReadFileData ( + IN CHAR16 *FileName, + OUT UINT8 **Buffer, + OUT UINT32 *BufferSize + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + UINT64 Size; + VOID *NewBuffer; + UINTN ReadSize; + + FileHandle = NULL; + NewBuffer = NULL; + Size = 0; + + Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = FileHandleIsDirectory (FileHandle); + if (!EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + goto Done; + } + + Status = FileHandleGetSize (FileHandle, &Size); + if (EFI_ERROR (Status)) { + goto Done; + } + + NewBuffer = AllocatePool ((UINTN) Size); + + ReadSize = (UINTN) Size; + Status = FileHandleRead (FileHandle, &ReadSize, NewBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } else if (ReadSize != (UINTN) Size) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + +Done: + if (FileHandle != NULL) { + ShellCloseFile (&FileHandle); + } + + if (EFI_ERROR (Status)) { + if (NewBuffer != NULL) { + FreePool (NewBuffer); + } + } else { + *Buffer = NewBuffer; + *BufferSize = (UINT32) Size; + } + + return Status; +} + +STATIC +VOID +PrintHelpInfo ( + VOID + ) +{ + PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle); + + Print (L"\n"); + PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_1), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_2), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_3), HiiHandle); + PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_4), HiiHandle); + + Print (L"\n"); +} + +/** + Read NumBytes bytes of data from the address specified by + PAddress into Buffer. + + @param[in] Address The starting physical address of the read. + @param[in,out] NumBytes On input, the number of bytes to read. On output, the number + of bytes actually read. + @param[out] Buffer The destination data buffer for the read. + + @retval EFI_SUCCESS Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +SpiFlashRead ( + IN UINTN Address, + IN OUT UINT32 *NumBytes, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 SectorSize; + UINT32 Offset; + UINT8 TempBuffer[SIZE_4KB]; + UINTN Count = 0; + UINT32 Length; + + Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); + SectorSize = SIZE_4KB; + Length = *NumBytes; + + while (Count < Length) { + Status = mSpiProtocol ->FlashRead ( + mSpiProtocol, + FlashRegionAll, + Offset, + SIZE_4KB, + TempBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Read SPI ROM Failed [%08x]\n", Offset)); + break; + } + + CopyMem ((Buffer + Count), (VOID *)TempBuffer, SectorSize); + Offset += SectorSize; + Count += SectorSize; + } + + return Status; + +} + +/** + Write NumBytes bytes of data from Buffer to the address specified by + PAddresss. + + @param[in] Address The starting physical address of the write. + @param[in,out] NumBytes On input, the number of bytes to write. On output, + the actual number of bytes written. + @param[in] Buffer The source data buffer for the write. + + @retval EFI_SUCCESS Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +SpiFlashWrite ( + IN UINTN Address, + IN OUT UINT32 *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINT32 Offset; + UINT32 Length; + UINT32 RemainingBytes; + + ASSERT ((NumBytes != NULL) && (Buffer != NULL)); + ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashAreaBaseAddress)); + + Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); + + ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashAreaSize)); + + Status = EFI_SUCCESS; + RemainingBytes = *NumBytes; + + while (RemainingBytes > 0) { + + DEBUG ((EFI_D_ERROR, "SpiFlashWrite RemainingBytes 0x%x\n", RemainingBytes)); + + if (RemainingBytes > SIZE_4KB) { + Length = SIZE_4KB; + } else { + Length = RemainingBytes; + } + + Status = mSpiProtocol->FlashWrite( + mSpiProtocol, + FlashRegionAll, + Offset, + Length, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SPI Wirte failed. Status: %r.\n", Status)); + break; + } + + RemainingBytes -= Length; + Offset += Length; + Buffer += Length; + } + + // + // Actual number of bytes written. + // + *NumBytes -= RemainingBytes; + + return Status; +} + +/** + Erase the block starting at Address. + + @param[in] Address The starting physical address of the block to be erased. + This library assume that caller garantee that the PAddress + is at the starting address of this block. + @param[in] NumBytes On input, the number of bytes of the logical block to be erased. + On output, the actual number of bytes erased. + + @retval EFI_SUCCESS. Opertion is successful. + @retval EFI_DEVICE_ERROR If there is any device errors. + +**/ +EFI_STATUS +EFIAPI +SpiFlashBlockErase ( + IN UINTN Address, + IN UINTN *NumBytes + ) +{ + EFI_STATUS Status; + UINT32 Offset; + UINTN RemainingBytes; + + ASSERT (NumBytes != NULL); + ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashAreaBaseAddress)); + + Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); + + ASSERT ((*NumBytes % SIZE_4KB) == 0); + ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashAreaSize)); + + Status = EFI_SUCCESS; + RemainingBytes = *NumBytes; + + while (RemainingBytes > 0) { + + Status = mSpiProtocol->FlashErase ( + mSpiProtocol, + FlashRegionAll, + Offset, + SIZE_4KB + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Erase failed. Status: %r Offset = 0x%x\n", Status, Offset)); + break; + } + + RemainingBytes -= SIZE_4KB; + Offset += SIZE_4KB; + } + + return Status; +} + +EFI_STATUS +EFIAPI +ConvertMac ( + CHAR16 *Str + ) +{ + UINTN Index; + UINT8 Temp[MAC_ADD_STR_LEN]; + + if (Str == NULL) + return EFI_INVALID_PARAMETER; + + if (StrLen(Str) != MAC_ADD_STR_LEN) + return EFI_INVALID_PARAMETER; + + for (Index = 0; Index < MAC_ADD_STR_LEN; Index++) { + if (Str[Index] >= 0x30 && Str[Index] <= 0x39) { + Temp[Index] = (UINT8)Str[Index] - 0x30; + } else if (Str[Index] >= 0x41 && Str[Index] <= 0x46) { + Temp[Index] = (UINT8)Str[Index] - 0x37; + } else if (Str[Index] >= 0x61 && Str[Index] <= 0x66) { + Temp[Index] = (UINT8)Str[Index] - 0x57; + } else { + return EFI_INVALID_PARAMETER; + } + } + + for (Index = 0; Index < MAC_ADD_BYTE_COUNT; Index++) { + mInputData.MacValue[Index] = (Temp[2 * Index] << 4) + Temp[2 * Index + 1]; + } + + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.h b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.h new file mode 100644 index 0000000000..61624b58b7 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.h @@ -0,0 +1,190 @@ +/** @file + +Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that 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. + + +**/ + +#ifndef _FIRMWARE_UPDATE_H_ +#define _FIRMWARE_UPDATE_H_ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Function Prototypes. +// +STATIC +EFI_STATUS +ReadFileData ( + IN CHAR16 *FileName, + OUT UINT8 **Buffer, + OUT UINT32 *BufferSize + ); + +STATIC +EFI_STATUS +InternalEraseBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress + ); + +#if 0 +STATIC +EFI_STATUS +InternalReadBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT VOID *ReadBuffer + ); +#endif + +STATIC +EFI_STATUS +InternalCompareBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT8 *Buffer + ); + +STATIC +EFI_STATUS +InternalWriteBlock ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT8 *Buffer, + IN UINT32 BufferSize + ); + +STATIC +VOID +PrintHelpInfo ( + VOID + ); + +STATIC +EFI_STATUS +EFIAPI +SpiFlashRead ( + IN UINTN Address, + IN OUT UINT32 *NumBytes, + OUT UINT8 *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +SpiFlashWrite ( + IN UINTN Address, + IN OUT UINT32 *NumBytes, + IN UINT8 *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +SpiFlashBlockErase ( + IN UINTN Address, + IN UINTN *NumBytes + ); + +STATIC +EFI_STATUS +EFIAPI +ConvertMac ( + CHAR16 *Str + ); + +EFI_STATUS +InitializeFVUPDATE ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// Flash specific definitions. +// - Should we use a PCD for this information? +// +#define BLOCK_SIZE SIZE_4KB + +// +// Flash region layout and update information. +// +typedef struct { + EFI_PHYSICAL_ADDRESS Base; + UINTN Size; + BOOLEAN Update; +} FV_REGION_INFO; + +// +// MAC Address information. +// +#define MAC_ADD_STR_LEN 12 +#define MAC_ADD_STR_SIZE (MAC_ADD_STR_LEN + 1) +#define MAC_ADD_BYTE_COUNT 6 +#define MAC_ADD_TMP_STR_LEN 2 +#define MAC_ADD_TMP_STR_SIZE (MAC_ADD_TMP_STR_LEN + 1) + +// +// Command Line Data. +// +#define INPUT_STRING_LEN 255 +#define INPUT_STRING_SIZE (INPUT_STRING_LEN + 1) +typedef struct { + BOOLEAN UpdateFromFile; + CHAR16 FileName[INPUT_STRING_SIZE]; + BOOLEAN UpdateMac; + UINT8 MacValue[MAC_ADD_BYTE_COUNT]; + BOOLEAN FullFlashUpdate; +} FV_INPUT_DATA; + +// +// Prefix Opcode Index on the host SPI controller. +// +typedef enum { + SPI_WREN, // Prefix Opcode 0: Write Enable. + SPI_EWSR, // Prefix Opcode 1: Enable Write Status Register. +} PREFIX_OPCODE_INDEX; + +// +// Opcode Menu Index on the host SPI controller. +// +typedef enum { + SPI_READ_ID, // Opcode 0: READ ID, Read cycle with address. + SPI_READ, // Opcode 1: READ, Read cycle with address. + SPI_RDSR, // Opcode 2: Read Status Register, No address. + SPI_WRDI_SFDP, // Opcode 3: Write Disable or Discovery Parameters, No address. + SPI_SERASE, // Opcode 4: Sector Erase (4KB), Write cycle with address. + SPI_BERASE, // Opcode 5: Block Erase (32KB), Write cycle with address. + SPI_PROG, // Opcode 6: Byte Program, Write cycle with address. + SPI_WRSR, // Opcode 7: Write Status Register, No address. +} SPI_OPCODE_INDEX; + +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.inf b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.inf new file mode 100644 index 0000000000..6215714f27 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.inf @@ -0,0 +1,83 @@ +## @file +# Implements a Tunnel Mountain specific flash update program. This will allow +# users to update all regions of the flash as needed in a given update. +# +# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that 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. +# +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FirmwareUpdate + FILE_GUID = AEFAF26C-FB6D-4fef-AF7A-9D78FF201FCA + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + FirmwareUpdateStrings.uni + FirmwareUpdate.c + FirmwareUpdate.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + BroxtonPlatformPkg/PlatformPkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + CacheMaintenanceLib + DebugLib + FileHandleLib + #FlashDeviceLib + #SpiFlashCommonLib + MemoryAllocationLib + PcdLib + ShellCEntryLib + ShellLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gScSpiProtocolGuid + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize ## CONSUMES + +[FixedPcd] +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize +# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + + gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress + gPlatformModuleTokenSpaceGuid.PcdFlashAreaSize + +[BuildOptions] + MSFT:*_*_X64_CC_FLAGS = /Od + INTEL:*_*_X64_CC_FLAGS = /Od \ No newline at end of file diff --git a/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdateStrings.uni b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdateStrings.uni new file mode 100644 index 0000000000..fdd254dea6 Binary files /dev/null and b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdateStrings.uni differ -- cgit v1.2.3