1/******************************************************************************* 2Copyright (C) 2016 Marvell International Ltd. 3 4Marvell BSD License Option 5 6If you received this File from Marvell, you may opt to use, redistribute and/or 7modify this File under the following licensing terms. 8Redistribution and use in source and binary forms, with or without modification, 9are 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 22THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29ANY 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 31SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33*******************************************************************************/ 34#include <Uefi.h> 35#include <ShellBase.h> 36 37#include <Library/BaseLib.h> 38#include <Library/BaseMemoryLib.h> 39#include <Library/DebugLib.h> 40#include <Library/MemoryAllocationLib.h> 41#include <Library/ShellCommandLib.h> 42#include <Library/ShellLib.h> 43#include <Library/UefiLib.h> 44#include <Library/UefiBootServicesTableLib.h> 45#include <Library/PrintLib.h> 46#include <Library/ShellCEntryLib.h> 47#include <Library/HiiLib.h> 48#include <Library/FileHandleLib.h> 49 50#include <Protocol/Spi.h> 51#include <Protocol/SpiFlash.h> 52 53MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol; 54MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol; 55 56CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand"; 57EFI_HANDLE gShellSfHiiHandle = NULL; 58 59BOOLEAN InitFlag = 1; 60 61STATIC CONST SHELL_PARAM_ITEM ParamList[] = { 62 {L"read", TypeFlag}, 63 {L"readfile", TypeFlag}, 64 {L"write", TypeFlag}, 65 {L"writefile", TypeFlag}, 66 {L"erase", TypeFlag}, 67 {L"update", TypeFlag}, 68 {L"updatefile", TypeFlag}, 69 {L"probe", TypeFlag}, 70 {L"help", TypeFlag}, 71 {NULL , TypeMax} 72 }; 73 74typedef enum { 75 PROBE = 1, 76 READ = 2, 77 READ_FILE = 4, 78 WRITE = 8, 79 WRITE_FILE = 16, 80 ERASE = 32, 81 UPDATE = 64, 82 UPDATE_FILE = 128, 83} Flags; 84 85/** 86 Return the file name of the help text file if not using HII. 87 88 @return The string pointer to the file name. 89**/ 90CONST CHAR16* 91EFIAPI 92ShellCommandGetManFileNameSpiFlash ( 93 VOID 94 ) 95{ 96 97 return gShellSpiFlashFileName; 98} 99 100VOID 101SfUsage ( 102 VOID 103 ) 104{ 105 Print (L"\nBasic SPI command\n" 106 "sf [probe | read | readfile | write | writefile | erase |" 107 "update | updatefile]" 108 "[<Address> | <FilePath>] <Offset> <Length>\n\n" 109 "Length - Number of bytes to send\n" 110 "Address - Address in RAM to store/load data\n" 111 "FilePath - Path to file to read/write data from/to\n" 112 "Offset - Offset from beggining of SPI flash to store/load data\n" 113 "Examples:\n" 114 "Check if there is response from SPI flash\n" 115 " sf probe\n" 116 "Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\n" 117 " sf read 0x100000 0xe00000 32\n" 118 "Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\n" 119 " sf read 0x300000 0x200000 0x20\n" 120 "Erase 0x10000 bytes from offset 0x100000 of SPI flash\n" 121 " sf erase 0x100000 0x100000\n" 122 "Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\n" 123 " sf write 0x200000 0x4000000 16\n" 124 "Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\n" 125 " sf update 0x100000 0xe00000 100\n" 126 "Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\n" 127 " sf readfile fs2:file.bin 0x0 0x3000 \n" 128 "Update data in SPI flash at 0x3000000 from file Linux.efi\n" 129 " sf updatefile Linux.efi 0x3000000\n" 130 ); 131} 132 133STATIC 134EFI_STATUS 135OpenAndPrepareFile ( 136 IN CHAR16 *FilePath, 137 SHELL_FILE_HANDLE *FileHandle 138 ) 139{ 140 EFI_STATUS Status; 141 UINT64 OpenMode; 142 143 OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE; 144 145 Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0); 146 if (EFI_ERROR (Status)) { 147 Print (L"sf: Cannot open file\n"); 148 return Status; 149 } 150 151 Status = FileHandleSetPosition(*FileHandle, 0); 152 153 if (EFI_ERROR(Status)) { 154 Print (L"sf: Cannot set file position to first byte\n"); 155 ShellCloseFile (FileHandle); 156 return Status; 157 } 158 159 return EFI_SUCCESS; 160} 161 162STATIC 163EFI_STATUS 164FlashProbe ( 165 IN SPI_DEVICE *Slave 166 ) 167{ 168 EFI_STATUS Status; 169 UINT8 IdBuffer[4]; 170 UINT32 Id, RefId; 171 172 Id = PcdGet32 (PcdSpiFlashId); 173 174 IdBuffer[0] = CMD_READ_ID; 175 176 SpiFlashProtocol->ReadId ( 177 Slave, 178 4, 179 IdBuffer 180 ); 181 182 RefId = (IdBuffer[0] << 16) + (IdBuffer[1] << 8) + IdBuffer[2]; 183 184 if (RefId == Id) { 185 Print (L"sf: Detected supported SPI flash with ID=%3x\n", RefId); 186 Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave); 187 if (EFI_ERROR(Status)) { 188 Print (L"sf: Cannot initialize flash device\n"); 189 return SHELL_ABORTED; 190 } 191 InitFlag = 0; 192 return EFI_SUCCESS; 193 } else if (RefId != 0) { 194 Print (L"sf: Unsupported SPI flash detected with ID=%2x\n", RefId); 195 return SHELL_ABORTED; 196 } 197 198 Print (L"sf: No SPI flash detected"); 199 return SHELL_ABORTED; 200} 201 202SHELL_STATUS 203EFIAPI 204ShellCommandRunSpiFlash ( 205 IN EFI_HANDLE ImageHandle, 206 IN EFI_SYSTEM_TABLE *SystemTable 207 ) 208{ 209EFI_STATUS Status; 210 SPI_DEVICE *Slave; 211 LIST_ENTRY *CheckPackage; 212 EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0; 213 SHELL_FILE_HANDLE FileHandle = NULL; 214 UINTN ByteCount, FileSize, I; 215 UINT8 *Buffer = NULL, *FileBuffer = NULL; 216 CHAR16 *ProblemParam, *FilePath; 217 CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL; 218 CONST CHAR16 *LengthStr = NULL, *FileStr = NULL; 219 BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE; 220 UINT8 Flag = 0, CheckFlag = 0; 221 222 Status = gBS->LocateProtocol ( 223 &gMarvellSpiFlashProtocolGuid, 224 NULL, 225 (VOID **)&SpiFlashProtocol 226 ); 227 if (EFI_ERROR(Status)) { 228 Print (L"sf: Cannot locate SpiFlash protocol\n"); 229 return SHELL_ABORTED; 230 } 231 232 Status = gBS->LocateProtocol ( 233 &gMarvellSpiMasterProtocolGuid, 234 NULL, 235 (VOID **)&SpiMasterProtocol 236 ); 237 if (EFI_ERROR(Status)) { 238 Print (L"sf: Cannot locate SpiMaster protocol\n"); 239 return SHELL_ABORTED; 240 } 241 242 // Parse Shell command line 243 Status = ShellInitialize (); 244 if (EFI_ERROR (Status)) { 245 Print (L"sf: Cannot initialize Shell\n"); 246 ASSERT_EFI_ERROR (Status); 247 return SHELL_ABORTED; 248 } 249 250 Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); 251 if (EFI_ERROR (Status)) { 252 Print (L"sf: Error while parsing command line\n"); 253 return SHELL_ABORTED; 254 } 255 256 if (ShellCommandLineGetFlag (CheckPackage, L"help")) { 257 SfUsage(); 258 return EFI_SUCCESS; 259 } 260 261 // Check flags provided by user 262 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"probe") << 0); 263 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 1); 264 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 2); 265 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 3); 266 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 4); 267 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"erase") << 5); 268 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"update") << 6); 269 Flag |= (ShellCommandLineGetFlag (CheckPackage, L"updatefile") << 7); 270 271 if (InitFlag && !(Flag & PROBE)) { 272 Print (L"Please run sf probe\n"); 273 return EFI_SUCCESS; 274 } 275 276 CheckFlag = Flag; 277 for (I = 0; CheckFlag; CheckFlag >>= 1) { 278 I += CheckFlag & 1; 279 if (I > 1) { 280 Print (L"sf: Too many flags\n"); 281 SfUsage(); 282 return SHELL_ABORTED; 283 } 284 } 285 286 // Setup new spi device 287 Slave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, 0, 0); 288 if (Slave == NULL) { 289 Print(L"sf: Cannot allocate SPI device!\n"); 290 return SHELL_ABORTED; 291 } 292 293 switch (Flag) { 294 case PROBE: 295 // Probe spi bus 296 Status = FlashProbe (Slave); 297 if (EFI_ERROR(Status)) { 298 // No supported spi flash detected 299 return SHELL_ABORTED; 300 } else { 301 return Status; 302 } 303 break; 304 // Fall through 305 case READ: 306 case WRITE: 307 case UPDATE: 308 AddressStr = ShellCommandLineGetRawValue (CheckPackage, 1); 309 OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); 310 LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); 311 AddrFlag = TRUE; 312 break; 313 case ERASE: 314 OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 1); 315 LengthStr = ShellCommandLineGetRawValue (CheckPackage, 2); 316 break; 317 case READ_FILE: 318 FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); 319 OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); 320 LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); 321 FileFlag = TRUE; 322 break; 323 case WRITE_FILE: 324 case UPDATE_FILE: 325 FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); 326 OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); 327 LengthFlag = FALSE; 328 FileFlag = TRUE; 329 break; 330 } 331 332 // Read address parameter 333 if ((AddressStr == NULL) & AddrFlag) { 334 Print (L"sf: No address parameter!\n"); 335 return SHELL_ABORTED; 336 } else if (AddrFlag) { 337 Address = ShellHexStrToUintn (AddressStr); 338 if (Address == (UINTN)(-1)) { 339 Print (L"sf: Wrong address parameter\n"); 340 return SHELL_ABORTED; 341 } 342 } 343 344 // Read offset parameter 345 if (OffsetStr == NULL) { 346 Print (L"sf: No offset Parameter!\n"); 347 return SHELL_ABORTED; 348 } else { 349 Offset = ShellHexStrToUintn (OffsetStr); 350 if (Offset < 0) { 351 Print (L"sf: Wrong offset parameter: %s", OffsetStr); 352 return SHELL_ABORTED; 353 } 354 } 355 356 // Read length parameter 357 if ((LengthStr == NULL) & LengthFlag) { 358 Print (L"sf: No lenght parameter!\n"); 359 return SHELL_ABORTED; 360 } else if (LengthFlag) { 361 ByteCount = ShellStrToUintn (LengthStr); 362 if (ByteCount < 0) { 363 Print (L"sf: Wrong length parameter %s!\n", LengthStr); 364 return SHELL_ABORTED; 365 } 366 } 367 368 if (FileFlag) { 369 // Read FilePath parameter 370 if (FileStr == NULL) { 371 Print (L"sf: No FilePath parameter!\n"); 372 return SHELL_ABORTED; 373 } else { 374 FilePath = (CHAR16 *) FileStr; 375 Status = ShellIsFile (FilePath); 376 // When read file into flash, file doesn't have to exist 377 if (EFI_ERROR(Status && !(Flag & READ_FILE))) { 378 Print (L"sf: Wrong FilePath parameter!\n"); 379 return SHELL_ABORTED; 380 } 381 } 382 383 Status = OpenAndPrepareFile (FilePath, &FileHandle); 384 if (EFI_ERROR(Status)) { 385 Print (L"sf: Error while preparing file\n"); 386 return SHELL_ABORTED; 387 } 388 389 // Get file size in order to check correctness at the end of transfer 390 if (Flag & (WRITE_FILE | UPDATE_FILE)) { 391 Status = FileHandleGetSize (FileHandle, &FileSize); 392 if (EFI_ERROR (Status)) { 393 Print (L"sf: Cannot get file size\n"); 394 } 395 ByteCount = (UINTN) FileSize; 396 } 397 398 FileBuffer = AllocateZeroPool ((UINTN) ByteCount); 399 if (FileBuffer == NULL) { 400 Print (L"sf: Cannot allocate memory\n"); 401 goto Error_Close_File; 402 } 403 404 // Read file content and store it in FileBuffer 405 if (Flag & (WRITE_FILE | UPDATE_FILE)) { 406 Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer); 407 if (EFI_ERROR (Status)) { 408 Print (L"sf: Read from file error\n"); 409 goto Error_Free_Buffer; 410 } else if (ByteCount != (UINTN) FileSize) { 411 Print (L"sf: Not whole file read. Abort\n"); 412 goto Error_Free_Buffer; 413 } 414 } 415 } 416 417 Buffer = (UINT8 *) Address; 418 if (FileFlag) { 419 Buffer = FileBuffer; 420 } 421 422 switch (Flag) { 423 case READ: 424 case READ_FILE: 425 Status = SpiFlashProtocol->Read (Slave, Offset, ByteCount, Buffer); 426 break; 427 case ERASE: 428 Status = SpiFlashProtocol->Erase (Slave, Offset, ByteCount); 429 break; 430 case WRITE: 431 case WRITE_FILE: 432 Status = SpiFlashProtocol->Write (Slave, Offset, ByteCount, Buffer); 433 break; 434 case UPDATE: 435 case UPDATE_FILE: 436 Status = SpiFlashProtocol->Update (Slave, Offset, ByteCount, Buffer); 437 break; 438 } 439 440 SpiMasterProtocol->FreeDevice(Slave); 441 442 if (EFI_ERROR (Status)) { 443 Print (L"sf: Error while performing spi transfer\n"); 444 return SHELL_ABORTED; 445 } 446 447 switch (Flag) { 448 case ERASE: 449 Print (L"sf: %d bytes succesfully erased at offset 0x%x\n", ByteCount, 450 Offset); 451 break; 452 case WRITE: 453 case WRITE_FILE: 454 Print (L"sf: Write %d bytes at offset 0x%x\n", ByteCount, Offset); 455 break; 456 case UPDATE: 457 case UPDATE_FILE: 458 Print (L"sf: Update %d bytes at offset 0x%x\n", ByteCount, Offset); 459 break; 460 case READ: 461 Print (L"sf: Read %d bytes from offset 0x%x\n", ByteCount, Offset); 462 break; 463 case READ_FILE: 464 Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer); 465 if (EFI_ERROR(Status)) { 466 Print (L"sf: Error while writing into file\n"); 467 goto Error_Free_Buffer; 468 } 469 break; 470 } 471 472 if (FileFlag) { 473 FreePool (FileBuffer); 474 475 if (FileHandle != NULL) { 476 ShellCloseFile (&FileHandle); 477 } 478 } 479 480 return EFI_SUCCESS; 481 482Error_Free_Buffer: 483 FreePool (FileBuffer); 484Error_Close_File: 485 ShellCloseFile (&FileHandle); 486 return SHELL_ABORTED; 487} 488 489EFI_STATUS 490EFIAPI 491ShellSpiFlashLibConstructor ( 492 IN EFI_HANDLE ImageHandle, 493 IN EFI_SYSTEM_TABLE *SystemTable 494 ) 495{ 496 gShellSfHiiHandle = NULL; 497 498 gShellSfHiiHandle = HiiAddPackages ( 499 &gShellSfHiiGuid, gImageHandle, 500 UefiShellSpiFlashLibStrings, NULL 501 ); 502 if (gShellSfHiiHandle == NULL) { 503 return EFI_DEVICE_ERROR; 504 } 505 506 ShellCommandRegisterCommandName ( 507 L"sf", ShellCommandRunSpiFlash, ShellCommandGetManFileNameSpiFlash, 0, 508 L"sf", TRUE , gShellSfHiiHandle, STRING_TOKEN (STR_GET_HELP_SF) 509 ); 510 511 return EFI_SUCCESS; 512} 513 514EFI_STATUS 515EFIAPI 516ShellSpiFlashLibDestructor ( 517 IN EFI_HANDLE ImageHandle, 518 IN EFI_SYSTEM_TABLE *SystemTable 519 ) 520{ 521 522 if (gShellSfHiiHandle != NULL) { 523 HiiRemovePackages (gShellSfHiiHandle); 524 } 525 return EFI_SUCCESS; 526} 527