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 <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
53 MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
54 MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
55
56 CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand";
57 EFI_HANDLE gShellSfHiiHandle = NULL;
58
59 BOOLEAN InitFlag = 1;
60
61 STATIC 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
74 typedef 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 **/
90 CONST CHAR16*
91 EFIAPI
ShellCommandGetManFileNameSpiFlash(VOID)92 ShellCommandGetManFileNameSpiFlash (
93 VOID
94 )
95 {
96
97 return gShellSpiFlashFileName;
98 }
99
100 VOID
SfUsage(VOID)101 SfUsage (
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
133 STATIC
134 EFI_STATUS
OpenAndPrepareFile(IN CHAR16 * FilePath,SHELL_FILE_HANDLE * FileHandle)135 OpenAndPrepareFile (
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
162 STATIC
163 EFI_STATUS
FlashProbe(IN SPI_DEVICE * Slave)164 FlashProbe (
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
202 SHELL_STATUS
203 EFIAPI
ShellCommandRunSpiFlash(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)204 ShellCommandRunSpiFlash (
205 IN EFI_HANDLE ImageHandle,
206 IN EFI_SYSTEM_TABLE *SystemTable
207 )
208 {
209 EFI_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
482 Error_Free_Buffer:
483 FreePool (FileBuffer);
484 Error_Close_File:
485 ShellCloseFile (&FileHandle);
486 return SHELL_ABORTED;
487 }
488
489 EFI_STATUS
490 EFIAPI
ShellSpiFlashLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)491 ShellSpiFlashLibConstructor (
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
514 EFI_STATUS
515 EFIAPI
ShellSpiFlashLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)516 ShellSpiFlashLibDestructor (
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