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