SpiFlashCmd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*******************************************************************************
  2. Copyright (C) 2016 Marvell International Ltd.
  3. Copyright (c) 2020, Intel Corporation. All rights reserved.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. *******************************************************************************/
  6. #include <Uefi.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/BaseMemoryLib.h>
  9. #include <Library/DebugLib.h>
  10. #include <Library/MemoryAllocationLib.h>
  11. #include <Library/ShellCommandLib.h>
  12. #include <Library/ShellLib.h>
  13. #include <Library/UefiLib.h>
  14. #include <Library/UefiBootServicesTableLib.h>
  15. #include <Library/PrintLib.h>
  16. #include <Library/ShellCEntryLib.h>
  17. #include <Library/HiiLib.h>
  18. #include <Library/FileHandleLib.h>
  19. #include <Protocol/Spi.h>
  20. #include <Protocol/SpiFlash.h>
  21. MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
  22. MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
  23. CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand";
  24. EFI_HANDLE gShellSfHiiHandle = NULL;
  25. BOOLEAN InitFlag = 1;
  26. STATIC SPI_DEVICE *mSlave;
  27. STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
  28. {L"read", TypeFlag},
  29. {L"readfile", TypeFlag},
  30. {L"write", TypeFlag},
  31. {L"writefile", TypeFlag},
  32. {L"erase", TypeFlag},
  33. {L"update", TypeFlag},
  34. {L"updatefile", TypeFlag},
  35. {L"probe", TypeFlag},
  36. {L"help", TypeFlag},
  37. {NULL , TypeMax}
  38. };
  39. typedef enum {
  40. PROBE = 1,
  41. READ = 2,
  42. READ_FILE = 4,
  43. WRITE = 8,
  44. WRITE_FILE = 16,
  45. ERASE = 32,
  46. UPDATE = 64,
  47. UPDATE_FILE = 128,
  48. } Flags;
  49. /**
  50. Return the file name of the help text file if not using HII.
  51. @return The string pointer to the file name.
  52. **/
  53. CONST CHAR16*
  54. EFIAPI
  55. ShellCommandGetManFileNameSpiFlash (
  56. VOID
  57. )
  58. {
  59. return gShellSpiFlashFileName;
  60. }
  61. VOID
  62. SfUsage (
  63. VOID
  64. )
  65. {
  66. Print (L"\nBasic SPI command\n"
  67. "sf [probe | read | readfile | write | writefile | erase |"
  68. "update | updatefile]"
  69. "[<Address> | <FilePath>] <Offset> <Length>\n\n"
  70. "Length - Number of bytes to send\n"
  71. "Address - Address in RAM to store/load data\n"
  72. "FilePath - Path to file to read/write data from/to\n"
  73. "Offset - Offset from beginning of SPI flash to store/load data\n"
  74. "Examples:\n"
  75. "Check if there is response from SPI flash\n"
  76. " sf probe\n"
  77. "Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\n"
  78. " sf read 0x100000 0xe00000 32\n"
  79. "Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\n"
  80. " sf read 0x300000 0x200000 0x20\n"
  81. "Erase 0x10000 bytes from offset 0x100000 of SPI flash\n"
  82. " sf erase 0x100000 0x100000\n"
  83. "Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\n"
  84. " sf write 0x200000 0x4000000 16\n"
  85. "Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\n"
  86. " sf update 0x100000 0xe00000 100\n"
  87. "Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\n"
  88. " sf readfile fs2:file.bin 0x0 0x3000 \n"
  89. "Update data in SPI flash at 0x3000000 from file Linux.efi\n"
  90. " sf updatefile Linux.efi 0x3000000\n"
  91. );
  92. }
  93. STATIC
  94. EFI_STATUS
  95. OpenAndPrepareFile (
  96. IN CHAR16 *FilePath,
  97. SHELL_FILE_HANDLE *FileHandle
  98. )
  99. {
  100. EFI_STATUS Status;
  101. UINT64 OpenMode;
  102. OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
  103. Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0);
  104. if (EFI_ERROR (Status)) {
  105. Print (L"sf: Cannot open file\n");
  106. return Status;
  107. }
  108. Status = FileHandleSetPosition(*FileHandle, 0);
  109. if (EFI_ERROR(Status)) {
  110. Print (L"sf: Cannot set file position to first byte\n");
  111. ShellCloseFile (FileHandle);
  112. return Status;
  113. }
  114. return EFI_SUCCESS;
  115. }
  116. STATIC
  117. EFI_STATUS
  118. FlashProbe (
  119. IN SPI_DEVICE *Slave
  120. )
  121. {
  122. EFI_STATUS Status;
  123. Status = SpiFlashProtocol->ReadId (Slave, FALSE);
  124. if (EFI_ERROR (Status)) {
  125. return SHELL_ABORTED;
  126. }
  127. Status = SpiFlashProtocol->Init (SpiFlashProtocol, Slave);
  128. if (EFI_ERROR (Status)) {
  129. Print (L"sf: Cannot initialize flash device\n");
  130. return SHELL_ABORTED;
  131. }
  132. InitFlag = 0;
  133. return SHELL_SUCCESS;
  134. }
  135. SHELL_STATUS
  136. EFIAPI
  137. ShellCommandRunSpiFlash (
  138. IN EFI_HANDLE ImageHandle,
  139. IN EFI_SYSTEM_TABLE *SystemTable
  140. )
  141. {
  142. EFI_STATUS Status;
  143. LIST_ENTRY *CheckPackage;
  144. EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0;
  145. SHELL_FILE_HANDLE FileHandle = NULL;
  146. UINTN ByteCount, I;
  147. UINT64 FileSize;
  148. UINT8 *Buffer = NULL, *FileBuffer = NULL;
  149. CHAR16 *ProblemParam, *FilePath;
  150. CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL;
  151. CONST CHAR16 *LengthStr = NULL, *FileStr = NULL;
  152. BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE;
  153. UINT8 Flag = 0, CheckFlag = 0;
  154. UINT8 Mode, Cs;
  155. Status = gBS->LocateProtocol (
  156. &gMarvellSpiFlashProtocolGuid,
  157. NULL,
  158. (VOID **)&SpiFlashProtocol
  159. );
  160. if (EFI_ERROR(Status)) {
  161. Print (L"sf: Cannot locate SpiFlash protocol\n");
  162. return SHELL_ABORTED;
  163. }
  164. Status = gBS->LocateProtocol (
  165. &gMarvellSpiMasterProtocolGuid,
  166. NULL,
  167. (VOID **)&SpiMasterProtocol
  168. );
  169. if (EFI_ERROR(Status)) {
  170. Print (L"sf: Cannot locate SpiMaster protocol\n");
  171. return SHELL_ABORTED;
  172. }
  173. // Parse Shell command line
  174. Status = ShellInitialize ();
  175. if (EFI_ERROR (Status)) {
  176. Print (L"sf: Cannot initialize Shell\n");
  177. ASSERT_EFI_ERROR (Status);
  178. return SHELL_ABORTED;
  179. }
  180. Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);
  181. if (EFI_ERROR (Status)) {
  182. Print (L"sf: Error while parsing command line\n");
  183. return SHELL_ABORTED;
  184. }
  185. if (ShellCommandLineGetFlag (CheckPackage, L"help")) {
  186. SfUsage();
  187. return EFI_SUCCESS;
  188. }
  189. // Check flags provided by user
  190. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"probe") << 0);
  191. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 1);
  192. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 2);
  193. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 3);
  194. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 4);
  195. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"erase") << 5);
  196. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"update") << 6);
  197. Flag |= (ShellCommandLineGetFlag (CheckPackage, L"updatefile") << 7);
  198. if (InitFlag && !(Flag & PROBE)) {
  199. Print (L"Please run sf probe\n");
  200. return EFI_SUCCESS;
  201. }
  202. CheckFlag = Flag;
  203. for (I = 0; CheckFlag; CheckFlag >>= 1) {
  204. I += CheckFlag & 1;
  205. if (I > 1) {
  206. Print (L"sf: Too many flags\n");
  207. SfUsage();
  208. return SHELL_ABORTED;
  209. }
  210. }
  211. Mode = PcdGet32 (PcdSpiFlashMode);
  212. Cs = PcdGet32 (PcdSpiFlashCs);
  213. // Setup new spi device
  214. mSlave = SpiMasterProtocol->SetupDevice (SpiMasterProtocol, mSlave, Cs, Mode);
  215. if (mSlave == NULL) {
  216. Print(L"sf: Cannot allocate SPI device!\n");
  217. return SHELL_ABORTED;
  218. }
  219. switch (Flag) {
  220. case PROBE:
  221. // Probe spi bus
  222. Status = FlashProbe (mSlave);
  223. if (EFI_ERROR(Status)) {
  224. // No supported spi flash detected
  225. SpiMasterProtocol->FreeDevice(mSlave);
  226. mSlave = NULL;
  227. return SHELL_ABORTED;
  228. } else {
  229. return Status;
  230. }
  231. break;
  232. // Fall through
  233. case READ:
  234. case WRITE:
  235. case UPDATE:
  236. AddressStr = ShellCommandLineGetRawValue (CheckPackage, 1);
  237. OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
  238. LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3);
  239. AddrFlag = TRUE;
  240. break;
  241. case ERASE:
  242. OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 1);
  243. LengthStr = ShellCommandLineGetRawValue (CheckPackage, 2);
  244. break;
  245. case READ_FILE:
  246. FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
  247. OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
  248. LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3);
  249. FileFlag = TRUE;
  250. break;
  251. case WRITE_FILE:
  252. case UPDATE_FILE:
  253. FileStr = ShellCommandLineGetRawValue (CheckPackage, 1);
  254. OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2);
  255. LengthFlag = FALSE;
  256. FileFlag = TRUE;
  257. break;
  258. }
  259. // Read address parameter
  260. if ((AddressStr == NULL) & AddrFlag) {
  261. Print (L"sf: No address parameter!\n");
  262. return SHELL_ABORTED;
  263. } else if (AddrFlag) {
  264. Address = ShellHexStrToUintn (AddressStr);
  265. if (Address == (UINTN)(-1)) {
  266. Print (L"sf: Wrong address parameter\n");
  267. return SHELL_ABORTED;
  268. }
  269. }
  270. // Read offset parameter
  271. if (OffsetStr == NULL) {
  272. Print (L"sf: No offset Parameter!\n");
  273. return SHELL_ABORTED;
  274. } else {
  275. Offset = ShellHexStrToUintn (OffsetStr);
  276. if (Offset < 0) {
  277. Print (L"sf: Wrong offset parameter: %s", OffsetStr);
  278. return SHELL_ABORTED;
  279. }
  280. }
  281. // Read length parameter
  282. if ((LengthStr == NULL) & LengthFlag) {
  283. Print (L"sf: No lenght parameter!\n");
  284. return SHELL_ABORTED;
  285. } else if (LengthFlag) {
  286. ByteCount = ShellStrToUintn (LengthStr);
  287. if (ByteCount < 0) {
  288. Print (L"sf: Wrong length parameter %s!\n", LengthStr);
  289. return SHELL_ABORTED;
  290. }
  291. }
  292. if (FileFlag) {
  293. // Read FilePath parameter
  294. if (FileStr == NULL) {
  295. Print (L"sf: No FilePath parameter!\n");
  296. return SHELL_ABORTED;
  297. } else {
  298. FilePath = (CHAR16 *) FileStr;
  299. Status = ShellIsFile (FilePath);
  300. // When read file into flash, file doesn't have to exist
  301. if (EFI_ERROR (Status) && !(Flag & READ_FILE)) {
  302. Print (L"sf: Wrong FilePath parameter!\n");
  303. return SHELL_ABORTED;
  304. }
  305. }
  306. Status = OpenAndPrepareFile (FilePath, &FileHandle);
  307. if (EFI_ERROR(Status)) {
  308. Print (L"sf: Error while preparing file\n");
  309. return SHELL_ABORTED;
  310. }
  311. // Get file size in order to check correctness at the end of transfer
  312. if (Flag & (WRITE_FILE | UPDATE_FILE)) {
  313. Status = FileHandleGetSize (FileHandle, &FileSize);
  314. if (EFI_ERROR (Status)) {
  315. Print (L"sf: Cannot get file size\n");
  316. }
  317. ByteCount = (UINTN) FileSize;
  318. }
  319. FileBuffer = AllocateZeroPool ((UINTN) ByteCount);
  320. if (FileBuffer == NULL) {
  321. Print (L"sf: Cannot allocate memory\n");
  322. goto Error_Close_File;
  323. }
  324. // Read file content and store it in FileBuffer
  325. if (Flag & (WRITE_FILE | UPDATE_FILE)) {
  326. Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer);
  327. if (EFI_ERROR (Status)) {
  328. Print (L"sf: Read from file error\n");
  329. goto Error_Free_Buffer;
  330. } else if (ByteCount != (UINTN) FileSize) {
  331. Print (L"sf: Not whole file read. Abort\n");
  332. goto Error_Free_Buffer;
  333. }
  334. }
  335. }
  336. Buffer = (UINT8 *)(UINTN)Address;
  337. if (FileFlag) {
  338. Buffer = FileBuffer;
  339. }
  340. switch (Flag) {
  341. case READ:
  342. case READ_FILE:
  343. Status = SpiFlashProtocol->Read (mSlave, Offset, ByteCount, Buffer);
  344. break;
  345. case ERASE:
  346. Status = SpiFlashProtocol->Erase (mSlave, Offset, ByteCount);
  347. break;
  348. case WRITE:
  349. case WRITE_FILE:
  350. Status = SpiFlashProtocol->Write (mSlave, Offset, ByteCount, Buffer);
  351. break;
  352. case UPDATE:
  353. case UPDATE_FILE:
  354. Status = SpiFlashProtocol->Update (mSlave, Offset, ByteCount, Buffer);
  355. break;
  356. }
  357. if (EFI_ERROR (Status)) {
  358. Print (L"sf: Error while performing spi transfer\n");
  359. return SHELL_ABORTED;
  360. }
  361. switch (Flag) {
  362. case ERASE:
  363. Print (L"sf: %d bytes succesfully erased at offset 0x%x\n", ByteCount,
  364. Offset);
  365. break;
  366. case WRITE:
  367. case WRITE_FILE:
  368. Print (L"sf: Write %d bytes at offset 0x%x\n", ByteCount, Offset);
  369. break;
  370. case UPDATE:
  371. case UPDATE_FILE:
  372. Print (L"sf: Update %d bytes at offset 0x%x\n", ByteCount, Offset);
  373. break;
  374. case READ:
  375. Print (L"sf: Read %d bytes from offset 0x%x\n", ByteCount, Offset);
  376. break;
  377. case READ_FILE:
  378. Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer);
  379. if (EFI_ERROR(Status)) {
  380. Print (L"sf: Error while writing into file\n");
  381. goto Error_Free_Buffer;
  382. }
  383. break;
  384. }
  385. if (FileFlag) {
  386. FreePool (FileBuffer);
  387. if (FileHandle != NULL) {
  388. ShellCloseFile (&FileHandle);
  389. }
  390. }
  391. return EFI_SUCCESS;
  392. Error_Free_Buffer:
  393. FreePool (FileBuffer);
  394. Error_Close_File:
  395. ShellCloseFile (&FileHandle);
  396. return SHELL_ABORTED;
  397. }
  398. EFI_STATUS
  399. EFIAPI
  400. ShellSpiFlashLibConstructor (
  401. IN EFI_HANDLE ImageHandle,
  402. IN EFI_SYSTEM_TABLE *SystemTable
  403. )
  404. {
  405. gShellSfHiiHandle = NULL;
  406. gShellSfHiiHandle = HiiAddPackages (
  407. &gShellSfHiiGuid, gImageHandle,
  408. UefiShellSpiFlashLibStrings, NULL
  409. );
  410. if (gShellSfHiiHandle == NULL) {
  411. return EFI_DEVICE_ERROR;
  412. }
  413. ShellCommandRegisterCommandName (
  414. L"sf", ShellCommandRunSpiFlash, ShellCommandGetManFileNameSpiFlash, 0,
  415. L"sf", TRUE , gShellSfHiiHandle, STRING_TOKEN (STR_GET_HELP_SF)
  416. );
  417. return EFI_SUCCESS;
  418. }
  419. EFI_STATUS
  420. EFIAPI
  421. ShellSpiFlashLibDestructor (
  422. IN EFI_HANDLE ImageHandle,
  423. IN EFI_SYSTEM_TABLE *SystemTable
  424. )
  425. {
  426. if (gShellSfHiiHandle != NULL) {
  427. HiiRemovePackages (gShellSfHiiHandle);
  428. }
  429. return EFI_SUCCESS;
  430. }