From: zwei4 <david.wei@intel.com>
To: edk2-devel@lists.01.org
Subject: [Patch][edk2-platforms/devel-MinnowBoard3] Add FirmwareUpdate application
Date: Mon, 13 Feb 2017 11:10:05 +0800 [thread overview]
Message-ID: <20170213031005.27728-1-david.wei@intel.com> (raw)
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 <david.wei@intel.com>
---
.../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
diff --git a/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c
new file mode 100644
index 000000000..b374b983d
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.c
@@ -0,0 +1,927 @@
+/** @file
+
+Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+
+ 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 000000000..61624b58b
--- /dev/null
+++ b/Platform/BroxtonPlatformPkg/Common/Application/FirmwareUpdate/FirmwareUpdate.h
@@ -0,0 +1,190 @@
+/** @file
+
+Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ 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 <Uefi.h>
+
+#include <PiDxe.h>
+
+#include <Guid/FileInfo.h>
+
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/Spi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+//
+// 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 000000000..6215714f2
--- /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.<BR>
+#
+# 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 0000000000000000000000000000000000000000..fdd254dea64e70d6021a660be1f861338ed910d0
GIT binary patch
literal 7480
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
literal 0
HcmV?d00001
--
2.11.0.windows.1
reply other threads:[~2017-02-13 3:10 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170213031005.27728-1-david.wei@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox