• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   A shell application that triggers capsule update process.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <Uefi.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/PrintLib.h>
24 #include <Protocol/LoadedImage.h>
25 #include <Protocol/SimpleFileSystem.h>
26 #include <Protocol/ShellParameters.h>
27 #include <Guid/FileInfo.h>
28 #include <Guid/Gpt.h>
29 
30 #define IS_HYPHEN(a)               ((a) == L'-')
31 #define IS_NULL(a)                 ((a) == L'\0')
32 
33 #define MAX_ARG_NUM     11
34 
35 UINTN  Argc;
36 CHAR16 **Argv;
37 
38 /**
39 
40   This function parse application ARG.
41 
42   @return Status
43 **/
44 EFI_STATUS
GetArg(VOID)45 GetArg (
46   VOID
47   )
48 {
49   EFI_STATUS                    Status;
50   EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
51 
52   Status = gBS->HandleProtocol (
53                   gImageHandle,
54                   &gEfiShellParametersProtocolGuid,
55                   (VOID**)&ShellParameters
56                   );
57   if (EFI_ERROR(Status)) {
58     return Status;
59   }
60 
61   Argc = ShellParameters->Argc;
62   Argv = ShellParameters->Argv;
63   return EFI_SUCCESS;
64 }
65 
66 /**
67   Converts a list of string to a specified buffer.
68 
69   @param[out] Buf             The output buffer that contains the string.
70   @param[in]  BufferLength    The length of the buffer
71   @param[in]  Str             The input string that contains the hex number
72 
73   @retval EFI_SUCCESS    The string was successfully converted to the buffer.
74 
75 **/
76 EFI_STATUS
InternalStrToBuf(OUT UINT8 * Buf,IN UINTN BufferLength,IN CHAR16 * Str)77 InternalStrToBuf (
78   OUT UINT8    *Buf,
79   IN  UINTN    BufferLength,
80   IN  CHAR16   *Str
81   )
82 {
83   UINTN       Index;
84   UINTN       StrLength;
85   UINT8       Digit;
86   UINT8       Byte;
87 
88   Digit = 0;
89 
90   //
91   // Two hex char make up one byte
92   //
93   StrLength = BufferLength * sizeof (CHAR16);
94 
95   for(Index = 0; Index < StrLength; Index++, Str++) {
96 
97     if ((*Str >= L'a') && (*Str <= L'f')) {
98       Digit = (UINT8) (*Str - L'a' + 0x0A);
99     } else if ((*Str >= L'A') && (*Str <= L'F')) {
100       Digit = (UINT8) (*Str - L'A' + 0x0A);
101     } else if ((*Str >= L'0') && (*Str <= L'9')) {
102       Digit = (UINT8) (*Str - L'0');
103     } else {
104       return EFI_INVALID_PARAMETER;
105     }
106 
107     //
108     // For odd characters, write the upper nibble for each buffer byte,
109     // and for even characters, the lower nibble.
110     //
111     if ((Index & 1) == 0) {
112       Byte = (UINT8) (Digit << 4);
113     } else {
114       Byte = Buf[Index / 2];
115       Byte &= 0xF0;
116       Byte = (UINT8) (Byte | Digit);
117     }
118 
119     Buf[Index / 2] = Byte;
120   }
121 
122   return EFI_SUCCESS;
123 }
124 
125 /**
126   Converts a string to GUID value.
127   Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
128 
129   @param[in]  Str              The registry format GUID string that contains the GUID value.
130   @param[out] Guid             A pointer to the converted GUID value.
131 
132   @retval EFI_SUCCESS     The GUID string was successfully converted to the GUID value.
133   @retval EFI_UNSUPPORTED The input string is not in registry format.
134   @return others          Some error occurred when converting part of GUID value.
135 
136 **/
137 EFI_STATUS
InternalStrToGuid(IN CHAR16 * Str,OUT EFI_GUID * Guid)138 InternalStrToGuid (
139   IN  CHAR16   *Str,
140   OUT EFI_GUID *Guid
141   )
142 {
143   //
144   // Get the first UINT32 data
145   //
146   Guid->Data1 = (UINT32) StrHexToUint64  (Str);
147   while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
148     Str ++;
149   }
150 
151   if (IS_HYPHEN (*Str)) {
152     Str++;
153   } else {
154     return EFI_UNSUPPORTED;
155   }
156 
157   //
158   // Get the second UINT16 data
159   //
160   Guid->Data2 = (UINT16) StrHexToUint64  (Str);
161   while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
162     Str ++;
163   }
164 
165   if (IS_HYPHEN (*Str)) {
166     Str++;
167   } else {
168     return EFI_UNSUPPORTED;
169   }
170 
171   //
172   // Get the third UINT16 data
173   //
174   Guid->Data3 = (UINT16) StrHexToUint64  (Str);
175   while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
176     Str ++;
177   }
178 
179   if (IS_HYPHEN (*Str)) {
180     Str++;
181   } else {
182     return EFI_UNSUPPORTED;
183   }
184 
185   //
186   // Get the following 8 bytes data
187   //
188   InternalStrToBuf (&Guid->Data4[0], 2, Str);
189   //
190   // Skip 2 byte hex chars
191   //
192   Str += 2 * 2;
193 
194   if (IS_HYPHEN (*Str)) {
195     Str++;
196   } else {
197     return EFI_UNSUPPORTED;
198   }
199   InternalStrToBuf (&Guid->Data4[2], 6, Str);
200 
201   return EFI_SUCCESS;
202 }
203 
204 /**
205   Return File System Volume containing this shell application.
206 
207   @return File System Volume containing this shell application.
208 **/
209 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *
GetMyVol(VOID)210 GetMyVol (
211   VOID
212   )
213 {
214   EFI_STATUS                        Status;
215   EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
216   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
217 
218   Status = gBS->HandleProtocol (
219                   gImageHandle,
220                   &gEfiLoadedImageProtocolGuid,
221                   (VOID **)&LoadedImage
222                   );
223   ASSERT_EFI_ERROR (Status);
224 
225   Status = gBS->HandleProtocol (
226                   LoadedImage->DeviceHandle,
227                   &gEfiSimpleFileSystemProtocolGuid,
228                   (VOID **)&Vol
229                   );
230   if (!EFI_ERROR (Status)) {
231     return Vol;
232   }
233 
234   return NULL;
235 }
236 
237 /**
238   Read a file from this volume.
239 
240   @param[in]  Vol             File System Volume
241   @param[in]  FileName        The file to be read.
242   @param[out] BufferSize      The file buffer size
243   @param[out] Buffer          The file buffer
244 
245   @retval EFI_SUCCESS    Read file successfully
246   @retval EFI_NOT_FOUND  File not found
247 **/
248 EFI_STATUS
ReadFileFromVol(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * Vol,IN CHAR16 * FileName,OUT UINTN * BufferSize,OUT VOID ** Buffer)249 ReadFileFromVol (
250   IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol,
251   IN  CHAR16                            *FileName,
252   OUT UINTN                             *BufferSize,
253   OUT VOID                              **Buffer
254   )
255 {
256   EFI_STATUS                        Status;
257   EFI_FILE_HANDLE                   RootDir;
258   EFI_FILE_HANDLE                   Handle;
259   UINTN                             FileInfoSize;
260   EFI_FILE_INFO                     *FileInfo;
261   UINTN                             TempBufferSize;
262   VOID                              *TempBuffer;
263 
264   //
265   // Open the root directory
266   //
267   Status = Vol->OpenVolume (Vol, &RootDir);
268   if (EFI_ERROR (Status)) {
269     return Status;
270   }
271 
272   //
273   // Open the file
274   //
275   Status = RootDir->Open (
276                       RootDir,
277                       &Handle,
278                       FileName,
279                       EFI_FILE_MODE_READ,
280                       0
281                       );
282   if (EFI_ERROR (Status)) {
283     RootDir->Close (RootDir);
284     return Status;
285   }
286 
287   RootDir->Close (RootDir);
288 
289   //
290   // Get the file information
291   //
292   FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
293 
294   FileInfo = AllocateZeroPool (FileInfoSize);
295   if (FileInfo == NULL) {
296     Handle->Close (Handle);
297     return Status;
298   }
299 
300   Status = Handle->GetInfo (
301                      Handle,
302                      &gEfiFileInfoGuid,
303                      &FileInfoSize,
304                      FileInfo
305                      );
306   if (EFI_ERROR (Status)) {
307     Handle->Close (Handle);
308     gBS->FreePool (FileInfo);
309     return Status;
310   }
311 
312   //
313   // Allocate buffer for the file data. The last CHAR16 is for L'\0'
314   //
315   TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);
316   TempBuffer = AllocateZeroPool (TempBufferSize);
317   if (TempBuffer == NULL) {
318     Handle->Close (Handle);
319     gBS->FreePool (FileInfo);
320     return Status;
321   }
322 
323   gBS->FreePool (FileInfo);
324 
325   //
326   // Read the file data to the buffer
327   //
328   Status = Handle->Read (
329                      Handle,
330                      &TempBufferSize,
331                      TempBuffer
332                      );
333   if (EFI_ERROR (Status)) {
334     Handle->Close (Handle);
335     gBS->FreePool (TempBuffer);
336     return Status;
337   }
338 
339   Handle->Close (Handle);
340 
341   *BufferSize = TempBufferSize;
342   *Buffer     = TempBuffer;
343   return EFI_SUCCESS;
344 }
345 
346 /**
347   Read a file.
348   If ScanFs is FLASE, it will use this Vol as default Fs.
349   If ScanFs is TRUE, it will scan all FS and check the file.
350     If there is only one file match the name, it will be read.
351     If there is more than one file match the name, it will return Error.
352 
353   @param[in,out]  ThisVol         File System Volume
354   @param[in]      FileName        The file to be read.
355   @param[out]     BufferSize      The file buffer size
356   @param[out]     Buffer          The file buffer
357   @param[in]      ScanFs          Need Scan all FS
358 
359   @retval EFI_SUCCESS    Read file successfully
360   @retval EFI_NOT_FOUND  File not found
361   @retval EFI_NO_MAPPING There is duplicated files found
362 **/
363 EFI_STATUS
ReadFileToBufferEx(IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL ** ThisVol,IN CHAR16 * FileName,OUT UINTN * BufferSize,OUT VOID ** Buffer,IN BOOLEAN ScanFs)364 ReadFileToBufferEx (
365   IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   **ThisVol,
366   IN  CHAR16                               *FileName,
367   OUT UINTN                                *BufferSize,
368   OUT VOID                                 **Buffer,
369   IN  BOOLEAN                              ScanFs
370   )
371 {
372   EFI_STATUS                        Status;
373   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
374   UINTN                             TempBufferSize;
375   VOID                              *TempBuffer;
376   UINTN                             NoHandles;
377   EFI_HANDLE                        *HandleBuffer;
378   UINTN                             Index;
379 
380   //
381   // Check parameters
382   //
383   if ((FileName == NULL) || (Buffer == NULL) || (ThisVol == NULL)) {
384     return EFI_INVALID_PARAMETER;
385   }
386 
387   //
388   // not scan fs
389   //
390   if (!ScanFs) {
391     if (*ThisVol == NULL) {
392       *ThisVol = GetMyVol ();
393       if (*ThisVol == NULL) {
394         return EFI_INVALID_PARAMETER;
395       }
396     }
397     //
398     // Read file directly from Vol
399     //
400     return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer);
401   }
402 
403   //
404   // need scan fs
405   //
406 
407   //
408   // Get all Vol handle
409   //
410   Status = gBS->LocateHandleBuffer (
411                    ByProtocol,
412                    &gEfiSimpleFileSystemProtocolGuid,
413                    NULL,
414                    &NoHandles,
415                    &HandleBuffer
416                    );
417   if (EFI_ERROR (Status) && (NoHandles == 0)) {
418     return EFI_NOT_FOUND;
419   }
420 
421   //
422   // Walk through each Vol
423   //
424   *ThisVol = NULL;
425   *BufferSize = 0;
426   *Buffer     = NULL;
427   for (Index = 0; Index < NoHandles; Index++) {
428     Status = gBS->HandleProtocol (
429                     HandleBuffer[Index],
430                     &gEfiSimpleFileSystemProtocolGuid,
431                     (VOID **)&Vol
432                     );
433     if (EFI_ERROR(Status)) {
434       continue;
435     }
436 
437     Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);
438     if (!EFI_ERROR (Status)) {
439       //
440       // Read file OK, check duplication
441       //
442       if (*ThisVol != NULL) {
443         //
444         // Find the duplicated file
445         //
446         gBS->FreePool (TempBuffer);
447         gBS->FreePool (*Buffer);
448         Print (L"Duplicated FileName found!\n");
449         return EFI_NO_MAPPING;
450       } else {
451         //
452         // Record value
453         //
454         *ThisVol = Vol;
455         *BufferSize = TempBufferSize;
456         *Buffer     = TempBuffer;
457       }
458     }
459   }
460 
461   //
462   // Scan Fs done
463   //
464   if (*ThisVol == NULL) {
465     return EFI_NOT_FOUND;
466   }
467 
468   //
469   // Done
470   //
471   return EFI_SUCCESS;
472 }
473 
474 /**
475   Read a file.
476 
477   @param[in]  FileName        The file to be read.
478   @param[out] BufferSize      The file buffer size
479   @param[out] Buffer          The file buffer
480 
481   @retval EFI_SUCCESS    Read file successfully
482   @retval EFI_NOT_FOUND  File not found
483 **/
484 EFI_STATUS
ReadFileToBuffer(IN CHAR16 * FileName,OUT UINTN * BufferSize,OUT VOID ** Buffer)485 ReadFileToBuffer (
486   IN  CHAR16                               *FileName,
487   OUT UINTN                                *BufferSize,
488   OUT VOID                                 **Buffer
489   )
490 {
491   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
492   Vol = NULL;
493   return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE);
494 }
495 
496 /**
497   Write a file.
498 
499   @param[in] FileName        The file to be written.
500   @param[in] BufferSize      The file buffer size
501   @param[in] Buffer          The file buffer
502 
503   @retval EFI_SUCCESS    Write file successfully
504 **/
505 EFI_STATUS
WriteFileFromBuffer(IN CHAR16 * FileName,IN UINTN BufferSize,IN VOID * Buffer)506 WriteFileFromBuffer (
507   IN  CHAR16                               *FileName,
508   IN  UINTN                                BufferSize,
509   IN  VOID                                 *Buffer
510   )
511 {
512   EFI_STATUS                        Status;
513   EFI_FILE_HANDLE                   RootDir;
514   EFI_FILE_HANDLE                   Handle;
515   UINTN                             TempBufferSize;
516   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
517 
518   Vol = GetMyVol();
519   if (Vol == NULL) {
520     return EFI_NOT_FOUND;
521   }
522 
523   //
524   // Open the root directory
525   //
526   Status = Vol->OpenVolume (Vol, &RootDir);
527   if (EFI_ERROR (Status)) {
528     return Status;
529   }
530 
531   //
532   // Open the file
533   //
534   Status = RootDir->Open (
535                       RootDir,
536                       &Handle,
537                       FileName,
538                       EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
539                       0
540                       );
541   if (EFI_ERROR (Status)) {
542     RootDir->Close (RootDir);
543     return Status;
544   }
545 
546   //
547   // Delete file
548   //
549   Status = Handle->Delete(Handle);
550   if (EFI_ERROR(Status)) {
551     return Status;
552   }
553 
554   //
555   // Open the file again
556   //
557   Status = RootDir->Open (
558                       RootDir,
559                       &Handle,
560                       FileName,
561                       EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
562                       0
563                       );
564   if (EFI_ERROR (Status)) {
565     RootDir->Close (RootDir);
566     return Status;
567   }
568 
569   RootDir->Close (RootDir);
570 
571   //
572   // Write the file data from the buffer
573   //
574   TempBufferSize = BufferSize;
575   Status = Handle->Write (
576                      Handle,
577                      &TempBufferSize,
578                      Buffer
579                      );
580   if (EFI_ERROR (Status)) {
581     Handle->Close (Handle);
582     return Status;
583   }
584 
585   Handle->Close (Handle);
586 
587   return EFI_SUCCESS;
588 }
589 
590