• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
SpiFlashProbe(IN SPI_DEVICE * Slave)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
CheckImageHeader(IN OUT UINTN * ImageHeader)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
PrepareFirmwareImage(IN LIST_ENTRY * CheckPackage,IN OUT SHELL_FILE_HANDLE * FileHandle,IN OUT UINTN ** FileBuffer,IN OUT UINTN * FileSize)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
ShellCommandGetManFileNameFUpdate(VOID)227 ShellCommandGetManFileNameFUpdate (
228   VOID
229   )
230 {
231   return gShellFUpdateFileName;
232 }
233 
234 STATIC
235 VOID
FUpdateUsage(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
ShellCommandRunFUpdate(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
ShellFUpdateCommandConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
ShellFUpdateCommandDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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