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