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