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