public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] Marvell/Applications: FirmwareUpdate: Enable burning image on SD/MMC
@ 2019-05-02 11:31 Marcin Wojtas
  2019-05-02 12:57 ` Ard Biesheuvel
  0 siblings, 1 reply; 3+ messages in thread
From: Marcin Wojtas @ 2019-05-02 11:31 UTC (permalink / raw)
  To: devel
  Cc: leif.lindholm, ard.biesheuvel, mw, jsd, jaz, Jici.Gao,
	Tomasz Michalec

From: Tomasz Michalec <tm@semihalf.com>

Extend fupdate shell application to be able to flash firmware
on SD/MMC. Device on which firmware will be updated
is selected via third argument of command.
The SPI is still used as default.

Command uses BlockIo protocol to communicate with SD/MMC. It is possible
to list all valid devices and specify selection via handle number or
device path string. Example output (detailed usage can be found in
updated command's 'help'):

Shell> fupdate list
Handle  Path
spi     spi
8F      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,00006EF00000000000)/SD(0x0)
93      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x0)
94      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x1)
95      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x2)

The code was restructured, to dynamically assign appropriate
firmware update routine, depending on the user choice
(SPI vs BlockDevice).

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
 Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf |  13 +-
 Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c   | 542 +++++++++++++++++---
 Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni | Bin 5190 -> 6758 bytes
 3 files changed, 485 insertions(+), 70 deletions(-)

diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
index 69ee0f8..46847fc 100644
--- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
+++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
@@ -55,6 +55,7 @@
   BaseMemoryLib
   DebugLib
   FileHandleLib
+  HandleParsingLib
   HiiLib
   MemoryAllocationLib
   PcdLib
@@ -62,12 +63,18 @@
   ShellLib
   UefiBootServicesTableLib
   UefiLib
-  UefiLib
   UefiRuntimeServicesTableLib
 
+[Pcd]
+  gMarvellTokenSpaceGuid.PcdSpiFlashCs
+  gMarvellTokenSpaceGuid.PcdSpiFlashMode
+
 [Protocols]
- gMarvellSpiFlashProtocolGuid
- gMarvellSpiMasterProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiDevicePathFromTextProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gMarvellSpiFlashProtocolGuid
+  gMarvellSpiMasterProtocolGuid
 
 [Guids]
   gShellFUpdateHiiGuid
diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
index 22a9b8f..3a496f0 100644
--- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
+++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
@@ -36,7 +36,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
 #include <Library/FileHandleLib.h>
+#include <Library/HandleParsingLib.h>
 #include <Library/HiiLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PrintLib.h>
@@ -46,22 +48,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathFromText.h>
 #include <Protocol/Spi.h>
 #include <Protocol/SpiFlash.h>
 
 #define CMD_NAME_STRING       L"fupdate"
 
+#define SHELL_USE_DEVICE_PATH_PARAM  L"-p"
+#define SHELL_DEVICE_NAME_PARAM      L"DeviceName"
+#define SHELL_FILE_NAME_PARAM        L"LocalFileName"
+#define SHELL_HELP_PARAM             L"help"
+#define SHELL_LIST_PARAM             L"list"
+
 #define MAIN_HDR_MAGIC        0xB105B002
 
-STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
-STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+STATIC EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+STATIC MARVELL_SPI_MASTER_PROTOCOL         *SpiMasterProtocol;
+STATIC MARVELL_SPI_FLASH_PROTOCOL          *SpiFlashProtocol;
+STATIC EFI_BLOCK_IO_PROTOCOL               *BlkIo;
 
 STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands";
 STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL;
 
 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
-  {L"help", TypeFlag},
-  {NULL , TypeMax}
+  {SHELL_HELP_PARAM,            TypeFlag},
+  {SHELL_LIST_PARAM,            TypeFlag},
+  {SHELL_USE_DEVICE_PATH_PARAM, TypeFlag},
+  {SHELL_FILE_NAME_PARAM,       TypePosition},
+  {SHELL_DEVICE_NAME_PARAM,     TypePosition},
+  {NULL ,                       TypeMax}
   };
 
 typedef struct {              // Bytes
@@ -86,6 +103,14 @@ typedef struct {              // Bytes
   UINT32  Reserved3;          // 60-63
 } MV_FIRMWARE_IMAGE_HEADER;
 
+typedef
+EFI_STATUS
+(EFIAPI *FLASH_COMMAND) (
+  UINT64           FileSize,
+  UINTN            *FileBuffer,
+  EFI_LBA          Offset
+);
+
 STATIC
 EFI_STATUS
 SpiFlashProbe (
@@ -109,6 +134,156 @@ SpiFlashProbe (
   return EFI_SUCCESS;
 }
 
+/**
+  Verify if selected device is valid for the firmware update.
+
+  @param[in]   Handle            Handle of verified device
+  @param[in]   Offset            [OPTIONAL] Additional parameter
+                                 required for BlkIo->WriteBlocks,
+                                 filled depending on detected device
+                                 type.
+
+**/
+STATIC
+EFI_STATUS
+IsDeviceSupported (
+  IN  EFI_HANDLE   Handle,
+  OUT EFI_LBA     *Offset OPTIONAL
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
+
+  //
+  // Skip handles that do not have device path protocol
+  //
+  Status = gBS->OpenProtocol (Handle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID**)&DevicePath,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Skip handles that are not block devices
+  //
+  Status = gBS->OpenProtocol (Handle,
+                  &gEfiBlockIoProtocolGuid,
+                  NULL,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  while (!IsDevicePathEnd (DevicePath)) {
+    if (DevicePath->Type == MESSAGING_DEVICE_PATH) {
+      //
+      // Search for SD/MMC devices.
+      //
+      if (DevicePath->SubType == MSG_SD_DP) {
+        //
+        // Only flashing in the beginning of SD card makes sense.
+        //
+        DevicePath = NextDevicePathNode (DevicePath);
+        if (!IsDevicePathEnd (DevicePath)) {
+          return EFI_UNSUPPORTED;
+        }
+        if (Offset != NULL) {
+          *Offset = 1;
+        }
+        return EFI_SUCCESS;
+      }
+      if (DevicePath->SubType == MSG_EMMC_DP) {
+        //
+        // Filter out entire MMC device (ctrl(0x0))
+        // and boot partitions (ctrl(0x1)/ctrl(0x2)) as valid for
+        // the firmware update.
+        //
+        DevicePath = NextDevicePathNode (DevicePath);
+        if (IsDevicePathEnd (DevicePath)) {
+          return EFI_UNSUPPORTED;
+        }
+        DevicePath = NextDevicePathNode (DevicePath);
+        if (!IsDevicePathEnd (DevicePath)) {
+          return EFI_UNSUPPORTED;
+        }
+        if (Offset != NULL) {
+          *Offset = 0;
+        }
+        return EFI_SUCCESS;
+      }
+    }
+    DevicePath = NextDevicePathNode (DevicePath);
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Print information about single device supporting the firmware update.
+
+  @param[in]   Handle            Handle of verified device
+
+**/
+STATIC
+EFI_STATUS
+PrintSupportedDevice (
+  IN EFI_HANDLE  Handle
+  )
+{
+  CHAR16         *Name;
+
+  gEfiShellProtocol->GetDeviceName (Handle,
+    EFI_DEVICE_NAME_USE_DEVICE_PATH,
+    NULL,
+    &Name);
+  if (Name != NULL) {
+    ShellPrintEx (-1,
+      -1,
+      L"%H%02x%N      %s\n",
+      ConvertHandleToHandleIndex (Handle),
+      Name);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Print information about all devices supporting the firmware update.
+
+**/
+STATIC
+EFI_STATUS
+ListSupportedDevices (
+  )
+{
+  UINTN          LoopVar;
+  EFI_HANDLE     Handle;
+  EFI_STATUS     Status;
+
+  ShellPrintEx (-1, -1, L"%BHandle  Path%N\n");
+  ShellPrintEx (-1, -1, L"%Hspi%N     spi\n");
+
+  for (LoopVar = 1; ; LoopVar++) {
+    Handle = ConvertHandleIndexToHandle (LoopVar);
+    if (Handle == NULL) {
+      break;
+    }
+
+    Status = IsDeviceSupported (Handle, NULL);
+    if (!EFI_ERROR (Status)) {
+      PrintSupportedDevice (Handle);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
 STATIC
 EFI_STATUS
 CheckImageHeader (
@@ -149,13 +324,15 @@ PrepareFirmwareImage (
   IN LIST_ENTRY             *CheckPackage,
   IN OUT SHELL_FILE_HANDLE  *FileHandle,
   IN OUT UINTN              **FileBuffer,
-  IN OUT UINT64             *FileSize
+  IN OUT UINT64             *FileSize,
+  IN UINT64                 Alignment
   )
 {
   CONST CHAR16         *FileStr;
   EFI_STATUS           Status;
   UINT64               OpenMode;
   UINTN                *Buffer;
+  UINTN                AlignedFileSize;
 
   // Parse string from commandline
   FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
@@ -184,8 +361,20 @@ PrepareFirmwareImage (
       Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING);
     }
 
+  // Allocate aligned buffer in case of updating firmware in a BlockDevice
+  if (Alignment > 0) {
+    AlignedFileSize = *FileSize + (Alignment - (*FileSize % Alignment));
+  } else {
+    AlignedFileSize = *FileSize;
+  }
+
   // Read Image header into buffer
-  Buffer = AllocateZeroPool (*FileSize);
+  Buffer = AllocateZeroPool (AlignedFileSize);
+  if (Buffer == NULL) {
+    Print (L"%s: Fail to allocate buffer\n", CMD_NAME_STRING);
+    ShellCloseFile (FileHandle);
+    return EFI_OUT_OF_RESOURCES;
+  }
 
   Status = FileHandleRead (*FileHandle, (UINTN *)FileSize, Buffer);
   if (EFI_ERROR (Status)) {
@@ -196,6 +385,233 @@ PrepareFirmwareImage (
   }
 
   *FileBuffer = Buffer;
+  *FileSize = AlignedFileSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update firmware image in the block device.
+
+  @param[in]   FileSize            Size of the file to be flashed
+  @param[in]  *FileBuffer          Pointer to the file in memory
+  @param[in]   Offset              First logical block to be updated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProgramBlockDevice (
+  IN UINT64      FileSize,
+  IN UINTN      *FileBuffer,
+  IN EFI_LBA     Offset
+  )
+{
+  EFI_STATUS     Status;
+
+  Print (L"Updating image in BlockDevice\n");
+
+  Status = BlkIo->WriteBlocks (BlkIo,
+                    BlkIo->Media->MediaId,
+                    Offset,
+                    FileSize,
+                    FileBuffer);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Cannot write to device (Status: %r)\n",
+      CMD_NAME_STRING,
+      Status);
+    return Status;
+  }
+
+  Status = BlkIo->FlushBlocks (BlkIo);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Cannot flush to device (Status: %r)\n",
+      CMD_NAME_STRING,
+      Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Update firmware image in the SPI flash.
+
+  @param[in]   FileSize            Size of the file to be flashed
+  @param[in]  *FileBuffer          Pointer to the file in memory
+  @param[in]   Offset              First logical block to be updated.
+                                   Irrelevant for SPI.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ProgramSpiFlash (
+  IN UINT64      FileSize,
+  IN UINTN      *FileBuffer,
+  IN EFI_LBA     Offset
+  )
+{
+  SPI_DEVICE    *SpiFlash;
+  EFI_STATUS     Status;
+
+  // Locate SPI protocols
+  Status = gBS->LocateProtocol (&gMarvellSpiFlashProtocolGuid,
+                  NULL,
+                  (VOID **)&SpiFlashProtocol);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
+    return Status;
+  }
+
+  Status = gBS->LocateProtocol (&gMarvellSpiMasterProtocolGuid,
+                  NULL,
+                  (VOID **)&SpiMasterProtocol);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
+    return Status;
+  }
+
+  // Setup and probe SPI flash
+  SpiFlash = NULL;
+  SpiFlash = SpiMasterProtocol->SetupDevice (SpiMasterProtocol,
+                                  SpiFlash,
+                                  PcdGet32 (PcdSpiFlashCs),
+                                  PcdGet32 (PcdSpiFlashMode));
+  if (SpiFlash == NULL) {
+    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
+    return EFI_ABORTED;
+  }
+
+  Status = SpiFlashProbe (SpiFlash);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
+    goto FlashProbeError;
+  }
+
+  // Update firmware image in flash at offset 0x0
+  Status = SpiFlashProtocol->Update (SpiFlash,
+                               0x0,
+                               FileSize,
+                               (UINT8 *)FileBuffer);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
+    goto FlashProbeError;
+  }
+
+  // Release resources
+  SpiMasterProtocol->FreeDevice (SpiFlash);
+
+  return EFI_SUCCESS;
+
+FlashProbeError:
+  SpiMasterProtocol->FreeDevice (SpiFlash);
+
+  return Status;
+}
+
+/**
+  Parse commandline parameters and pick device for the firmware update.
+
+  @param[in]     *CheckPackage        Shell command argument list.
+  @param[in/out] *FlashCommand        Pointer to firmware update command.
+                                      Picked, depending on the device type.
+  @param[in/out] *Alignment           File buffer alignment value.
+  @param[in/out] *Offset              First logical block to be updated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+SelectDevice (
+  IN LIST_ENTRY             *CheckPackage,
+  IN OUT FLASH_COMMAND      *FlashCommand,
+  IN OUT UINT64             *Alignment,
+  IN OUT EFI_LBA            *Offset
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  CONST CHAR16              *DeviceName;
+  EFI_HANDLE                Handle;
+  UINTN                     HandleIndex;
+  EFI_STATUS                Status;
+
+  //
+  // SPI flash
+  //
+  DeviceName = ShellCommandLineGetRawValue (CheckPackage, 2);
+  if (DeviceName == NULL || StrnCmp(DeviceName, L"spi", 4) == 0) {
+    *FlashCommand = ProgramSpiFlash;
+    *Alignment = 0;
+    *Offset = 0;
+    return EFI_SUCCESS;
+  }
+
+  if (ShellCommandLineGetFlag (CheckPackage, SHELL_USE_DEVICE_PATH_PARAM)) {
+    //
+    // SD/MMC is selected using device path string.
+    //
+    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid,
+                    NULL,
+                    (VOID **)&EfiDevicePathFromTextProtocol);
+    if (EFI_ERROR (Status)) {
+      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
+        CMD_NAME_STRING);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DeviceName);
+    if (DevicePath == NULL) {
+      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
+        CMD_NAME_STRING);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
+                    &DevicePath,
+                    &Handle);
+    if (EFI_ERROR (Status)) {
+      Print (L"%s: cannot locate selected block device\n", CMD_NAME_STRING);
+      return Status;
+    }
+  } else {
+    //
+    // SD/MMC device is selected using handle number.
+    //
+    HandleIndex = ShellHexStrToUintn (DeviceName);
+    if (HandleIndex == (UINTN)(-1)) {
+      Print (L"%s: handle to device have to be hex number\n", CMD_NAME_STRING);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Handle = ConvertHandleIndexToHandle (HandleIndex);
+    if (Handle == NULL) {
+      Print (L"%s: %x is not correct device handle\n",
+        CMD_NAME_STRING,
+        HandleIndex);
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  Status = IsDeviceSupported (Handle, Offset);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: device not supported\n", CMD_NAME_STRING);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = gBS->OpenProtocol (Handle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID**)&BlkIo,
+                  gImageHandle,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  if (EFI_ERROR (Status)) {
+    Print (L"%s: Cannot open device BlokIo protocol\n", CMD_NAME_STRING);
+    return Status;
+  }
+  *FlashCommand = ProgramBlockDevice;
+  *Alignment = BlkIo->Media->BlockSize;
 
   return EFI_SUCCESS;
 }
@@ -222,11 +638,23 @@ FUpdateUsage (
   )
 {
   Print (L"\nFirmware update command\n"
-         "fupdate <LocalFilePath>\n\n"
+         "fupdate <LocalFilePath> [-p] [Device]\n\n"
          "LocalFilePath - path to local firmware image file\n"
-         "Example:\n"
-         "Update firmware from file fs2:flash-image.bin\n"
-         "  fupdate fs2:flash-image.bin\n"
+         "-p            - When flag is selected Device is interpreted\n"
+         "                as device path, not device handle.\n"
+         "Device        - Select device which will be flashed.\n"
+         "                Supported devices can be listed using \"fupdate list\"\n"
+         "                command. Device is represented by its handle.\n"
+         "                The default value is spi.\n"
+         "EXAMPLES:\n"
+         " * Update firmware in SPI flash from file fs2:flash-image.bin\n"
+         "     fupdate fs2:flash-image.bin\n"
+         " * Update firmware in device with handle 5F from file flash-image.bin\n"
+         "     fupdate flash-image.bin 5F\n"
+         " * Update firmware in device with selected path from file flash.bin\n"
+         "     fupdate flash.bin -p VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/SD(0x0)\n"
+         " * List supported devices\n"
+         "     fupdate list\n"
   );
 }
 
@@ -238,36 +666,17 @@ ShellCommandRunFUpdate (
   IN EFI_SYSTEM_TABLE  *SystemTable
   )
 {
-  IN SHELL_FILE_HANDLE    FileHandle;
-  SPI_DEVICE              *Slave = NULL;
-  UINT64                  FileSize;
-  UINTN                   *FileBuffer = NULL;
-  CHAR16                  *ProblemParam;
-  LIST_ENTRY              *CheckPackage;
-  EFI_STATUS              Status;
-
-  // Locate SPI protocols
-  Status = gBS->LocateProtocol (
-                   &gMarvellSpiFlashProtocolGuid,
-                   NULL,
-                   (VOID **)&SpiFlashProtocol
-                 );
-
-  if (EFI_ERROR(Status)) {
-    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
-    return SHELL_ABORTED;
-  }
-
-  Status = gBS->LocateProtocol (
-                   &gMarvellSpiMasterProtocolGuid,
-                   NULL,
-                   (VOID **)&SpiMasterProtocol
-                 );
-
-  if (EFI_ERROR(Status)) {
-    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
-    return SHELL_ABORTED;
-  }
+  SHELL_FILE_HANDLE  FileHandle;
+  FLASH_COMMAND      FlashCommand;
+  LIST_ENTRY         *CheckPackage;
+  EFI_LBA            Offset;
+  UINT64             Alignment;
+  UINT64             FileSize;
+  UINTN              *FileBuffer;
+  CHAR16             *ProblemParam;
+  EFI_STATUS         Status;
+
+  FileBuffer = NULL;
 
   // Parse command line
   Status = ShellInitialize ();
@@ -283,14 +692,29 @@ ShellCommandRunFUpdate (
     return SHELL_ABORTED;
   }
 
-  if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
-    FUpdateUsage();
+  if (ShellCommandLineGetFlag (CheckPackage, SHELL_HELP_PARAM)) {
+    FUpdateUsage ();
     return EFI_SUCCESS;
   }
 
+  if (ShellCommandLineGetFlag (CheckPackage, SHELL_LIST_PARAM)) {
+    ListSupportedDevices ();
+    return EFI_SUCCESS;
+  }
+
+  // Select device to flash
+  Status = SelectDevice (CheckPackage, &FlashCommand, &Alignment, &Offset);
+  if (EFI_ERROR (Status)) {
+    return SHELL_ABORTED;
+  }
+
   // Prepare local file to be burned into flash
-  Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize);
-  if (EFI_ERROR(Status)) {
+  Status = PrepareFirmwareImage (CheckPackage,
+             &FileHandle,
+             &FileBuffer,
+             &FileSize,
+             Alignment);
+  if (EFI_ERROR (Status)) {
     return SHELL_ABORTED;
   }
 
@@ -300,38 +724,22 @@ ShellCommandRunFUpdate (
     goto HeaderError;
   }
 
-  // Setup and probe SPI flash
-  Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, Slave, 0, 0);
-  if (Slave == NULL) {
-    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
+  // Update firmware image
+  Status = FlashCommand (FileSize, FileBuffer, Offset);
+  if (EFI_ERROR (Status)) {
     goto HeaderError;
   }
 
-  Status = SpiFlashProbe (Slave);
-  if (EFI_ERROR(Status)) {
-    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
-    goto FlashProbeError;
-  }
-
-  // Update firmware image in flash at offset 0x0
-  Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer);
-
-  // Release resources
-  SpiMasterProtocol->FreeDevice(Slave);
   FreePool (FileBuffer);
   ShellCloseFile (&FileHandle);
 
-  if (EFI_ERROR(Status)) {
-    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
-    return SHELL_ABORTED;
-  }
-
-  Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize);
+  Print (L"%s: Update %d bytes at offset 0x%x succeeded!\n",
+    CMD_NAME_STRING,
+    FileSize,
+    Offset * Alignment);
 
   return EFI_SUCCESS;
 
-FlashProbeError:
-  SpiMasterProtocol->FreeDevice(Slave);
 HeaderError:
   FreePool (FileBuffer);
   ShellCloseFile (&FileHandle);
diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni
index 146f624737d96e2cd354857dbb63390ebe2f347e..3ea892aa2a982827ad235c505270acbca21ea27b 100644
GIT binary patch
delta 1093
zcmah|(P|Sx6g@$uNPXDuTB`)<=u@MnS*4*0zNBf3VttT^MNE-2v2I|EF`G2{<TuDg
z@FxU|U!V{Ehai3S*(cAP$>^GjGVIKqnRDmfd(Pc2ONT2TJ_kjEM<}C@9jLXAC)h_9
zZLT}=DaZ<asm?V{7{$ofs3`Hw@rPw%w~-LjqqT<=Ej*>wMaDVfdCISiA?FTH@~?VS
zm%e&GVC(@`i<K8aB;TU5@;y4Gk!mgbVu$xWD?@yX=mb~zau3gG8%D_^5+Zs$V-|7{
zEzIWP%e`n}L-TLY!)H0|Kj!PoK|<V^R?1<pOAlXdhD6?zjl<}S&-HEtBj(m;Mgvz3
z(fPcTo3_o&zm;0XJWC_is;nrJO?eYUv;Mw`i_^?(w;AUdhpTj%KDjEnb6O~~j$c*9
zF|La2;+4e=Ex%KI<*TaPw>rB@_84tME|l?o+9`L+iPyc4F8Q99A3-4R=9=u9OE7XW
zxFDy)q+nzm-uZo2(OUmx$g!>38h*bt<gSWMxg4I8tuUT9+^Y`Cc84hC&&cg?k#8%G
zJ#=gmxBBlGM?2N_mXyNcjP|su{5U-S`mYfueNPOQ$)}5?f0Dri%k?ex&JtqkQpHu=
zpjE{h|D!dma%|9A;mI}BXw|sZi74~D&Rxv8j_c0%CV@4!dpsGdyx63J-{;p7Ds1g_
m8~7y=C8eW6I<RGBQt7h)HLCh7x}uK|P0>~E;m3pUZQ&;(bkkG-

delta 54
zcmV-60LlO6G{z{f!Vr_v7#NfG5Ly9HlTi^<liCz)lL`<ZlP(tqlX4Yelf)Jhlk62V
MlkN}*v+5Xp0aXzc(f|Me

-- 
2.7.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] Marvell/Applications: FirmwareUpdate: Enable burning image on SD/MMC
  2019-05-02 11:31 [PATCH] Marvell/Applications: FirmwareUpdate: Enable burning image on SD/MMC Marcin Wojtas
@ 2019-05-02 12:57 ` Ard Biesheuvel
  2019-05-02 14:31   ` Marcin Wojtas
  0 siblings, 1 reply; 3+ messages in thread
From: Ard Biesheuvel @ 2019-05-02 12:57 UTC (permalink / raw)
  To: Marcin Wojtas
  Cc: edk2-devel-groups-io, Leif Lindholm, Jan Dąbroś,
	Grzegorz Jaszczyk, Jici Gao, Tomasz Michalec

On Thu, 2 May 2019 at 13:31, Marcin Wojtas <mw@semihalf.com> wrote:
>
> From: Tomasz Michalec <tm@semihalf.com>
>
> Extend fupdate shell application to be able to flash firmware
> on SD/MMC. Device on which firmware will be updated
> is selected via third argument of command.
> The SPI is still used as default.
>
> Command uses BlockIo protocol to communicate with SD/MMC. It is possible
> to list all valid devices and specify selection via handle number or
> device path string. Example output (detailed usage can be found in
> updated command's 'help'):
>
> Shell> fupdate list
> Handle  Path
> spi     spi
> 8F      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,00006EF00000000000)/SD(0x0)
> 93      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x0)
> 94      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x1)
> 95      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x2)
>
> The code was restructured, to dynamically assign appropriate
> firmware update routine, depending on the user choice
> (SPI vs BlockDevice).
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Marcin Wojtas <mw@semihalf.com>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Pushed as cee103d37d6b..4795747fe477

