SecurityPkg: Add FileExplorerLib.inf to the dsc file
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigFileExplorer.c
CommitLineData
ecc722ad 1/** @file\r
2 Internal file explorer functions for SecureBoot configuration module.\r
3\r
c2a65e23 4Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>\r
ecc722ad 5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "SecureBootConfigImpl.h"\r
16\r
17///\r
18/// File system selection menu\r
19///\r
20SECUREBOOT_MENU_OPTION FsOptionMenu = {\r
21 SECUREBOOT_MENU_OPTION_SIGNATURE,\r
22 {NULL},\r
23 0\r
24};\r
25\r
26///\r
27/// Files and sub-directories in current directory menu\r
28///\r
29SECUREBOOT_MENU_OPTION DirectoryMenu = {\r
30 SECUREBOOT_MENU_OPTION_SIGNATURE,\r
31 {NULL},\r
32 0\r
33};\r
34\r
35VOID *mStartOpCodeHandle = NULL;\r
36VOID *mEndOpCodeHandle = NULL;\r
37EFI_IFR_GUID_LABEL *mStartLabel = NULL;\r
38EFI_IFR_GUID_LABEL *mEndLabel = NULL;\r
39\r
40/**\r
41 Duplicate a string.\r
42\r
43 @param[in] Src The source string.\r
44\r
45 @return A new string which is duplicated copy of the source,\r
46 or NULL if there is not enough memory.\r
47\r
48**/\r
49CHAR16 *\r
50StrDuplicate (\r
51 IN CHAR16 *Src\r
52 )\r
53{\r
54 CHAR16 *Dest;\r
55 UINTN Size;\r
56\r
57 Size = StrSize (Src);\r
58 Dest = AllocateZeroPool (Size);\r
59 ASSERT (Dest != NULL);\r
60 if (Dest != NULL) {\r
61 CopyMem (Dest, Src, Size);\r
62 }\r
63\r
64 return Dest;\r
65}\r
66\r
67/**\r
20333c6d 68 Helper function called as part of the code needed to allocate\r
ecc722ad 69 the proper sized buffer for various EFI interfaces.\r
70\r
71 @param[in, out] Status Current status\r
72 @param[in, out] Buffer Current allocated buffer, or NULL\r
73 @param[in] BufferSize Current buffer size needed\r
74\r
75 @retval TRUE If the buffer was reallocated and the caller\r
76 should try the API again.\r
77 @retval FALSE The caller should not call this function again.\r
78\r
79**/\r
80BOOLEAN\r
81GrowBuffer (\r
82 IN OUT EFI_STATUS *Status,\r
83 IN OUT VOID **Buffer,\r
84 IN UINTN BufferSize\r
85 )\r
86{\r
87 BOOLEAN TryAgain;\r
88\r
89 //\r
90 // If this is an initial request, buffer will be null with a new buffer size\r
91 //\r
92 if ((*Buffer == NULL) && (BufferSize != 0)) {\r
93 *Status = EFI_BUFFER_TOO_SMALL;\r
94 }\r
95 //\r
96 // If the status code is "buffer too small", resize the buffer\r
97 //\r
98 TryAgain = FALSE;\r
99 if (*Status == EFI_BUFFER_TOO_SMALL) {\r
100\r
101 if (*Buffer != NULL) {\r
102 FreePool (*Buffer);\r
103 }\r
104\r
105 *Buffer = AllocateZeroPool (BufferSize);\r
106\r
107 if (*Buffer != NULL) {\r
108 TryAgain = TRUE;\r
109 } else {\r
110 *Status = EFI_OUT_OF_RESOURCES;\r
111 }\r
112 }\r
113 //\r
114 // If there's an error, free the buffer\r
115 //\r
116 if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {\r
117 FreePool (*Buffer);\r
118 *Buffer = NULL;\r
119 }\r
120\r
121 return TryAgain;\r
122}\r
123\r
124/**\r
20333c6d 125 Append file name to existing file name, and allocate a new buffer\r
ecc722ad 126 to hold the appended result.\r
127\r
128 @param[in] Str1 The existing file name\r
129 @param[in] Str2 The file name to be appended\r
130\r
131 @return A new string with appended result.\r
132\r
133**/\r
134CHAR16 *\r
135AppendFileName (\r
136 IN CHAR16 *Str1,\r
137 IN CHAR16 *Str2\r
138 )\r
139{\r
140 UINTN Size1;\r
141 UINTN Size2;\r
c2a65e23 142 UINTN BufferSize;\r
ecc722ad 143 CHAR16 *Str;\r
144 CHAR16 *TmpStr;\r
145 CHAR16 *Ptr;\r
146 CHAR16 *LastSlash;\r
147\r
148 Size1 = StrSize (Str1);\r
149 Size2 = StrSize (Str2);\r
c2a65e23
ZL
150 BufferSize = Size1 + Size2 + sizeof (CHAR16);\r
151 Str = AllocateZeroPool (BufferSize);\r
ecc722ad 152 ASSERT (Str != NULL);\r
153\r
c2a65e23 154 TmpStr = AllocateZeroPool (BufferSize);\r
ecc722ad 155 ASSERT (TmpStr != NULL);\r
156\r
c2a65e23
ZL
157 StrCatS (Str, BufferSize / sizeof (CHAR16), Str1);\r
158\r
ecc722ad 159 if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
c2a65e23 160 StrCatS (Str, BufferSize / sizeof (CHAR16), L"\\");\r
ecc722ad 161 }\r
162\r
c2a65e23 163 StrCatS (Str, BufferSize / sizeof (CHAR16), Str2);\r
ecc722ad 164\r
165 Ptr = Str;\r
166 LastSlash = Str;\r
167 while (*Ptr != 0) {\r
168 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {\r
169 //\r
170 // Convert "\Name\..\" to "\"\r
171 // DO NOT convert the .. if it is at the end of the string. This will\r
172 // break the .. behavior in changing directories.\r
173 //\r
174\r
175 //\r
c2a65e23 176 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings\r
ecc722ad 177 // that overlap.\r
178 //\r
c2a65e23
ZL
179 StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 3);\r
180 StrCpyS (LastSlash, BufferSize / sizeof (CHAR16), TmpStr);\r
ecc722ad 181 Ptr = LastSlash;\r
182 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
183 //\r
184 // Convert a "\.\" to a "\"\r
185 //\r
186\r
187 //\r
c2a65e23 188 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings\r
ecc722ad 189 // that overlap.\r
190 //\r
c2a65e23
ZL
191 StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 2);\r
192 StrCpyS (Ptr, BufferSize / sizeof (CHAR16), TmpStr);\r
ecc722ad 193 Ptr = LastSlash;\r
194 } else if (*Ptr == '\\') {\r
195 LastSlash = Ptr;\r
196 }\r
197\r
198 Ptr++;\r
199 }\r
200\r
201 FreePool (TmpStr);\r
20333c6d 202\r
ecc722ad 203 return Str;\r
204}\r
205\r
206/**\r
207 Create a SECUREBOOT_MENU_ENTRY, and stores it in a buffer allocated from the pool.\r
208\r
209 @return The new menu entry or NULL of error happens.\r
210\r
211**/\r
212SECUREBOOT_MENU_ENTRY *\r
213CreateMenuEntry (\r
214 VOID\r
215 )\r
216{\r
217 SECUREBOOT_MENU_ENTRY *MenuEntry;\r
218 UINTN ContextSize;\r
219\r
220 //\r
221 // Create new menu entry\r
222 //\r
223 MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));\r
224 if (MenuEntry == NULL) {\r
225 return NULL;\r
226 }\r
227\r
228 ContextSize = sizeof (SECUREBOOT_FILE_CONTEXT);\r
229 MenuEntry->FileContext = AllocateZeroPool (ContextSize);\r
230 if (MenuEntry->FileContext == NULL) {\r
231 FreePool (MenuEntry);\r
232 return NULL;\r
233 }\r
234\r
235 MenuEntry->Signature = SECUREBOOT_MENU_ENTRY_SIGNATURE;\r
236\r
237 return MenuEntry;\r
238}\r
239\r
240/**\r
241 Get Menu Entry from the Menu Entry List by MenuNumber.\r
242\r
243 If MenuNumber is great or equal to the number of Menu\r
244 Entry in the list, then ASSERT.\r
245\r
246 @param[in] MenuOption The Menu Entry List to read the menu entry.\r
247 @param[in] MenuNumber The index of Menu Entry.\r
248\r
249 @return The Menu Entry.\r
250\r
251**/\r
252SECUREBOOT_MENU_ENTRY *\r
253GetMenuEntry (\r
254 IN SECUREBOOT_MENU_OPTION *MenuOption,\r
255 IN UINTN MenuNumber\r
256 )\r
257{\r
258 SECUREBOOT_MENU_ENTRY *NewMenuEntry;\r
259 UINTN Index;\r
260 LIST_ENTRY *List;\r
261\r
262 ASSERT (MenuNumber < MenuOption->MenuNumber);\r
263\r
264 List = MenuOption->Head.ForwardLink;\r
265 for (Index = 0; Index < MenuNumber; Index++) {\r
266 List = List->ForwardLink;\r
267 }\r
268\r
269 NewMenuEntry = CR (List, SECUREBOOT_MENU_ENTRY, Link, SECUREBOOT_MENU_ENTRY_SIGNATURE);\r
270\r
271 return NewMenuEntry;\r
272}\r
273\r
274/**\r
275 Create string tokens for a menu from its help strings and display strings.\r
276\r
277 @param[in] HiiHandle Hii Handle of the package to be updated.\r
278 @param[in] MenuOption The Menu whose string tokens need to be created.\r
279\r
280**/\r
281VOID\r
282CreateMenuStringToken (\r
283 IN EFI_HII_HANDLE HiiHandle,\r
284 IN SECUREBOOT_MENU_OPTION *MenuOption\r
285 )\r
286{\r
287 SECUREBOOT_MENU_ENTRY *NewMenuEntry;\r
288 UINTN Index;\r
289\r
290 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {\r
291 NewMenuEntry = GetMenuEntry (MenuOption, Index);\r
292\r
293 NewMenuEntry->DisplayStringToken = HiiSetString (\r
294 HiiHandle,\r
295 0,\r
296 NewMenuEntry->DisplayString,\r
297 NULL\r
298 );\r
299\r
300 if (NewMenuEntry->HelpString == NULL) {\r
301 NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;\r
302 } else {\r
303 NewMenuEntry->HelpStringToken = HiiSetString (\r
304 HiiHandle,\r
305 0,\r
306 NewMenuEntry->HelpString,\r
307 NULL\r
308 );\r
309 }\r
310 }\r
311}\r
312\r
313/**\r
314 Free up all resources allocated for a SECUREBOOT_MENU_ENTRY.\r
315\r
316 @param[in, out] MenuEntry A pointer to SECUREBOOT_MENU_ENTRY.\r
317\r
318**/\r
319VOID\r
320DestroyMenuEntry (\r
321 IN OUT SECUREBOOT_MENU_ENTRY *MenuEntry\r
322 )\r
323{\r
324 SECUREBOOT_FILE_CONTEXT *FileContext;\r
325\r
326\r
327 FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;\r
328\r
968e1431 329 if (!FileContext->IsRoot && FileContext->DevicePath != NULL) {\r
ecc722ad 330 FreePool (FileContext->DevicePath);\r
331 } else {\r
332 if (FileContext->FHandle != NULL) {\r
333 FileContext->FHandle->Close (FileContext->FHandle);\r
334 }\r
335 }\r
336\r
337 if (FileContext->FileName != NULL) {\r
338 FreePool (FileContext->FileName);\r
339 }\r
340 if (FileContext->Info != NULL) {\r
341 FreePool (FileContext->Info);\r
342 }\r
343\r
344 FreePool (FileContext);\r
345\r
968e1431 346 if (MenuEntry->DisplayString != NULL) {\r
347 FreePool (MenuEntry->DisplayString);\r
348 }\r
ecc722ad 349 if (MenuEntry->HelpString != NULL) {\r
350 FreePool (MenuEntry->HelpString);\r
351 }\r
352\r
353 FreePool (MenuEntry);\r
354}\r
355\r
356/**\r
357 Free resources allocated in Allocate Rountine.\r
358\r
359 @param[in, out] MenuOption Menu to be freed\r
20333c6d 360\r
ecc722ad 361**/\r
362VOID\r
363FreeMenu (\r
364 IN OUT SECUREBOOT_MENU_OPTION *MenuOption\r
365 )\r
366{\r
367 SECUREBOOT_MENU_ENTRY *MenuEntry;\r
368 while (!IsListEmpty (&MenuOption->Head)) {\r
369 MenuEntry = CR (\r
370 MenuOption->Head.ForwardLink,\r
371 SECUREBOOT_MENU_ENTRY,\r
372 Link,\r
373 SECUREBOOT_MENU_ENTRY_SIGNATURE\r
374 );\r
375 RemoveEntryList (&MenuEntry->Link);\r
376 DestroyMenuEntry (MenuEntry);\r
377 }\r
378 MenuOption->MenuNumber = 0;\r
379}\r
380\r
381/**\r
382 This function gets the file information from an open file descriptor, and stores it\r
383 in a buffer allocated from pool.\r
384\r
385 @param[in] FHand File Handle.\r
386\r
387 @return A pointer to a buffer with file information or NULL is returned\r
388\r
389**/\r
390EFI_FILE_INFO *\r
391FileInfo (\r
392 IN EFI_FILE_HANDLE FHand\r
393 )\r
394{\r
395 EFI_STATUS Status;\r
396 EFI_FILE_INFO *Buffer;\r
397 UINTN BufferSize;\r
398\r
399 //\r
400 // Initialize for GrowBuffer loop\r
401 //\r
402 Buffer = NULL;\r
403 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;\r
404\r
405 //\r
406 // Call the real function\r
407 //\r
408 while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
409 Status = FHand->GetInfo (\r
410 FHand,\r
411 &gEfiFileInfoGuid,\r
412 &BufferSize,\r
413 Buffer\r
414 );\r
415 }\r
416\r
417 return Buffer;\r
418}\r
419\r
420/**\r
421 This function gets the file system information from an open file descriptor,\r
422 and stores it in a buffer allocated from pool.\r
423\r
424 @param[in] FHand The file handle.\r
425\r
426 @return A pointer to a buffer with file information.\r
427 @retval NULL is returned if failed to get Vaolume Label Info.\r
428\r
429**/\r
430EFI_FILE_SYSTEM_VOLUME_LABEL *\r
431FileSystemVolumeLabelInfo (\r
432 IN EFI_FILE_HANDLE FHand\r
433 )\r
434{\r
435 EFI_STATUS Status;\r
436 EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;\r
437 UINTN BufferSize;\r
438 //\r
439 // Initialize for GrowBuffer loop\r
440 //\r
441 Buffer = NULL;\r
442 BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;\r
443\r
444 //\r
445 // Call the real function\r
446 //\r
447 while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
448 Status = FHand->GetInfo (\r
449 FHand,\r
450 &gEfiFileSystemVolumeLabelInfoIdGuid,\r
451 &BufferSize,\r
452 Buffer\r
453 );\r
454 }\r
455\r
456 return Buffer;\r
457}\r
458\r
459/**\r
460 This function will open a file or directory referenced by DevicePath.\r
461\r
462 This function opens a file with the open mode according to the file path. The\r
463 Attributes is valid only for EFI_FILE_MODE_CREATE.\r
464\r
20333c6d 465 @param[in, out] FilePath On input, the device path to the file.\r
ecc722ad 466 On output, the remaining device path.\r
467 @param[out] FileHandle Pointer to the file handle.\r
468 @param[in] OpenMode The mode to open the file with.\r
469 @param[in] Attributes The file's file attributes.\r
470\r
471 @retval EFI_SUCCESS The information was set.\r
472 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
473 @retval EFI_UNSUPPORTED Could not open the file path.\r
474 @retval EFI_NOT_FOUND The specified file could not be found on the\r
475 device or the file system could not be found on\r
476 the device.\r
477 @retval EFI_NO_MEDIA The device has no medium.\r
478 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the\r
479 medium is no longer supported.\r
480 @retval EFI_DEVICE_ERROR The device reported an error.\r
481 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
482 @retval EFI_WRITE_PROTECTED The file or medium is write protected.\r
483 @retval EFI_ACCESS_DENIED The file was opened read only.\r
484 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the\r
485 file.\r
486 @retval EFI_VOLUME_FULL The volume is full.\r
487**/\r
488EFI_STATUS\r
489EFIAPI\r
490OpenFileByDevicePath(\r
491 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
492 OUT EFI_FILE_HANDLE *FileHandle,\r
493 IN UINT64 OpenMode,\r
494 IN UINT64 Attributes\r
495 )\r
496{\r
497 EFI_STATUS Status;\r
498 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;\r
499 EFI_FILE_PROTOCOL *Handle1;\r
500 EFI_FILE_PROTOCOL *Handle2;\r
20333c6d 501 EFI_HANDLE DeviceHandle;\r
ecc722ad 502\r
503 if ((FilePath == NULL || FileHandle == NULL)) {\r
504 return EFI_INVALID_PARAMETER;\r
505 }\r
506\r
507 Status = gBS->LocateDevicePath (\r
508 &gEfiSimpleFileSystemProtocolGuid,\r
509 FilePath,\r
510 &DeviceHandle\r
511 );\r
512 if (EFI_ERROR (Status)) {\r
513 return Status;\r
514 }\r
515\r
516 Status = gBS->OpenProtocol(\r
517 DeviceHandle,\r
518 &gEfiSimpleFileSystemProtocolGuid,\r
519 (VOID**)&EfiSimpleFileSystemProtocol,\r
520 gImageHandle,\r
521 NULL,\r
522 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
523 );\r
524 if (EFI_ERROR (Status)) {\r
525 return Status;\r
526 }\r
527\r
528 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);\r
529 if (EFI_ERROR (Status)) {\r
530 FileHandle = NULL;\r
531 return Status;\r
532 }\r
533\r
534 //\r
535 // go down directories one node at a time.\r
536 //\r
537 while (!IsDevicePathEnd (*FilePath)) {\r
538 //\r
539 // For file system access each node should be a file path component\r
540 //\r
541 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||\r
542 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP\r
543 ) {\r
544 FileHandle = NULL;\r
545 return (EFI_INVALID_PARAMETER);\r
546 }\r
547 //\r
548 // Open this file path node\r
549 //\r
550 Handle2 = Handle1;\r
551 Handle1 = NULL;\r
552\r
553 //\r
554 // Try to test opening an existing file\r
555 //\r
556 Status = Handle2->Open (\r
557 Handle2,\r
558 &Handle1,\r
559 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,\r
560 OpenMode &~EFI_FILE_MODE_CREATE,\r
561 0\r
562 );\r
563\r
564 //\r
565 // see if the error was that it needs to be created\r
566 //\r
567 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {\r
568 Status = Handle2->Open (\r
569 Handle2,\r
570 &Handle1,\r
571 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,\r
572 OpenMode,\r
573 Attributes\r
574 );\r
575 }\r
576 //\r
577 // Close the last node\r
578 //\r
579 Handle2->Close (Handle2);\r
580\r
581 if (EFI_ERROR(Status)) {\r
582 return (Status);\r
583 }\r
584\r
585 //\r
586 // Get the next node\r
587 //\r
588 *FilePath = NextDevicePathNode (*FilePath);\r
589 }\r
590\r
591 //\r
592 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!\r
593 //\r
594 *FileHandle = (VOID*)Handle1;\r
595 return EFI_SUCCESS;\r
596}\r
597\r
598/**\r
599 Function opens and returns a file handle to the root directory of a volume.\r
600\r
601 @param[in] DeviceHandle A handle for a device\r
602\r
603 @return A valid file handle or NULL if error happens.\r
604\r
605**/\r
606EFI_FILE_HANDLE\r
607OpenRoot (\r
608 IN EFI_HANDLE DeviceHandle\r
609 )\r
610{\r
611 EFI_STATUS Status;\r
612 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
613 EFI_FILE_HANDLE File;\r
614\r
615 File = NULL;\r
616\r
617 //\r
618 // File the file system interface to the device\r
619 //\r
620 Status = gBS->HandleProtocol (\r
621 DeviceHandle,\r
622 &gEfiSimpleFileSystemProtocolGuid,\r
623 (VOID *) &Volume\r
624 );\r
625\r
626 //\r
627 // Open the root directory of the volume\r
628 //\r
629 if (!EFI_ERROR (Status)) {\r
630 Status = Volume->OpenVolume (\r
631 Volume,\r
632 &File\r
633 );\r
634 }\r
635 //\r
636 // Done\r
637 //\r
638 return EFI_ERROR (Status) ? NULL : File;\r
639}\r
640\r
641/**\r
642 This function builds the FsOptionMenu list which records all\r
643 available file system in the system. They include all instances\r
644 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM\r
645 and all type of legacy boot device.\r
646\r
647 @retval EFI_SUCCESS Success find the file system\r
648 @retval EFI_OUT_OF_RESOURCES Can not create menu entry\r
649\r
650**/\r
651EFI_STATUS\r
652FindFileSystem (\r
653 VOID\r
654 )\r
655{\r
656 UINTN NoBlkIoHandles;\r
657 UINTN NoSimpleFsHandles;\r
ecc722ad 658 EFI_HANDLE *BlkIoHandle;\r
659 EFI_HANDLE *SimpleFsHandle;\r
660 UINT16 *VolumeLabel;\r
661 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
662 UINTN Index;\r
663 EFI_STATUS Status;\r
664 SECUREBOOT_MENU_ENTRY *MenuEntry;\r
665 SECUREBOOT_FILE_CONTEXT *FileContext;\r
666 UINT16 *TempStr;\r
667 UINTN OptionNumber;\r
668 VOID *Buffer;\r
669\r
670 BOOLEAN RemovableMedia;\r
671\r
672\r
673 NoSimpleFsHandles = 0;\r
ecc722ad 674 OptionNumber = 0;\r
675 InitializeListHead (&FsOptionMenu.Head);\r
676\r
677 //\r
678 // Locate Handles that support BlockIo protocol\r
679 //\r
680 Status = gBS->LocateHandleBuffer (\r
681 ByProtocol,\r
682 &gEfiBlockIoProtocolGuid,\r
683 NULL,\r
684 &NoBlkIoHandles,\r
685 &BlkIoHandle\r
686 );\r
687 if (!EFI_ERROR (Status)) {\r
688\r
689 for (Index = 0; Index < NoBlkIoHandles; Index++) {\r
690 Status = gBS->HandleProtocol (\r
691 BlkIoHandle[Index],\r
692 &gEfiBlockIoProtocolGuid,\r
693 (VOID **) &BlkIo\r
694 );\r
695\r
696 if (EFI_ERROR (Status)) {\r
697 continue;\r
698 }\r
699\r
700 //\r
701 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media\r
702 //\r
703 if (BlkIo->Media->RemovableMedia) {\r
704 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);\r
705 if (NULL == Buffer) {\r
706 FreePool (BlkIoHandle);\r
707 return EFI_OUT_OF_RESOURCES;\r
708 }\r
709\r
710 BlkIo->ReadBlocks (\r
711 BlkIo,\r
712 BlkIo->Media->MediaId,\r
713 0,\r
714 BlkIo->Media->BlockSize,\r
715 Buffer\r
716 );\r
717 FreePool (Buffer);\r
718 }\r
719 }\r
720 FreePool (BlkIoHandle);\r
721 }\r
722\r
723 //\r
724 // Locate Handles that support Simple File System protocol\r
725 //\r
726 Status = gBS->LocateHandleBuffer (\r
727 ByProtocol,\r
728 &gEfiSimpleFileSystemProtocolGuid,\r
729 NULL,\r
730 &NoSimpleFsHandles,\r
731 &SimpleFsHandle\r
732 );\r
733 if (!EFI_ERROR (Status)) {\r
734 //\r
735 // Find all the instances of the File System prototocol\r
736 //\r
737 for (Index = 0; Index < NoSimpleFsHandles; Index++) {\r
738 Status = gBS->HandleProtocol (\r
739 SimpleFsHandle[Index],\r
740 &gEfiBlockIoProtocolGuid,\r
741 (VOID **) &BlkIo\r
742 );\r
743 if (EFI_ERROR (Status)) {\r
744 //\r
745 // If no block IO exists assume it's NOT a removable media\r
746 //\r
747 RemovableMedia = FALSE;\r
748 } else {\r
749 //\r
750 // If block IO exists check to see if it's remobable media\r
751 //\r
752 RemovableMedia = BlkIo->Media->RemovableMedia;\r
753 }\r
754\r
755 //\r
756 // Allocate pool for this instance.\r
757 //\r
758 MenuEntry = CreateMenuEntry ();\r
759 if (NULL == MenuEntry) {\r
760 FreePool (SimpleFsHandle);\r
761 return EFI_OUT_OF_RESOURCES;\r
762 }\r
763\r
764 FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;\r
765\r
766 FileContext->Handle = SimpleFsHandle[Index];\r
767 MenuEntry->OptionNumber = Index;\r
768 FileContext->FHandle = OpenRoot (FileContext->Handle);\r
769 if (FileContext->FHandle == NULL) {\r
770 DestroyMenuEntry (MenuEntry);\r
771 continue;\r
772 }\r
773\r
774 MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));\r
775 FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle);\r
776 FileContext->FileName = StrDuplicate (L"\\");\r
777 FileContext->DevicePath = FileDevicePath (\r
778 FileContext->Handle,\r
779 FileContext->FileName\r
780 );\r
781 FileContext->IsDir = TRUE;\r
782 FileContext->IsRoot = TRUE;\r
783 FileContext->IsRemovableMedia = RemovableMedia;\r
784 FileContext->IsLoadFile = FALSE;\r
785\r
786 //\r
787 // Get current file system's Volume Label\r
788 //\r
789 if (FileContext->Info == NULL) {\r
790 VolumeLabel = L"NO FILE SYSTEM INFO";\r
791 } else {\r
792 if (FileContext->Info->VolumeLabel == NULL) {\r
793 VolumeLabel = L"NULL VOLUME LABEL";\r
794 } else {\r
795 VolumeLabel = FileContext->Info->VolumeLabel;\r
796 if (*VolumeLabel == 0x0000) {\r
797 VolumeLabel = L"NO VOLUME LABEL";\r
798 }\r
799 }\r
800 }\r
801\r
802 TempStr = MenuEntry->HelpString;\r
803 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
804 ASSERT (MenuEntry->DisplayString != NULL);\r
805 UnicodeSPrint (\r
806 MenuEntry->DisplayString,\r
807 MAX_CHAR,\r
808 L"%s, [%s]",\r
809 VolumeLabel,\r
810 TempStr\r
811 );\r
812 OptionNumber++;\r
813 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
814 }\r
815 }\r
816\r
817 if (NoSimpleFsHandles != 0) {\r
818 FreePool (SimpleFsHandle);\r
819 }\r
20333c6d 820\r
ecc722ad 821 //\r
822 // Remember how many file system options are here\r
823 //\r
824 FsOptionMenu.MenuNumber = OptionNumber;\r
825 return EFI_SUCCESS;\r
826}\r
827\r
828\r
829/**\r
20333c6d 830 Find files under the current directory. All files and sub-directories\r
ecc722ad 831 in current directory will be stored in DirectoryMenu for future use.\r
832\r
833 @param[in] MenuEntry The Menu Entry.\r
834\r
835 @retval EFI_SUCCESS Get files from current dir successfully.\r
836 @return Other Can't get files from current dir.\r
837\r
838**/\r
839EFI_STATUS\r
840FindFiles (\r
841 IN SECUREBOOT_MENU_ENTRY *MenuEntry\r
842 )\r
843{\r
844 EFI_FILE_HANDLE NewDir;\r
845 EFI_FILE_HANDLE Dir;\r
846 EFI_FILE_INFO *DirInfo;\r
847 UINTN BufferSize;\r
848 UINTN DirBufferSize;\r
849 SECUREBOOT_MENU_ENTRY *NewMenuEntry;\r
850 SECUREBOOT_FILE_CONTEXT *FileContext;\r
851 SECUREBOOT_FILE_CONTEXT *NewFileContext;\r
852 UINTN Pass;\r
853 EFI_STATUS Status;\r
854 UINTN OptionNumber;\r
855\r
856 FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;\r
857 Dir = FileContext->FHandle;\r
858 OptionNumber = 0;\r
859 //\r
860 // Open current directory to get files from it\r
861 //\r
862 Status = Dir->Open (\r
863 Dir,\r
864 &NewDir,\r
865 FileContext->FileName,\r
866 EFI_FILE_READ_ONLY,\r
867 0\r
868 );\r
869 if (!FileContext->IsRoot) {\r
870 Dir->Close (Dir);\r
871 }\r
872\r
873 if (EFI_ERROR (Status)) {\r
874 return Status;\r
875 }\r
876\r
877 DirInfo = FileInfo (NewDir);\r
878 if (DirInfo == NULL) {\r
879 return EFI_NOT_FOUND;\r
880 }\r
881\r
882 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {\r
883 return EFI_INVALID_PARAMETER;\r
884 }\r
885\r
886 FileContext->DevicePath = FileDevicePath (\r
887 FileContext->Handle,\r
888 FileContext->FileName\r
889 );\r
890\r
891 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;\r
892 DirInfo = AllocateZeroPool (DirBufferSize);\r
893 if (DirInfo == NULL) {\r
894 return EFI_OUT_OF_RESOURCES;\r
895 }\r
20333c6d 896\r
ecc722ad 897 //\r
898 // Get all files in current directory\r
899 // Pass 1 to get Directories\r
900 // Pass 2 to get files that are EFI images\r
901 //\r
902 for (Pass = 1; Pass <= 2; Pass++) {\r
903 NewDir->SetPosition (NewDir, 0);\r
904 for (;;) {\r
905 BufferSize = DirBufferSize;\r
906 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);\r
907 if (EFI_ERROR (Status) || BufferSize == 0) {\r
908 break;\r
909 }\r
910\r
911 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||\r
912 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)\r
913 ) {\r
914 //\r
915 // Pass 1 is for Directories\r
916 // Pass 2 is for file names\r
917 //\r
918 continue;\r
919 }\r
920\r
921 NewMenuEntry = CreateMenuEntry ();\r
922 if (NULL == NewMenuEntry) {\r
923 return EFI_OUT_OF_RESOURCES;\r
924 }\r
925\r
926 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;\r
927 NewFileContext->Handle = FileContext->Handle;\r
928 NewFileContext->FileName = AppendFileName (\r
929 FileContext->FileName,\r
930 DirInfo->FileName\r
931 );\r
932 NewFileContext->FHandle = NewDir;\r
933 NewFileContext->DevicePath = FileDevicePath (\r
934 NewFileContext->Handle,\r
935 NewFileContext->FileName\r
936 );\r
937 NewMenuEntry->HelpString = NULL;\r
20333c6d 938\r
ecc722ad 939 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);\r
940 if (NewFileContext->IsDir) {\r
941 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;\r
942 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
943\r
944 UnicodeSPrint (\r
945 NewMenuEntry->DisplayString,\r
946 BufferSize,\r
947 L"<%s>",\r
948 DirInfo->FileName\r
949 );\r
950\r
951 } else {\r
952 NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName);\r
953 }\r
954\r
955 NewFileContext->IsRoot = FALSE;\r
956 NewFileContext->IsLoadFile = FALSE;\r
957 NewFileContext->IsRemovableMedia = FALSE;\r
958\r
959 NewMenuEntry->OptionNumber = OptionNumber;\r
960 OptionNumber++;\r
961 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);\r
962 }\r
963 }\r
964\r
965 DirectoryMenu.MenuNumber = OptionNumber;\r
966 FreePool (DirInfo);\r
967 return EFI_SUCCESS;\r
968}\r
969\r
970/**\r
971 Refresh the global UpdateData structure.\r
972\r
973**/\r
974VOID\r
975RefreshUpdateData (\r
976 VOID\r
977 )\r
978{\r
979 //\r
980 // Free current updated date\r
20333c6d 981 //\r
ecc722ad 982 if (mStartOpCodeHandle != NULL) {\r
983 HiiFreeOpCodeHandle (mStartOpCodeHandle);\r
984 }\r
985\r
986 //\r
987 // Create new OpCode Handle\r
988 //\r
989 mStartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
990\r
991 //\r
992 // Create Hii Extend Label OpCode as the start opcode\r
993 //\r
994 mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
995 mStartOpCodeHandle,\r
996 &gEfiIfrTianoGuid,\r
997 NULL,\r
998 sizeof (EFI_IFR_GUID_LABEL)\r
999 );\r
1000 mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
1001}\r
1002\r
1003/**\r
1004 Update the File Explore page.\r
1005\r
1006 @param[in] HiiHandle Hii Handle of the package to be updated.\r
1007 @param[in] MenuOption The Menu whose string tokens need to be updated.\r
1008 @param[in] FeCurrentState Current file explorer state.\r
1009\r
1010**/\r
1011VOID\r
1012UpdateFileExplorePage (\r
1013 IN EFI_HII_HANDLE HiiHandle,\r
1014 IN SECUREBOOT_MENU_OPTION *MenuOption,\r
1015 IN FILE_EXPLORER_STATE FeCurrentState\r
1016 )\r
1017{\r
1018 UINTN Index;\r
1019 SECUREBOOT_MENU_ENTRY *NewMenuEntry;\r
1020 SECUREBOOT_FILE_CONTEXT *NewFileContext;\r
1021 EFI_FORM_ID FormId;\r
1022 EFI_FORM_ID FileFormId;\r
1023\r
1024 if (FeCurrentState == FileExplorerStateEnrollPkFile) {\r
1025 FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;\r
1026 FileFormId = FORM_FILE_EXPLORER_ID_PK;\r
1027 } else if (FeCurrentState == FileExplorerStateEnrollKekFile) {\r
1028 FormId = FORMID_ENROLL_KEK_FORM;\r
1029 FileFormId = FORM_FILE_EXPLORER_ID_KEK;\r
1030 } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {\r
1031 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;\r
1032 FileFormId = FORM_FILE_EXPLORER_ID_DB;\r
1033 } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {\r
1034 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;\r
1035 FileFormId = FORM_FILE_EXPLORER_ID_DBX;\r
20333c6d
QL
1036 } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {\r
1037 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;\r
1038 FileFormId = FORM_FILE_EXPLORER_ID_DBT;\r
ecc722ad 1039 } else {\r
1040 return;\r
1041 }\r
1042\r
1043 NewMenuEntry = NULL;\r
1044 NewFileContext = NULL;\r
1045\r
1046 RefreshUpdateData ();\r
1047 mStartLabel->Number = FORM_FILE_EXPLORER_ID;\r
1048\r
1049 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {\r
1050 NewMenuEntry = GetMenuEntry (MenuOption, Index);\r
1051 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;\r
1052\r
1053 if (NewFileContext->IsDir) {\r
1054 //\r
1055 // Create Text opcode for directory.\r
1056 //\r
1057 HiiCreateActionOpCode (\r
1058 mStartOpCodeHandle,\r
1059 (UINT16) (FILE_OPTION_OFFSET + Index),\r
1060 NewMenuEntry->DisplayStringToken,\r
1061 STRING_TOKEN (STR_NULL),\r
1062 EFI_IFR_FLAG_CALLBACK,\r
1063 0\r
1064 );\r
1065 } else {\r
1066\r
1067 //\r
1068 // Create Goto opcode for file.\r
1069 //\r
1070 HiiCreateGotoOpCode (\r
1071 mStartOpCodeHandle,\r
1072 FormId,\r
1073 NewMenuEntry->DisplayStringToken,\r
1074 STRING_TOKEN (STR_NULL),\r
1075 EFI_IFR_FLAG_CALLBACK,\r
c93bcb7e 1076 (UINT16) (FILE_OPTION_GOTO_OFFSET + Index)\r
ecc722ad 1077 );\r
1078 }\r
1079 }\r
1080\r
1081 HiiUpdateForm (\r
1082 HiiHandle,\r
1083 &gSecureBootConfigFormSetGuid,\r
1084 FileFormId,\r
1085 mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID\r
1086 mEndOpCodeHandle // LABEL_END\r
1087 );\r
1088}\r
1089\r
1090/**\r
1091 Update the file explorer page with the refreshed file system.\r
1092\r
1093 @param[in] PrivateData Module private data.\r
1094 @param[in] KeyValue Key value to identify the type of data to expect.\r
1095\r
1096 @retval TRUE Inform the caller to create a callback packet to exit file explorer.\r
1097 @retval FALSE Indicate that there is no need to exit file explorer.\r
1098\r
1099**/\r
1100BOOLEAN\r
1101UpdateFileExplorer (\r
1102 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
1103 IN UINT16 KeyValue\r
1104 )\r
1105{\r
1106 UINT16 FileOptionMask;\r
1107 SECUREBOOT_MENU_ENTRY *NewMenuEntry;\r
1108 SECUREBOOT_FILE_CONTEXT *NewFileContext;\r
1109 EFI_FORM_ID FormId;\r
1110 BOOLEAN ExitFileExplorer;\r
1111 EFI_STATUS Status;\r
1112 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
1113\r
1114 NewMenuEntry = NULL;\r
1115 NewFileContext = NULL;\r
1116 ExitFileExplorer = FALSE;\r
1117 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);\r
1118\r
1119 if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) {\r
1120 //\r
1121 // First in, display file system.\r
1122 //\r
1123 FreeMenu (&FsOptionMenu);\r
1124 FindFileSystem ();\r
20333c6d 1125\r
ecc722ad 1126 CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu);\r
1127 UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState);\r
1128\r
1129 PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem;\r
1130 } else {\r
1131 if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) {\r
1132 NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask);\r
1133 } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) {\r
1134 NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask);\r
1135 }\r
1136\r
1137 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;\r
1138\r
1139 if (NewFileContext->IsDir ) {\r
0b716fd7
ED
1140 PrivateData->FeDisplayContext = FileExplorerDisplayDirectory;\r
1141\r
1142 RemoveEntryList (&NewMenuEntry->Link);\r
ecc722ad 1143 FreeMenu (&DirectoryMenu);\r
1144 Status = FindFiles (NewMenuEntry);\r
1145 if (EFI_ERROR (Status)) {\r
1146 ExitFileExplorer = TRUE;\r
1147 goto OnExit;\r
1148 }\r
1149 CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu);\r
0b716fd7
ED
1150 DestroyMenuEntry (NewMenuEntry);\r
1151\r
ecc722ad 1152 UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState);\r
1153\r
1154 } else {\r
1155 if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) {\r
1156 FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;\r
1157 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) {\r
1158 FormId = FORMID_ENROLL_KEK_FORM;\r
1159 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {\r
1160 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;\r
1161 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {\r
1162 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;\r
20333c6d
QL
1163 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {\r
1164 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;\r
ecc722ad 1165 } else {\r
1166 return FALSE;\r
1167 }\r
1168\r
1169 PrivateData->MenuEntry = NewMenuEntry;\r
1170 PrivateData->FileContext->FileName = NewFileContext->FileName;\r
20333c6d 1171\r
ecc722ad 1172 TmpDevicePath = NewFileContext->DevicePath;\r
1173 OpenFileByDevicePath (\r
1174 &TmpDevicePath,\r
1175 &PrivateData->FileContext->FHandle,\r
1176 EFI_FILE_MODE_READ,\r
1177 0\r
1178 );\r
1179\r
1180 //\r
1181 // Create Subtitle op-code for the display string of the option.\r
1182 //\r
1183 RefreshUpdateData ();\r
1184 mStartLabel->Number = FormId;\r
1185\r
1186 HiiCreateSubTitleOpCode (\r
1187 mStartOpCodeHandle,\r
1188 NewMenuEntry->DisplayStringToken,\r
1189 0,\r
1190 0,\r
1191 0\r
1192 );\r
1193\r
1194 HiiUpdateForm (\r
1195 PrivateData->HiiHandle,\r
1196 &gSecureBootConfigFormSetGuid,\r
1197 FormId,\r
1198 mStartOpCodeHandle, // Label FormId\r
1199 mEndOpCodeHandle // LABEL_END\r
1200 );\r
1201 }\r
1202 }\r
1203\r
1204OnExit:\r
1205 return ExitFileExplorer;\r
1206}\r
1207\r
1208/**\r
20333c6d 1209 Clean up the dynamic opcode at label and form specified by both LabelId.\r
ecc722ad 1210\r
1211 @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.\r
1212 @param[in] PrivateData Module private data.\r
1213\r
1214**/\r
1215VOID\r
1216CleanUpPage (\r
1217 IN UINT16 LabelId,\r
1218 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData\r
1219 )\r
1220{\r
1221 RefreshUpdateData ();\r
1222\r
1223 //\r
1224 // Remove all op-codes from dynamic page\r
1225 //\r
1226 mStartLabel->Number = LabelId;\r
1227 HiiUpdateForm (\r
1228 PrivateData->HiiHandle,\r
1229 &gSecureBootConfigFormSetGuid,\r
1230 LabelId,\r
1231 mStartOpCodeHandle, // Label LabelId\r
1232 mEndOpCodeHandle // LABEL_END\r
1233 );\r
1234}\r