Home | History | Annotate | Download | only in FirmwareUpdate
      1 /*******************************************************************************
      2 Copyright (C) 2016 Marvell International Ltd.
      3 
      4 Marvell BSD License Option
      5 
      6 If you received this File from Marvell, you may opt to use, redistribute and/or
      7 modify this File under the following licensing terms.
      8 Redistribution and use in source and binary forms, with or without modification,
      9 are permitted provided that the following conditions are met:
     10 
     11 * Redistributions of source code must retain the above copyright notice,
     12   this list of conditions and the following disclaimer.
     13 
     14 * Redistributions in binary form must reproduce the above copyright
     15   notice, this list of conditions and the following disclaimer in the
     16   documentation and/or other materials provided with the distribution.
     17 
     18 * Neither the name of Marvell nor the names of its contributors may be
     19   used to endorse or promote products derived from this software without
     20   specific prior written permission.
     21 
     22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32 
     33 *******************************************************************************/
     34 #include <ShellBase.h>
     35 #include <Uefi.h>
     36 
     37 #include <Library/BaseLib.h>
     38 #include <Library/BaseMemoryLib.h>
     39 #include <Library/DebugLib.h>
     40 #include <Library/FileHandleLib.h>
     41 #include <Library/HiiLib.h>
     42 #include <Library/MemoryAllocationLib.h>
     43 #include <Library/PrintLib.h>
     44 #include <Library/ShellCEntryLib.h>
     45 #include <Library/ShellCommandLib.h>
     46 #include <Library/ShellLib.h>
     47 #include <Library/UefiBootServicesTableLib.h>
     48 #include <Library/UefiLib.h>
     49 
     50 #include <Protocol/Spi.h>
     51 #include <Protocol/SpiFlash.h>
     52 
     53 #define CMD_NAME_STRING       L"fupdate"
     54 
     55 #define MAIN_HDR_MAGIC        0xB105B002
     56 
     57 STATIC MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
     58 STATIC MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
     59 
     60 STATIC CONST CHAR16 gShellFUpdateFileName[] = L"ShellCommands";
     61 STATIC EFI_HANDLE gShellFUpdateHiiHandle = NULL;
     62 
     63 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
     64   {L"help", TypeFlag},
     65   {NULL , TypeMax}
     66   };
     67 
     68 typedef struct {              // Bytes
     69   UINT32  Magic;              //  0-3
     70   UINT32  PrologSize;         //  4-7
     71   UINT32  PrologChecksum;     //  8-11
     72   UINT32  BootImageSize;      // 12-15
     73   UINT32  BootImageChecksum;  // 16-19
     74   UINT32  Reserved0;          // 20-23
     75   UINT32  LoadAddr;           // 24-27
     76   UINT32  ExecAddr;           // 28-31
     77   UINT8   UartConfig;         //  32
     78   UINT8   Baudrate;           //  33
     79   UINT8   ExtCount;           //  34
     80   UINT8   AuxFlags;           //  35
     81   UINT32  IoArg0;             // 36-39
     82   UINT32  IoArg1;             // 40-43
     83   UINT32  IoArg2;             // 43-47
     84   UINT32  IoArg3;             // 48-51
     85   UINT32  Reserved1;          // 52-55
     86   UINT32  Reserved2;          // 56-59
     87   UINT32  Reserved3;          // 60-63
     88 } MV_FIRMWARE_IMAGE_HEADER;
     89 
     90 STATIC
     91 EFI_STATUS
     92 SpiFlashProbe (
     93   IN SPI_DEVICE    *Slave
     94   )
     95 {
     96   EFI_STATUS       Status;
     97   UINT32           IdBuffer, Id, RefId;
     98 
     99   Id = PcdGet32 (PcdSpiFlashId);
    100 
    101   IdBuffer = CMD_READ_ID & 0xff;
    102 
    103   // Read SPI flash ID
    104   SpiFlashProtocol->ReadId (Slave, sizeof (UINT32), (UINT8 *)&IdBuffer);
    105 
    106   // Swap and extract 3 bytes of the ID
    107   RefId = SwapBytes32 (IdBuffer) >> 8;
    108 
    109   if (RefId == 0) {
    110     Print (L"%s: No SPI flash detected");
    111     return EFI_DEVICE_ERROR;
    112   } else if (RefId != Id) {
    113     Print (L"%s: Unsupported SPI flash detected with ID=%2x\n", CMD_NAME_STRING, RefId);
    114     return EFI_DEVICE_ERROR;
    115   }
    116 
    117   Print (L"%s: Detected supported SPI flash with ID=%3x\n", CMD_NAME_STRING, RefId);
    118 
    119   Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave);
    120   if (EFI_ERROR(Status)) {
    121     Print (L"%s: Cannot initialize flash device\n", CMD_NAME_STRING);
    122     return EFI_DEVICE_ERROR;
    123   }
    124 
    125   return EFI_SUCCESS;
    126 }
    127 
    128 STATIC
    129 EFI_STATUS
    130 CheckImageHeader (
    131   IN OUT UINTN *ImageHeader
    132   )
    133 {
    134   MV_FIRMWARE_IMAGE_HEADER *Header;
    135   UINT32 HeaderLength, Checksum, ChecksumBackup;
    136 
    137   Header = (MV_FIRMWARE_IMAGE_HEADER *)ImageHeader;
    138   HeaderLength = Header->PrologSize;
    139   ChecksumBackup = Header->PrologChecksum;
    140 
    141   // Compare magic number
    142   if (Header->Magic != MAIN_HDR_MAGIC) {
    143     Print (L"%s: Bad Image magic 0x%08x != 0x%08x\n", CMD_NAME_STRING, Header->Magic, MAIN_HDR_MAGIC);
    144     return EFI_DEVICE_ERROR;
    145   }
    146 
    147   // The checksum field is discarded from calculation
    148   Header->PrologChecksum = 0;
    149 
    150   Checksum = CalculateSum32 ((UINT32 *)Header, HeaderLength);
    151   if (Checksum != ChecksumBackup) {
    152     Print (L"%s: Bad Image checksum. 0x%x != 0x%x\n", CMD_NAME_STRING, Checksum, ChecksumBackup);
    153     return EFI_DEVICE_ERROR;
    154   }
    155 
    156   // Restore checksum backup
    157   Header->PrologChecksum = ChecksumBackup;
    158 
    159   return 0;
    160 }
    161 
    162 STATIC
    163 EFI_STATUS
    164 PrepareFirmwareImage (
    165   IN LIST_ENTRY             *CheckPackage,
    166   IN OUT SHELL_FILE_HANDLE  *FileHandle,
    167   IN OUT UINTN              **FileBuffer,
    168   IN OUT UINTN              *FileSize
    169   )
    170 {
    171   CONST CHAR16         *FileStr;
    172   EFI_STATUS           Status;
    173   UINT64               OpenMode;
    174   UINTN                *Buffer;
    175 
    176   // Parse string from commandline
    177   FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
    178   if (FileStr == NULL) {
    179     Print (L"%s: No image specified\n", CMD_NAME_STRING);
    180     return EFI_INVALID_PARAMETER;
    181   } else {
    182     Status = ShellIsFile (FileStr);
    183     if (EFI_ERROR(Status)) {
    184       Print (L"%s: File not found\n", CMD_NAME_STRING);
    185       return EFI_INVALID_PARAMETER;
    186     }
    187   }
    188 
    189   // Obtain file size
    190   OpenMode = EFI_FILE_MODE_READ;
    191 
    192   Status = ShellOpenFileByName (FileStr, FileHandle, OpenMode, 0);
    193     if (EFI_ERROR (Status)) {
    194       Print (L"%s: Cannot open Image file\n", CMD_NAME_STRING);
    195       return EFI_DEVICE_ERROR;
    196     }
    197 
    198   Status = FileHandleGetSize (*FileHandle, FileSize);
    199     if (EFI_ERROR (Status)) {
    200       Print (L"%s: Cannot get Image file size\n", CMD_NAME_STRING);
    201     }
    202 
    203   // Read Image header into buffer
    204   Buffer = AllocateZeroPool (*FileSize);
    205 
    206   Status = FileHandleRead (*FileHandle, FileSize, Buffer);
    207   if (EFI_ERROR (Status)) {
    208     Print (L"%s: Cannot read Image file header\n", CMD_NAME_STRING);
    209     ShellCloseFile (FileHandle);
    210     FreePool (Buffer);
    211     return EFI_DEVICE_ERROR;
    212   }
    213 
    214   *FileBuffer = Buffer;
    215 
    216   return EFI_SUCCESS;
    217 }
    218 
    219 /**
    220   Return the file name of the help text file if not using HII.
    221 
    222   @return The string pointer to the file name.
    223 **/
    224 STATIC
    225 CONST CHAR16*
    226 EFIAPI
    227 ShellCommandGetManFileNameFUpdate (
    228   VOID
    229   )
    230 {
    231   return gShellFUpdateFileName;
    232 }
    233 
    234 STATIC
    235 VOID
    236 FUpdateUsage (
    237   VOID
    238   )
    239 {
    240   Print (L"\nFirmware update command\n"
    241          "fupdate <LocalFilePath>\n\n"
    242          "LocalFilePath - path to local firmware image file\n"
    243          "Example:\n"
    244          "Update firmware from file fs2:flash-image.bin\n"
    245          "  fupdate fs2:flash-image.bin\n"
    246   );
    247 }
    248 
    249 STATIC
    250 SHELL_STATUS
    251 EFIAPI
    252 ShellCommandRunFUpdate (
    253   IN EFI_HANDLE        ImageHandle,
    254   IN EFI_SYSTEM_TABLE  *SystemTable
    255   )
    256 {
    257   IN SHELL_FILE_HANDLE    FileHandle;
    258   SPI_DEVICE              *Slave;
    259   UINTN                   FileSize;
    260   UINTN                   *FileBuffer = NULL;
    261   CHAR16                  *ProblemParam;
    262   LIST_ENTRY              *CheckPackage;
    263   EFI_STATUS              Status;
    264 
    265   // Locate SPI protocols
    266   Status = gBS->LocateProtocol (
    267                    &gMarvellSpiFlashProtocolGuid,
    268                    NULL,
    269                    (VOID **)&SpiFlashProtocol
    270                  );
    271 
    272   if (EFI_ERROR(Status)) {
    273     Print (L"%s: Cannot locate SpiFlash protocol\n", CMD_NAME_STRING);
    274     return SHELL_ABORTED;
    275   }
    276 
    277   Status = gBS->LocateProtocol (
    278                    &gMarvellSpiMasterProtocolGuid,
    279                    NULL,
    280                    (VOID **)&SpiMasterProtocol
    281                  );
    282 
    283   if (EFI_ERROR(Status)) {
    284     Print (L"%s: Cannot locate SpiMaster protocol\n", CMD_NAME_STRING);
    285     return SHELL_ABORTED;
    286   }
    287 
    288   // Parse command line
    289   Status = ShellInitialize ();
    290   if (EFI_ERROR (Status)) {
    291     Print (L"%s: Error while initializing Shell\n", CMD_NAME_STRING);
    292     ASSERT_EFI_ERROR (Status);
    293     return SHELL_ABORTED;
    294   }
    295 
    296   Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
    297   if (EFI_ERROR (Status)) {
    298     Print (L"%s: Invalid parameter\n", CMD_NAME_STRING);
    299     return SHELL_ABORTED;
    300   }
    301 
    302   if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
    303     FUpdateUsage();
    304     return EFI_SUCCESS;
    305   }
    306 
    307   // Prepare local file to be burned into flash
    308   Status = PrepareFirmwareImage (CheckPackage, &FileHandle, &FileBuffer, &FileSize);
    309   if (EFI_ERROR(Status)) {
    310     return SHELL_ABORTED;
    311   }
    312 
    313   // Check image checksum and magic
    314   Status = CheckImageHeader (FileBuffer);
    315   if (EFI_ERROR(Status)) {
    316     goto HeaderError;
    317   }
    318 
    319   // Setup and probe SPI flash
    320   Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0);
    321   if (Slave == NULL) {
    322     Print(L"%s: Cannot allocate SPI device!\n", CMD_NAME_STRING);
    323     goto HeaderError;
    324   }
    325 
    326   Status = SpiFlashProbe (Slave);
    327   if (EFI_ERROR(Status)) {
    328     Print (L"%s: Error while performing SPI flash probe\n", CMD_NAME_STRING);
    329     goto FlashProbeError;
    330   }
    331 
    332   // Update firmware image in flash at offset 0x0
    333   Status = SpiFlashProtocol->Update (Slave, 0, FileSize, (UINT8 *)FileBuffer);
    334 
    335   // Release resources
    336   SpiMasterProtocol->FreeDevice(Slave);
    337   FreePool (FileBuffer);
    338   ShellCloseFile (&FileHandle);
    339 
    340   if (EFI_ERROR(Status)) {
    341     Print (L"%s: Error while performing flash update\n", CMD_NAME_STRING);
    342     return SHELL_ABORTED;
    343   }
    344 
    345   Print (L"%s: Update %d bytes at offset 0x0 succeeded!\n", CMD_NAME_STRING, FileSize);
    346 
    347   return EFI_SUCCESS;
    348 
    349 FlashProbeError:
    350   SpiMasterProtocol->FreeDevice(Slave);
    351 HeaderError:
    352   FreePool (FileBuffer);
    353   ShellCloseFile (&FileHandle);
    354 
    355   return SHELL_ABORTED;
    356 }
    357 
    358 EFI_STATUS
    359 EFIAPI
    360 ShellFUpdateCommandConstructor (
    361   IN EFI_HANDLE        ImageHandle,
    362   IN EFI_SYSTEM_TABLE  *SystemTable
    363   )
    364 {
    365   EFI_STATUS Status;
    366 
    367   gShellFUpdateHiiHandle = NULL;
    368 
    369   gShellFUpdateHiiHandle = HiiAddPackages (
    370                                   &gShellFUpdateHiiGuid,
    371                                   gImageHandle,
    372                                   UefiShellFUpdateCommandLibStrings,
    373                                   NULL
    374                                 );
    375 
    376   if (gShellFUpdateHiiHandle == NULL) {
    377     Print (L"%s: Cannot add Hii package\n", CMD_NAME_STRING);
    378     return EFI_DEVICE_ERROR;
    379   }
    380 
    381   Status = ShellCommandRegisterCommandName (
    382                            CMD_NAME_STRING,
    383                            ShellCommandRunFUpdate,
    384                            ShellCommandGetManFileNameFUpdate,
    385                            0,
    386                            CMD_NAME_STRING,
    387                            TRUE,
    388                            gShellFUpdateHiiHandle,
    389                            STRING_TOKEN (STR_GET_HELP_FUPDATE)
    390                          );
    391 
    392   if (EFI_ERROR(Status)) {
    393     Print (L"%s: Error while registering command\n", CMD_NAME_STRING);
    394     return SHELL_ABORTED;
    395   }
    396 
    397   return EFI_SUCCESS;
    398 }
    399 
    400 EFI_STATUS
    401 EFIAPI
    402 ShellFUpdateCommandDestructor (
    403   IN EFI_HANDLE        ImageHandle,
    404   IN EFI_SYSTEM_TABLE  *SystemTable
    405   )
    406 {
    407 
    408   if (gShellFUpdateHiiHandle != NULL) {
    409     HiiRemovePackages (gShellFUpdateHiiHandle);
    410   }
    411 
    412   return EFI_SUCCESS;
    413 }
    414