> ---
>  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf |  13 +-
>  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c   | 542 +++++++++++++++++---
>  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni | Bin 5190 -> 6758 bytes
>  3 files changed, 485 insertions(+), 70 deletions(-)
>
> diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> index 69ee0f8..46847fc 100644
> --- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> +++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> @@ -55,6 +55,7 @@
>    BaseMemoryLib
>    DebugLib
>    FileHandleLib
> +  HandleParsingLib
>    HiiLib
>    MemoryAllocationLib
>    PcdLib
> @@ -62,12 +63,18 @@
>    ShellLib
>    UefiBootServicesTableLib
>    UefiLib
> -  UefiLib
>    UefiRuntimeServicesTableLib
>
> +[Pcd]
> +  gMarvellTokenSpaceGuid.PcdSpiFlashCs
> +  gMarvellTokenSpaceGuid.PcdSpiFlashMode
> +
>  [Protocols]
> - gMarvellSpiFlashProtocolGuid
> - gMarvellSpiMasterProtocolGuid
> +  gEfiBlockIoProtocolGuid
> +  gEfiDevicePathFromTextProtocolGuid
> +  gEfiDevicePathProtocolGuid
> +  gMarvellSpiFlashProtocolGuid
> +  gMarvellSpiMasterProtocolGuid
>
>  [Guids]
>    gShellFUpdateHiiGuid
> diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> index 22a9b8f..3a496f0 100644
> --- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> +++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> @@ -36,7 +36,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
>  #include <Library/FileHandleLib.h>
> +#include <Library/HandleParsingLib.h>
>  #include <Library/HiiLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/PrintLib.h>
> @@ -46,22 +48,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>
> +#include <Protocol/BlockIo.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/DevicePathFromText.h>
>  #include <Protocol/Spi.h>
>  #include <Protocol/SpiFlash.h>
>
>  #define CMD_NAME_STRING       L"fupdate"
>
> +#define SHELL_USE_DEVICE_PATH_PARAM  L"-p"
> +#define SHELL_DEVICE_NAME_PARAM      L"DeviceName"
> +#define SHELL_FILE_NAME_PARAM        L"LocalFileName"
> +#define SHELL_HELP_PARAM             L"help"
> +#define SHELL_LIST_PARAM             L"list"
> +
>  #define MAIN_HDR_MAGIC        0xB105B002
>
> -STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
> -STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
> +STATIC EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
> +STATIC MARVELL_SPI_MASTER_PROTOCOL         *SpiMasterProtocol;
> +STATIC MARVELL_SPI_FLASH_PROTOCOL          *SpiFlashProtocol;
> +STATIC EFI_BLOCK_IO_PROTOCOL               *BlkIo;
>
>  STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands";
>  STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL;
>
>  STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> -  {L"help", TypeFlag},
> -  {NULL , TypeMax}
> +  {SHELL_HELP_PARAM,            TypeFlag},
> +  {SHELL_LIST_PARAM,            TypeFlag},
> +  {SHELL_USE_DEVICE_PATH_PARAM, TypeFlag},
> +  {SHELL_FILE_NAME_PARAM,       TypePosition},
> +  {SHELL_DEVICE_NAME_PARAM,     TypePosition},
> +  {NULL ,                       TypeMax}
>    };
>
>  typedef struct {              // Bytes
> @@ -86,6 +103,14 @@ typedef struct {              // Bytes
>    UINT32  Reserved3;          // 60-63
>  } MV_FIRMWARE_IMAGE_HEADER;
>
> +typedef
> +EFI_STATUS
> +(EFIAPI *FLASH_COMMAND) (
> +  UINT64           FileSize,
> +  UINTN            *FileBuffer,
> +  EFI_LBA          Offset
> +);
> +
>  STATIC
>  EFI_STATUS
>  SpiFlashProbe (
> @@ -109,6 +134,156 @@ SpiFlashProbe (
>    return EFI_SUCCESS;
>  }
>
> +/**
> +  Verify if selected device is valid for the firmware update.
> +
> +  @param[in]   Handle            Handle of verified device
> +  @param[in]   Offset            [OPTIONAL] Additional parameter
> +                                 required for BlkIo->WriteBlocks,
> +                                 filled depending on detected device
> +                                 type.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +IsDeviceSupported (
> +  IN  EFI_HANDLE   Handle,
> +  OUT EFI_LBA     *Offset OPTIONAL
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
> +
> +  //
> +  // Skip handles that do not have device path protocol
> +  //
> +  Status = gBS->OpenProtocol (Handle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID**)&DevicePath,
> +                  gImageHandle,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Skip handles that are not block devices
> +  //
> +  Status = gBS->OpenProtocol (Handle,
> +                  &gEfiBlockIoProtocolGuid,
> +                  NULL,
> +                  NULL,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  while (!IsDevicePathEnd (DevicePath)) {
> +    if (DevicePath->Type == MESSAGING_DEVICE_PATH) {
> +      //
> +      // Search for SD/MMC devices.
> +      //
> +      if (DevicePath->SubType == MSG_SD_DP) {
> +        //
> +        // Only flashing in the beginning of SD card makes sense.
> +        //
> +        DevicePath = NextDevicePathNode (DevicePath);
> +        if (!IsDevicePathEnd (DevicePath)) {
> +          return EFI_UNSUPPORTED;
> +        }
> +        if (Offset != NULL) {
> +          *Offset = 1;
> +        }
> +        return EFI_SUCCESS;
> +      }
> +      if (DevicePath->SubType == MSG_EMMC_DP) {
> +        //
> +        // Filter out entire MMC device (ctrl(0x0))
> +        // and boot partitions (ctrl(0x1)/ctrl(0x2)) as valid for
> +        // the firmware update.
> +        //
> +        DevicePath = NextDevicePathNode (DevicePath);
> +        if (IsDevicePathEnd (DevicePath)) {
> +          return EFI_UNSUPPORTED;
> +        }
> +        DevicePath = NextDevicePathNode (DevicePath);
> +        if (!IsDevicePathEnd (DevicePath)) {
> +          return EFI_UNSUPPORTED;
> +        }
> +        if (Offset != NULL) {
> +          *Offset = 0;
> +        }
> +        return EFI_SUCCESS;
> +      }
> +    }
> +    DevicePath = NextDevicePathNode (DevicePath);
> +  }
> +
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Print information about single device supporting the firmware update.
> +
> +  @param[in]   Handle            Handle of verified device
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PrintSupportedDevice (
> +  IN EFI_HANDLE  Handle
> +  )
> +{
> +  CHAR16         *Name;
> +
> +  gEfiShellProtocol->GetDeviceName (Handle,
> +    EFI_DEVICE_NAME_USE_DEVICE_PATH,
> +    NULL,
> +    &Name);
> +  if (Name != NULL) {
> +    ShellPrintEx (-1,
> +      -1,
> +      L"%H%02x%N      %s\n",
> +      ConvertHandleToHandleIndex (Handle),
> +      Name);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Print information about all devices supporting the firmware update.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +ListSupportedDevices (
> +  )
> +{
> +  UINTN          LoopVar;
> +  EFI_HANDLE     Handle;
> +  EFI_STATUS     Status;
> +
> +  ShellPrintEx (-1, -1, L"%BHandle  Path%N\n");
> +  ShellPrintEx (-1, -1, L"%Hspi%N     spi\n");
> +
> +  for (LoopVar = 1; ; LoopVar++) {
> +    Handle = ConvertHandleIndexToHandle (LoopVar);
> +    if (Handle == NULL) {
> +      break;
> +    }
> +
> +    Status = IsDeviceSupported (Handle, NULL);
> +    if (!EFI_ERROR (Status)) {
> +      PrintSupportedDevice (Handle);
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
>  STATIC
>  EFI_STATUS
>  CheckImageHeader (
> @@ -149,13 +324,15 @@ PrepareFirmwareImage (
>    IN LIST_ENTRY             *CheckPackage,
>    IN OUT SHELL_FILE_HANDLE  *FileHandle,
>    IN OUT UINTN              **FileBuffer,
> -  IN OUT UINT64             *FileSize
> +  IN OUT UINT64             *FileSize,
> +  IN UINT64                 Alignment
>    )
>  {
>    CONST CHAR16         *FileStr;
>    EFI_STATUS           Status;
>    UINT64               OpenMode;
>    UINTN                *Buffer;
> +  UINTN                AlignedFileSize;
>
>    // Parse string from commandline
>    FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
> @@ -184,8 +361,20 @@ PrepareFirmwareImage (
>        Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING);
>      }
>
> +  // Allocate aligned buffer in case of updating firmware in a BlockDevice
> +  if (Alignment > 0) {
> +    AlignedFileSize = *FileSize + (Alignment - (*FileSize % Alignment));
> +  } else {
> +    AlignedFileSize = *FileSize;
> +  }
> +
>    // Read Image header into buffer
> -  Buffer = AllocateZeroPool (*FileSize);
> +  Buffer = AllocateZeroPool (AlignedFileSize);
> +  if (Buffer == NULL) {
> +    Print (L"%s: Fail to allocate buffer\n", CMD_NAME_STRING);
> +    ShellCloseFile (FileHandle);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
>
>    Status = FileHandleRead (*FileHandle, (UINTN *)FileSize, Buffer);
>    if (EFI_ERROR (Status)) {
> @@ -196,6 +385,233 @@ PrepareFirmwareImage (
>    }
>
>    *FileBuffer = Buffer;
> +  *FileSize = AlignedFileSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Update firmware image in the block device.
> +
> +  @param[in]   FileSize            Size of the file to be flashed
> +  @param[in]  *FileBuffer          Pointer to the file in memory
> +  @param[in]   Offset              First logical block to be updated.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +ProgramBlockDevice (
> +  IN UINT64      FileSize,
> +  IN UINTN      *FileBuffer,
> +  IN EFI_LBA     Offset
> +  )
> +{
> +  EFI_STATUS     Status;
> +
> +  Print (L"Updating image in BlockDevice\n");
> +
> +  Status = BlkIo->WriteBlocks (BlkIo,
> +                    BlkIo->Media->MediaId,
> +                    Offset,
> +                    FileSize,
> +                    FileBuffer);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Cannot write to device (Status: %r)\n",
> +      CMD_NAME_STRING,
> +      Status);
> +    return Status;
> +  }
> +
> +  Status = BlkIo->FlushBlocks (BlkIo);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Cannot flush to device (Status: %r)\n",
> +      CMD_NAME_STRING,
> +      Status);
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +  Update firmware image in the SPI flash.
> +
> +  @param[in]   FileSize            Size of the file to be flashed
> +  @param[in]  *FileBuffer          Pointer to the file in memory
> +  @param[in]   Offset              First logical block to be updated.
> +                                   Irrelevant for SPI.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +ProgramSpiFlash (
> +  IN UINT64      FileSize,
> +  IN UINTN      *FileBuffer,
> +  IN EFI_LBA     Offset
> +  )
> +{
> +  SPI_DEVICE    *SpiFlash;
> +  EFI_STATUS     Status;
> +
> +  // Locate SPI protocols
> +  Status = gBS->LocateProtocol (&gMarvellSpiFlashProtocolGuid,
> +                  NULL,
> +                  (VOID **)&SpiFlashProtocol);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
> +    return Status;
> +  }
> +
> +  Status = gBS->LocateProtocol (&gMarvellSpiMasterProtocolGuid,
> +                  NULL,
> +                  (VOID **)&SpiMasterProtocol);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
> +    return Status;
> +  }
> +
> +  // Setup and probe SPI flash
> +  SpiFlash = NULL;
> +  SpiFlash = SpiMasterProtocol->SetupDevice (SpiMasterProtocol,
> +                                  SpiFlash,
> +                                  PcdGet32 (PcdSpiFlashCs),
> +                                  PcdGet32 (PcdSpiFlashMode));
> +  if (SpiFlash == NULL) {
> +    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
> +    return EFI_ABORTED;
> +  }
> +
> +  Status = SpiFlashProbe (SpiFlash);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
> +    goto FlashProbeError;
> +  }
> +
> +  // Update firmware image in flash at offset 0x0
> +  Status = SpiFlashProtocol->Update (SpiFlash,
> +                               0x0,
> +                               FileSize,
> +                               (UINT8 *)FileBuffer);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
> +    goto FlashProbeError;
> +  }
> +
> +  // Release resources
> +  SpiMasterProtocol->FreeDevice (SpiFlash);
> +
> +  return EFI_SUCCESS;
> +
> +FlashProbeError:
> +  SpiMasterProtocol->FreeDevice (SpiFlash);
> +
> +  return Status;
> +}
> +
> +/**
> +  Parse commandline parameters and pick device for the firmware update.
> +
> +  @param[in]     *CheckPackage        Shell command argument list.
> +  @param[in/out] *FlashCommand        Pointer to firmware update command.
> +                                      Picked, depending on the device type.
> +  @param[in/out] *Alignment           File buffer alignment value.
> +  @param[in/out] *Offset              First logical block to be updated.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +SelectDevice (
> +  IN LIST_ENTRY             *CheckPackage,
> +  IN OUT FLASH_COMMAND      *FlashCommand,
> +  IN OUT UINT64             *Alignment,
> +  IN OUT EFI_LBA            *Offset
> +  )
> +{
> +  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
> +  CONST CHAR16              *DeviceName;
> +  EFI_HANDLE                Handle;
> +  UINTN                     HandleIndex;
> +  EFI_STATUS                Status;
> +
> +  //
> +  // SPI flash
> +  //
> +  DeviceName = ShellCommandLineGetRawValue (CheckPackage, 2);
> +  if (DeviceName == NULL || StrnCmp(DeviceName, L"spi", 4) == 0) {
> +    *FlashCommand = ProgramSpiFlash;
> +    *Alignment = 0;
> +    *Offset = 0;
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_USE_DEVICE_PATH_PARAM)) {
> +    //
> +    // SD/MMC is selected using device path string.
> +    //
> +    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid,
> +                    NULL,
> +                    (VOID **)&EfiDevicePathFromTextProtocol);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
> +        CMD_NAME_STRING);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DeviceName);
> +    if (DevicePath == NULL) {
> +      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
> +        CMD_NAME_STRING);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> +                    &DevicePath,
> +                    &Handle);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"%s: cannot locate selected block device\n", CMD_NAME_STRING);
> +      return Status;
> +    }
> +  } else {
> +    //
> +    // SD/MMC device is selected using handle number.
> +    //
> +    HandleIndex = ShellHexStrToUintn (DeviceName);
> +    if (HandleIndex == (UINTN)(-1)) {
> +      Print (L"%s: handle to device have to be hex number\n", CMD_NAME_STRING);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    Handle = ConvertHandleIndexToHandle (HandleIndex);
> +    if (Handle == NULL) {
> +      Print (L"%s: %x is not correct device handle\n",
> +        CMD_NAME_STRING,
> +        HandleIndex);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  Status = IsDeviceSupported (Handle, Offset);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: device not supported\n", CMD_NAME_STRING);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = gBS->OpenProtocol (Handle,
> +                  &gEfiBlockIoProtocolGuid,
> +                  (VOID**)&BlkIo,
> +                  gImageHandle,
> +                  NULL,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"%s: Cannot open device BlokIo protocol\n", CMD_NAME_STRING);
> +    return Status;
> +  }
> +  *FlashCommand = ProgramBlockDevice;
> +  *Alignment = BlkIo->Media->BlockSize;
>
>    return EFI_SUCCESS;
>  }
> @@ -222,11 +638,23 @@ FUpdateUsage (
>    )
>  {
>    Print (L"\nFirmware update command\n"
> -         "fupdate <LocalFilePath>\n\n"
> +         "fupdate <LocalFilePath> [-p] [Device]\n\n"
>           "LocalFilePath - path to local firmware image file\n"
> -         "Example:\n"
> -         "Update firmware from file fs2:flash-image.bin\n"
> -         "  fupdate fs2:flash-image.bin\n"
> +         "-p            - When flag is selected Device is interpreted\n"
> +         "                as device path, not device handle.\n"
> +         "Device        - Select device which will be flashed.\n"
> +         "                Supported devices can be listed using \"fupdate list\"\n"
> +         "                command. Device is represented by its handle.\n"
> +         "                The default value is spi.\n"
> +         "EXAMPLES:\n"
> +         " * Update firmware in SPI flash from file fs2:flash-image.bin\n"
> +         "     fupdate fs2:flash-image.bin\n"
> +         " * Update firmware in device with handle 5F from file flash-image.bin\n"
> +         "     fupdate flash-image.bin 5F\n"
> +         " * Update firmware in device with selected path from file flash.bin\n"
> +         "     fupdate flash.bin -p VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/SD(0x0)\n"
> +         " * List supported devices\n"
> +         "     fupdate list\n"
>    );
>  }
>
> @@ -238,36 +666,17 @@ ShellCommandRunFUpdate (
>    IN EFI_SYSTEM_TABLE  *SystemTable
>    )
>  {
> -  IN SHELL_FILE_HANDLE    FileHandle;
> -  SPI_DEVICE              *Slave = NULL;
> -  UINT64                  FileSize;
> -  UINTN                   *FileBuffer = NULL;
> -  CHAR16                  *ProblemParam;
> -  LIST_ENTRY              *CheckPackage;
> -  EFI_STATUS              Status;
> -
> -  // Locate SPI protocols
> -  Status = gBS->LocateProtocol (
> -                   &gMarvellSpiFlashProtocolGuid,
> -                   NULL,
> -                   (VOID **)&SpiFlashProtocol
> -                 );
> -
> -  if (EFI_ERROR(Status)) {
> -    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
> -    return SHELL_ABORTED;
> -  }
> -
> -  Status = gBS->LocateProtocol (
> -                   &gMarvellSpiMasterProtocolGuid,
> -                   NULL,
> -                   (VOID **)&SpiMasterProtocol
> -                 );
> -
> -  if (EFI_ERROR(Status)) {
> -    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
> -    return SHELL_ABORTED;
> -  }
> +  SHELL_FILE_HANDLE  FileHandle;
> +  FLASH_COMMAND      FlashCommand;
> +  LIST_ENTRY         *CheckPackage;
> +  EFI_LBA            Offset;
> +  UINT64             Alignment;
> +  UINT64             FileSize;
> +  UINTN              *FileBuffer;
> +  CHAR16             *ProblemParam;
> +  EFI_STATUS         Status;
> +
> +  FileBuffer = NULL;
>
>    // Parse command line
>    Status = ShellInitialize ();
> @@ -283,14 +692,29 @@ ShellCommandRunFUpdate (
>      return SHELL_ABORTED;
>    }
>
> -  if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
> -    FUpdateUsage();
> +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_HELP_PARAM)) {
> +    FUpdateUsage ();
>      return EFI_SUCCESS;
>    }
>
> +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_LIST_PARAM)) {
> +    ListSupportedDevices ();
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Select device to flash
> +  Status = SelectDevice (CheckPackage, &FlashCommand, &Alignment, &Offset);
> +  if (EFI_ERROR (Status)) {
> +    return SHELL_ABORTED;
> +  }
> +
>    // Prepare local file to be burned into flash
> -  Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize);
> -  if (EFI_ERROR(Status)) {
> +  Status = PrepareFirmwareImage (CheckPackage,
> +             &FileHandle,
> +             &FileBuffer,
> +             &FileSize,
> +             Alignment);
> +  if (EFI_ERROR (Status)) {
>      return SHELL_ABORTED;
>    }
>
> @@ -300,38 +724,22 @@ ShellCommandRunFUpdate (
>      goto HeaderError;
>    }
>
> -  // Setup and probe SPI flash
> -  Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, Slave, 0, 0);
> -  if (Slave == NULL) {
> -    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
> +  // Update firmware image
> +  Status = FlashCommand (FileSize, FileBuffer, Offset);
> +  if (EFI_ERROR (Status)) {
>      goto HeaderError;
>    }
>
> -  Status = SpiFlashProbe (Slave);
> -  if (EFI_ERROR(Status)) {
> -    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
> -    goto FlashProbeError;
> -  }
> -
> -  // Update firmware image in flash at offset 0x0
> -  Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer);
> -
> -  // Release resources
> -  SpiMasterProtocol->FreeDevice(Slave);
>    FreePool (FileBuffer);
>    ShellCloseFile (&FileHandle);
>
> -  if (EFI_ERROR(Status)) {
> -    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
> -    return SHELL_ABORTED;
> -  }
> -
> -  Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize);
> +  Print (L"%s: Update %d bytes at offset 0x%x succeeded!\n",
> +    CMD_NAME_STRING,
> +    FileSize,
> +    Offset * Alignment);
>
>    return EFI_SUCCESS;
>
> -FlashProbeError:
> -  SpiMasterProtocol->FreeDevice(Slave);
>  HeaderError:
>    FreePool (FileBuffer);
>    ShellCloseFile (&FileHandle);
> diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni
> index 146f624737d96e2cd354857dbb63390ebe2f347e..3ea892aa2a982827ad235c505270acbca21ea27b 100644
> GIT binary patch
> delta 1093
> zcmah|(P|Sx6g@$uNPXDuTB`)<=u@MnS*4*0zNBf3VttT^MNE-2v2I|EF`G2{<TuDg
> z@FxU|U!V{Ehai3S*(cAP$>^GjGVIKqnRDmfd(Pc2ONT2TJ_kjEM<}C@9jLXAC)h_9
> zZLT}=DaZ<asm?V{7{$ofs3`Hw@rPw%w~-LjqqT<=Ej*>wMaDVfdCISiA?FTH@~?VS
> zm%e&GVC(@`i<K8aB;TU5@;y4Gk!mgbVu$xWD?@yX=mb~zau3gG8%D_^5+Zs$V-|7{
> zEzIWP%e`n}L-TLY!)H0|Kj!PoK|<V^R?1<pOAlXdhD6?zjl<}S&-HEtBj(m;Mgvz3
> z(fPcTo3_o&zm;0XJWC_is;nrJO?eYUv;Mw`i_^?(w;AUdhpTj%KDjEnb6O~~j$c*9
> zF|La2;+4e=Ex%KI<*TaPw>rB@_84tME|l?o+9`L+iPyc4F8Q99A3-4R=9=u9OE7XW
> zxFDy)q+nzm-uZo2(OUmx$g!>38h*bt<gSWMxg4I8tuUT9+^Y`Cc84hC&&cg?k#8%G
> zJ#=gmxBBlGM?2N_mXyNcjP|su{5U-S`mYfueNPOQ$)}5?f0Dri%k?ex&JtqkQpHu=
> zpjE{h|D!dma%|9A;mI}BXw|sZi74~D&Rxv8j_c0%CV@4!dpsGdyx63J-{;p7Ds1g_
> m8~7y=C8eW6I<RGBQt7h)HLCh7x}uK|P0>~E;m3pUZQ&;(bkkG-
>
> delta 54
> zcmV-60LlO6G{z{f!Vr_v7#NfG5Ly9HlTi^<liCz)lL`<ZlP(tqlX4Yelf)Jhlk62V
> MlkN}*v+5Xp0aXzc(f|Me
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Marvell/Applications: FirmwareUpdate: Enable burning image on SD/MMC
  2019-05-02 12:57 ` Ard Biesheuvel
@ 2019-05-02 14:31   ` Marcin Wojtas
  0 siblings, 0 replies; 3+ messages in thread
From: Marcin Wojtas @ 2019-05-02 14:31 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: edk2-devel-groups-io, Leif Lindholm, Jan Dąbroś,
	Grzegorz Jaszczyk, Jici Gao, Tomasz Michalec

Hi Ard,

czw., 2 maj 2019 o 14:58 Ard Biesheuvel <ard.biesheuvel@linaro.org> napisał(a):
>
> On Thu, 2 May 2019 at 13:31, Marcin Wojtas <mw@semihalf.com> wrote:
> >
> > From: Tomasz Michalec <tm@semihalf.com>
> >
> > Extend fupdate shell application to be able to flash firmware
> > on SD/MMC. Device on which firmware will be updated
> > is selected via third argument of command.
> > The SPI is still used as default.
> >
> > Command uses BlockIo protocol to communicate with SD/MMC. It is possible
> > to list all valid devices and specify selection via handle number or
> > device path string. Example output (detailed usage can be found in
> > updated command's 'help'):
> >
> > Shell> fupdate list
> > Handle  Path
> > spi     spi
> > 8F      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,00006EF00000000000)/SD(0x0)
> > 93      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x0)
> > 94      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x1)
> > 95      VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/eMMC(0x0)/Ctrl(0x2)
> >
> > The code was restructured, to dynamically assign appropriate
> > firmware update routine, depending on the user choice
> > (SPI vs BlockDevice).
> >
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Marcin Wojtas <mw@semihalf.com>
>
> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>
> Pushed as cee103d37d6b..4795747fe477
>

Wow, thanks - I didn't expect it to happen that fast :) If so, I'm
submitting the last 3 small patches I have on my stack. PCIE most
likely tomorrow. Afterwards SMBIOS and we'd be functionally ahead of
any other branch for this SoC :)

Best regard,
Marcin

> > ---
> >  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf |  13 +-
> >  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c   | 542 +++++++++++++++++---
> >  Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni | Bin 5190 -> 6758 bytes
> >  3 files changed, 485 insertions(+), 70 deletions(-)
> >
> > diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> > index 69ee0f8..46847fc 100644
> > --- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> > +++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.inf
> > @@ -55,6 +55,7 @@
> >    BaseMemoryLib
> >    DebugLib
> >    FileHandleLib
> > +  HandleParsingLib
> >    HiiLib
> >    MemoryAllocationLib
> >    PcdLib
> > @@ -62,12 +63,18 @@
> >    ShellLib
> >    UefiBootServicesTableLib
> >    UefiLib
> > -  UefiLib
> >    UefiRuntimeServicesTableLib
> >
> > +[Pcd]
> > +  gMarvellTokenSpaceGuid.PcdSpiFlashCs
> > +  gMarvellTokenSpaceGuid.PcdSpiFlashMode
> > +
> >  [Protocols]
> > - gMarvellSpiFlashProtocolGuid
> > - gMarvellSpiMasterProtocolGuid
> > +  gEfiBlockIoProtocolGuid
> > +  gEfiDevicePathFromTextProtocolGuid
> > +  gEfiDevicePathProtocolGuid
> > +  gMarvellSpiFlashProtocolGuid
> > +  gMarvellSpiMasterProtocolGuid
> >
> >  [Guids]
> >    gShellFUpdateHiiGuid
> > diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> > index 22a9b8f..3a496f0 100644
> > --- a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> > +++ b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.c
> > @@ -36,7 +36,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> >  #include <Library/BaseLib.h>
> >  #include <Library/BaseMemoryLib.h>
> >  #include <Library/DebugLib.h>
> > +#include <Library/DevicePathLib.h>
> >  #include <Library/FileHandleLib.h>
> > +#include <Library/HandleParsingLib.h>
> >  #include <Library/HiiLib.h>
> >  #include <Library/MemoryAllocationLib.h>
> >  #include <Library/PrintLib.h>
> > @@ -46,22 +48,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> >  #include <Library/UefiBootServicesTableLib.h>
> >  #include <Library/UefiLib.h>
> >
> > +#include <Protocol/BlockIo.h>
> > +#include <Protocol/DevicePath.h>
> > +#include <Protocol/DevicePathFromText.h>
> >  #include <Protocol/Spi.h>
> >  #include <Protocol/SpiFlash.h>
> >
> >  #define CMD_NAME_STRING       L"fupdate"
> >
> > +#define SHELL_USE_DEVICE_PATH_PARAM  L"-p"
> > +#define SHELL_DEVICE_NAME_PARAM      L"DeviceName"
> > +#define SHELL_FILE_NAME_PARAM        L"LocalFileName"
> > +#define SHELL_HELP_PARAM             L"help"
> > +#define SHELL_LIST_PARAM             L"list"
> > +
> >  #define MAIN_HDR_MAGIC        0xB105B002
> >
> > -STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
> > -STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
> > +STATIC EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
> > +STATIC MARVELL_SPI_MASTER_PROTOCOL         *SpiMasterProtocol;
> > +STATIC MARVELL_SPI_FLASH_PROTOCOL          *SpiFlashProtocol;
> > +STATIC EFI_BLOCK_IO_PROTOCOL               *BlkIo;
> >
> >  STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands";
> >  STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL;
> >
> >  STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> > -  {L"help", TypeFlag},
> > -  {NULL , TypeMax}
> > +  {SHELL_HELP_PARAM,            TypeFlag},
> > +  {SHELL_LIST_PARAM,            TypeFlag},
> > +  {SHELL_USE_DEVICE_PATH_PARAM, TypeFlag},
> > +  {SHELL_FILE_NAME_PARAM,       TypePosition},
> > +  {SHELL_DEVICE_NAME_PARAM,     TypePosition},
> > +  {NULL ,                       TypeMax}
> >    };
> >
> >  typedef struct {              // Bytes
> > @@ -86,6 +103,14 @@ typedef struct {              // Bytes
> >    UINT32  Reserved3;          // 60-63
> >  } MV_FIRMWARE_IMAGE_HEADER;
> >
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *FLASH_COMMAND) (
> > +  UINT64           FileSize,
> > +  UINTN            *FileBuffer,
> > +  EFI_LBA          Offset
> > +);
> > +
> >  STATIC
> >  EFI_STATUS
> >  SpiFlashProbe (
> > @@ -109,6 +134,156 @@ SpiFlashProbe (
> >    return EFI_SUCCESS;
> >  }
> >
> > +/**
> > +  Verify if selected device is valid for the firmware update.
> > +
> > +  @param[in]   Handle            Handle of verified device
> > +  @param[in]   Offset            [OPTIONAL] Additional parameter
> > +                                 required for BlkIo->WriteBlocks,
> > +                                 filled depending on detected device
> > +                                 type.
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +IsDeviceSupported (
> > +  IN  EFI_HANDLE   Handle,
> > +  OUT EFI_LBA     *Offset OPTIONAL
> > +  )
> > +{
> > +  EFI_STATUS                  Status;
> > +  EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
> > +
> > +  //
> > +  // Skip handles that do not have device path protocol
> > +  //
> > +  Status = gBS->OpenProtocol (Handle,
> > +                  &gEfiDevicePathProtocolGuid,
> > +                  (VOID**)&DevicePath,
> > +                  gImageHandle,
> > +                  NULL,
> > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +  if (EFI_ERROR (Status)) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  //
> > +  // Skip handles that are not block devices
> > +  //
> > +  Status = gBS->OpenProtocol (Handle,
> > +                  &gEfiBlockIoProtocolGuid,
> > +                  NULL,
> > +                  NULL,
> > +                  NULL,
> > +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
> > +  if (EFI_ERROR (Status)) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  while (!IsDevicePathEnd (DevicePath)) {
> > +    if (DevicePath->Type == MESSAGING_DEVICE_PATH) {
> > +      //
> > +      // Search for SD/MMC devices.
> > +      //
> > +      if (DevicePath->SubType == MSG_SD_DP) {
> > +        //
> > +        // Only flashing in the beginning of SD card makes sense.
> > +        //
> > +        DevicePath = NextDevicePathNode (DevicePath);
> > +        if (!IsDevicePathEnd (DevicePath)) {
> > +          return EFI_UNSUPPORTED;
> > +        }
> > +        if (Offset != NULL) {
> > +          *Offset = 1;
> > +        }
> > +        return EFI_SUCCESS;
> > +      }
> > +      if (DevicePath->SubType == MSG_EMMC_DP) {
> > +        //
> > +        // Filter out entire MMC device (ctrl(0x0))
> > +        // and boot partitions (ctrl(0x1)/ctrl(0x2)) as valid for
> > +        // the firmware update.
> > +        //
> > +        DevicePath = NextDevicePathNode (DevicePath);
> > +        if (IsDevicePathEnd (DevicePath)) {
> > +          return EFI_UNSUPPORTED;
> > +        }
> > +        DevicePath = NextDevicePathNode (DevicePath);
> > +        if (!IsDevicePathEnd (DevicePath)) {
> > +          return EFI_UNSUPPORTED;
> > +        }
> > +        if (Offset != NULL) {
> > +          *Offset = 0;
> > +        }
> > +        return EFI_SUCCESS;
> > +      }
> > +    }
> > +    DevicePath = NextDevicePathNode (DevicePath);
> > +  }
> > +
> > +  return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > +  Print information about single device supporting the firmware update.
> > +
> > +  @param[in]   Handle            Handle of verified device
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +PrintSupportedDevice (
> > +  IN EFI_HANDLE  Handle
> > +  )
> > +{
> > +  CHAR16         *Name;
> > +
> > +  gEfiShellProtocol->GetDeviceName (Handle,
> > +    EFI_DEVICE_NAME_USE_DEVICE_PATH,
> > +    NULL,
> > +    &Name);
> > +  if (Name != NULL) {
> > +    ShellPrintEx (-1,
> > +      -1,
> > +      L"%H%02x%N      %s\n",
> > +      ConvertHandleToHandleIndex (Handle),
> > +      Name);
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Print information about all devices supporting the firmware update.
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +ListSupportedDevices (
> > +  )
> > +{
> > +  UINTN          LoopVar;
> > +  EFI_HANDLE     Handle;
> > +  EFI_STATUS     Status;
> > +
> > +  ShellPrintEx (-1, -1, L"%BHandle  Path%N\n");
> > +  ShellPrintEx (-1, -1, L"%Hspi%N     spi\n");
> > +
> > +  for (LoopVar = 1; ; LoopVar++) {
> > +    Handle = ConvertHandleIndexToHandle (LoopVar);
> > +    if (Handle == NULL) {
> > +      break;
> > +    }
> > +
> > +    Status = IsDeviceSupported (Handle, NULL);
> > +    if (!EFI_ERROR (Status)) {
> > +      PrintSupportedDevice (Handle);
> > +    }
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> >  STATIC
> >  EFI_STATUS
> >  CheckImageHeader (
> > @@ -149,13 +324,15 @@ PrepareFirmwareImage (
> >    IN LIST_ENTRY             *CheckPackage,
> >    IN OUT SHELL_FILE_HANDLE  *FileHandle,
> >    IN OUT UINTN              **FileBuffer,
> > -  IN OUT UINT64             *FileSize
> > +  IN OUT UINT64             *FileSize,
> > +  IN UINT64                 Alignment
> >    )
> >  {
> >    CONST CHAR16         *FileStr;
> >    EFI_STATUS           Status;
> >    UINT64               OpenMode;
> >    UINTN                *Buffer;
> > +  UINTN                AlignedFileSize;
> >
> >    // Parse string from commandline
> >    FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
> > @@ -184,8 +361,20 @@ PrepareFirmwareImage (
> >        Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING);
> >      }
> >
> > +  // Allocate aligned buffer in case of updating firmware in a BlockDevice
> > +  if (Alignment > 0) {
> > +    AlignedFileSize = *FileSize + (Alignment - (*FileSize % Alignment));
> > +  } else {
> > +    AlignedFileSize = *FileSize;
> > +  }
> > +
> >    // Read Image header into buffer
> > -  Buffer = AllocateZeroPool (*FileSize);
> > +  Buffer = AllocateZeroPool (AlignedFileSize);
> > +  if (Buffer == NULL) {
> > +    Print (L"%s: Fail to allocate buffer\n", CMD_NAME_STRING);
> > +    ShellCloseFile (FileHandle);
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> >
> >    Status = FileHandleRead (*FileHandle, (UINTN *)FileSize, Buffer);
> >    if (EFI_ERROR (Status)) {
> > @@ -196,6 +385,233 @@ PrepareFirmwareImage (
> >    }
> >
> >    *FileBuffer = Buffer;
> > +  *FileSize = AlignedFileSize;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Update firmware image in the block device.
> > +
> > +  @param[in]   FileSize            Size of the file to be flashed
> > +  @param[in]  *FileBuffer          Pointer to the file in memory
> > +  @param[in]   Offset              First logical block to be updated.
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +EFIAPI
> > +ProgramBlockDevice (
> > +  IN UINT64      FileSize,
> > +  IN UINTN      *FileBuffer,
> > +  IN EFI_LBA     Offset
> > +  )
> > +{
> > +  EFI_STATUS     Status;
> > +
> > +  Print (L"Updating image in BlockDevice\n");
> > +
> > +  Status = BlkIo->WriteBlocks (BlkIo,
> > +                    BlkIo->Media->MediaId,
> > +                    Offset,
> > +                    FileSize,
> > +                    FileBuffer);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Cannot write to device (Status: %r)\n",
> > +      CMD_NAME_STRING,
> > +      Status);
> > +    return Status;
> > +  }
> > +
> > +  Status = BlkIo->FlushBlocks (BlkIo);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Cannot flush to device (Status: %r)\n",
> > +      CMD_NAME_STRING,
> > +      Status);
> > +    return Status;
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > +  Update firmware image in the SPI flash.
> > +
> > +  @param[in]   FileSize            Size of the file to be flashed
> > +  @param[in]  *FileBuffer          Pointer to the file in memory
> > +  @param[in]   Offset              First logical block to be updated.
> > +                                   Irrelevant for SPI.
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +EFIAPI
> > +ProgramSpiFlash (
> > +  IN UINT64      FileSize,
> > +  IN UINTN      *FileBuffer,
> > +  IN EFI_LBA     Offset
> > +  )
> > +{
> > +  SPI_DEVICE    *SpiFlash;
> > +  EFI_STATUS     Status;
> > +
> > +  // Locate SPI protocols
> > +  Status = gBS->LocateProtocol (&gMarvellSpiFlashProtocolGuid,
> > +                  NULL,
> > +                  (VOID **)&SpiFlashProtocol);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
> > +    return Status;
> > +  }
> > +
> > +  Status = gBS->LocateProtocol (&gMarvellSpiMasterProtocolGuid,
> > +                  NULL,
> > +                  (VOID **)&SpiMasterProtocol);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
> > +    return Status;
> > +  }
> > +
> > +  // Setup and probe SPI flash
> > +  SpiFlash = NULL;
> > +  SpiFlash = SpiMasterProtocol->SetupDevice (SpiMasterProtocol,
> > +                                  SpiFlash,
> > +                                  PcdGet32 (PcdSpiFlashCs),
> > +                                  PcdGet32 (PcdSpiFlashMode));
> > +  if (SpiFlash == NULL) {
> > +    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
> > +    return EFI_ABORTED;
> > +  }
> > +
> > +  Status = SpiFlashProbe (SpiFlash);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
> > +    goto FlashProbeError;
> > +  }
> > +
> > +  // Update firmware image in flash at offset 0x0
> > +  Status = SpiFlashProtocol->Update (SpiFlash,
> > +                               0x0,
> > +                               FileSize,
> > +                               (UINT8 *)FileBuffer);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
> > +    goto FlashProbeError;
> > +  }
> > +
> > +  // Release resources
> > +  SpiMasterProtocol->FreeDevice (SpiFlash);
> > +
> > +  return EFI_SUCCESS;
> > +
> > +FlashProbeError:
> > +  SpiMasterProtocol->FreeDevice (SpiFlash);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Parse commandline parameters and pick device for the firmware update.
> > +
> > +  @param[in]     *CheckPackage        Shell command argument list.
> > +  @param[in/out] *FlashCommand        Pointer to firmware update command.
> > +                                      Picked, depending on the device type.
> > +  @param[in/out] *Alignment           File buffer alignment value.
> > +  @param[in/out] *Offset              First logical block to be updated.
> > +
> > +**/
> > +STATIC
> > +EFI_STATUS
> > +EFIAPI
> > +SelectDevice (
> > +  IN LIST_ENTRY             *CheckPackage,
> > +  IN OUT FLASH_COMMAND      *FlashCommand,
> > +  IN OUT UINT64             *Alignment,
> > +  IN OUT EFI_LBA            *Offset
> > +  )
> > +{
> > +  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
> > +  CONST CHAR16              *DeviceName;
> > +  EFI_HANDLE                Handle;
> > +  UINTN                     HandleIndex;
> > +  EFI_STATUS                Status;
> > +
> > +  //
> > +  // SPI flash
> > +  //
> > +  DeviceName = ShellCommandLineGetRawValue (CheckPackage, 2);
> > +  if (DeviceName == NULL || StrnCmp(DeviceName, L"spi", 4) == 0) {
> > +    *FlashCommand = ProgramSpiFlash;
> > +    *Alignment = 0;
> > +    *Offset = 0;
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_USE_DEVICE_PATH_PARAM)) {
> > +    //
> > +    // SD/MMC is selected using device path string.
> > +    //
> > +    Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid,
> > +                    NULL,
> > +                    (VOID **)&EfiDevicePathFromTextProtocol);
> > +    if (EFI_ERROR (Status)) {
> > +      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
> > +        CMD_NAME_STRING);
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DeviceName);
> > +    if (DevicePath == NULL) {
> > +      Print (L"%s: cannot locate EfiDevicePathFromText protocol\n",
> > +        CMD_NAME_STRING);
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
> > +                    &DevicePath,
> > +                    &Handle);
> > +    if (EFI_ERROR (Status)) {
> > +      Print (L"%s: cannot locate selected block device\n", CMD_NAME_STRING);
> > +      return Status;
> > +    }
> > +  } else {
> > +    //
> > +    // SD/MMC device is selected using handle number.
> > +    //
> > +    HandleIndex = ShellHexStrToUintn (DeviceName);
> > +    if (HandleIndex == (UINTN)(-1)) {
> > +      Print (L"%s: handle to device have to be hex number\n", CMD_NAME_STRING);
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    Handle = ConvertHandleIndexToHandle (HandleIndex);
> > +    if (Handle == NULL) {
> > +      Print (L"%s: %x is not correct device handle\n",
> > +        CMD_NAME_STRING,
> > +        HandleIndex);
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +  }
> > +
> > +  Status = IsDeviceSupported (Handle, Offset);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: device not supported\n", CMD_NAME_STRING);
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  Status = gBS->OpenProtocol (Handle,
> > +                  &gEfiBlockIoProtocolGuid,
> > +                  (VOID**)&BlkIo,
> > +                  gImageHandle,
> > +                  NULL,
> > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +  if (EFI_ERROR (Status)) {
> > +    Print (L"%s: Cannot open device BlokIo protocol\n", CMD_NAME_STRING);
> > +    return Status;
> > +  }
> > +  *FlashCommand = ProgramBlockDevice;
> > +  *Alignment = BlkIo->Media->BlockSize;
> >
> >    return EFI_SUCCESS;
> >  }
> > @@ -222,11 +638,23 @@ FUpdateUsage (
> >    )
> >  {
> >    Print (L"\nFirmware update command\n"
> > -         "fupdate <LocalFilePath>\n\n"
> > +         "fupdate <LocalFilePath> [-p] [Device]\n\n"
> >           "LocalFilePath - path to local firmware image file\n"
> > -         "Example:\n"
> > -         "Update firmware from file fs2:flash-image.bin\n"
> > -         "  fupdate fs2:flash-image.bin\n"
> > +         "-p            - When flag is selected Device is interpreted\n"
> > +         "                as device path, not device handle.\n"
> > +         "Device        - Select device which will be flashed.\n"
> > +         "                Supported devices can be listed using \"fupdate list\"\n"
> > +         "                command. Device is represented by its handle.\n"
> > +         "                The default value is spi.\n"
> > +         "EXAMPLES:\n"
> > +         " * Update firmware in SPI flash from file fs2:flash-image.bin\n"
> > +         "     fupdate fs2:flash-image.bin\n"
> > +         " * Update firmware in device with handle 5F from file flash-image.bin\n"
> > +         "     fupdate flash-image.bin 5F\n"
> > +         " * Update firmware in device with selected path from file flash.bin\n"
> > +         "     fupdate flash.bin -p VenHw(0D51905B-B77E-452A-A2C0-ECA0CC8D514A,000078F20000000000)/SD(0x0)\n"
> > +         " * List supported devices\n"
> > +         "     fupdate list\n"
> >    );
> >  }
> >
> > @@ -238,36 +666,17 @@ ShellCommandRunFUpdate (
> >    IN EFI_SYSTEM_TABLE  *SystemTable
> >    )
> >  {
> > -  IN SHELL_FILE_HANDLE    FileHandle;
> > -  SPI_DEVICE              *Slave = NULL;
> > -  UINT64                  FileSize;
> > -  UINTN                   *FileBuffer = NULL;
> > -  CHAR16                  *ProblemParam;
> > -  LIST_ENTRY              *CheckPackage;
> > -  EFI_STATUS              Status;
> > -
> > -  // Locate SPI protocols
> > -  Status = gBS->LocateProtocol (
> > -                   &gMarvellSpiFlashProtocolGuid,
> > -                   NULL,
> > -                   (VOID **)&SpiFlashProtocol
> > -                 );
> > -
> > -  if (EFI_ERROR(Status)) {
> > -    Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
> > -    return SHELL_ABORTED;
> > -  }
> > -
> > -  Status = gBS->LocateProtocol (
> > -                   &gMarvellSpiMasterProtocolGuid,
> > -                   NULL,
> > -                   (VOID **)&SpiMasterProtocol
> > -                 );
> > -
> > -  if (EFI_ERROR(Status)) {
> > -    Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
> > -    return SHELL_ABORTED;
> > -  }
> > +  SHELL_FILE_HANDLE  FileHandle;
> > +  FLASH_COMMAND      FlashCommand;
> > +  LIST_ENTRY         *CheckPackage;
> > +  EFI_LBA            Offset;
> > +  UINT64             Alignment;
> > +  UINT64             FileSize;
> > +  UINTN              *FileBuffer;
> > +  CHAR16             *ProblemParam;
> > +  EFI_STATUS         Status;
> > +
> > +  FileBuffer = NULL;
> >
> >    // Parse command line
> >    Status = ShellInitialize ();
> > @@ -283,14 +692,29 @@ ShellCommandRunFUpdate (
> >      return SHELL_ABORTED;
> >    }
> >
> > -  if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
> > -    FUpdateUsage();
> > +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_HELP_PARAM)) {
> > +    FUpdateUsage ();
> >      return EFI_SUCCESS;
> >    }
> >
> > +  if (ShellCommandLineGetFlag (CheckPackage, SHELL_LIST_PARAM)) {
> > +    ListSupportedDevices ();
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  // Select device to flash
> > +  Status = SelectDevice (CheckPackage, &FlashCommand, &Alignment, &Offset);
> > +  if (EFI_ERROR (Status)) {
> > +    return SHELL_ABORTED;
> > +  }
> > +
> >    // Prepare local file to be burned into flash
> > -  Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize);
> > -  if (EFI_ERROR(Status)) {
> > +  Status = PrepareFirmwareImage (CheckPackage,
> > +             &FileHandle,
> > +             &FileBuffer,
> > +             &FileSize,
> > +             Alignment);
> > +  if (EFI_ERROR (Status)) {
> >      return SHELL_ABORTED;
> >    }
> >
> > @@ -300,38 +724,22 @@ ShellCommandRunFUpdate (
> >      goto HeaderError;
> >    }
> >
> > -  // Setup and probe SPI flash
> > -  Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, Slave, 0, 0);
> > -  if (Slave == NULL) {
> > -    Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
> > +  // Update firmware image
> > +  Status = FlashCommand (FileSize, FileBuffer, Offset);
> > +  if (EFI_ERROR (Status)) {
> >      goto HeaderError;
> >    }
> >
> > -  Status = SpiFlashProbe (Slave);
> > -  if (EFI_ERROR(Status)) {
> > -    Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
> > -    goto FlashProbeError;
> > -  }
> > -
> > -  // Update firmware image in flash at offset 0x0
> > -  Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer);
> > -
> > -  // Release resources
> > -  SpiMasterProtocol->FreeDevice(Slave);
> >    FreePool (FileBuffer);
> >    ShellCloseFile (&FileHandle);
> >
> > -  if (EFI_ERROR(Status)) {
> > -    Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
> > -    return SHELL_ABORTED;
> > -  }
> > -
> > -  Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize);
> > +  Print (L"%s: Update %d bytes at offset 0x%x succeeded!\n",
> > +    CMD_NAME_STRING,
> > +    FileSize,
> > +    Offset * Alignment);
> >
> >    return EFI_SUCCESS;
> >
> > -FlashProbeError:
> > -  SpiMasterProtocol->FreeDevice(Slave);
> >  HeaderError:
> >    FreePool (FileBuffer);
> >    ShellCloseFile (&FileHandle);
> > diff --git a/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni b/Silicon/Marvell/Applications/FirmwareUpdate/FUpdate.uni
> > index 146f624737d96e2cd354857dbb63390ebe2f347e..3ea892aa2a982827ad235c505270acbca21ea27b 100644
> > GIT binary patch
> > delta 1093
> > zcmah|(P|Sx6g@$uNPXDuTB`)<=u@MnS*4*0zNBf3VttT^MNE-2v2I|EF`G2{<TuDg
> > z@FxU|U!V{Ehai3S*(cAP$>^GjGVIKqnRDmfd(Pc2ONT2TJ_kjEM<}C@9jLXAC)h_9
> > zZLT}=DaZ<asm?V{7{$ofs3`Hw@rPw%w~-LjqqT<=Ej*>wMaDVfdCISiA?FTH@~?VS
> > zm%e&GVC(@`i<K8aB;TU5@;y4Gk!mgbVu$xWD?@yX=mb~zau3gG8%D_^5+Zs$V-|7{
> > zEzIWP%e`n}L-TLY!)H0|Kj!PoK|<V^R?1<pOAlXdhD6?zjl<}S&-HEtBj(m;Mgvz3
> > z(fPcTo3_o&zm;0XJWC_is;nrJO?eYUv;Mw`i_^?(w;AUdhpTj%KDjEnb6O~~j$c*9
> > zF|La2;+4e=Ex%KI<*TaPw>rB@_84tME|l?o+9`L+iPyc4F8Q99A3-4R=9=u9OE7XW
> > zxFDy)q+nzm-uZo2(OUmx$g!>38h*bt<gSWMxg4I8tuUT9+^Y`Cc84hC&&cg?k#8%G
> > zJ#=gmxBBlGM?2N_mXyNcjP|su{5U-S`mYfueNPOQ$)}5?f0Dri%k?ex&JtqkQpHu=
> > zpjE{h|D!dma%|9A;mI}BXw|sZi74~D&Rxv8j_c0%CV@4!dpsGdyx63J-{;p7Ds1g_
> > m8~7y=C8eW6I<RGBQt7h)HLCh7x}uK|P0>~E;m3pUZQ&;(bkkG-
> >
> > delta 54
> > zcmV-60LlO6G{z{f!Vr_v7#NfG5Ly9HlTi^<liCz)lL`<ZlP(tqlX4Yelf)Jhlk62V
> > MlkN}*v+5Xp0aXzc(f|Me
> >
> > --
> > 2.7.4
> >

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-05-02 14:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-02 11:31 [PATCH] Marvell/Applications: FirmwareUpdate: Enable burning image on SD/MMC Marcin Wojtas
2019-05-02 12:57 ` Ard Biesheuvel
2019-05-02 14:31   ` Marcin Wojtas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox