]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
310b1ecd4e89f7934d89fcc5acd17a5b67a8a0b0
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigFileExplorer.c
1 /** @file
2 Internal file explorer functions for SecureBoot configuration module.
3
4 Copyright (c) 2012 - 2014, 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 && FileContext->DevicePath != NULL) {
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 if (MenuEntry->DisplayString != NULL) {
344 FreePool (MenuEntry->DisplayString);
345 }
346 if (MenuEntry->HelpString != NULL) {
347 FreePool (MenuEntry->HelpString);
348 }
349
350 FreePool (MenuEntry);
351 }
352
353 /**
354 Free resources allocated in Allocate Rountine.
355
356 @param[in, out] MenuOption Menu to be freed
357
358 **/
359 VOID
360 FreeMenu (
361 IN OUT SECUREBOOT_MENU_OPTION *MenuOption
362 )
363 {
364 SECUREBOOT_MENU_ENTRY *MenuEntry;
365 while (!IsListEmpty (&MenuOption->Head)) {
366 MenuEntry = CR (
367 MenuOption->Head.ForwardLink,
368 SECUREBOOT_MENU_ENTRY,
369 Link,
370 SECUREBOOT_MENU_ENTRY_SIGNATURE
371 );
372 RemoveEntryList (&MenuEntry->Link);
373 DestroyMenuEntry (MenuEntry);
374 }
375 MenuOption->MenuNumber = 0;
376 }
377
378 /**
379 This function gets the file information from an open file descriptor, and stores it
380 in a buffer allocated from pool.
381
382 @param[in] FHand File Handle.
383
384 @return A pointer to a buffer with file information or NULL is returned
385
386 **/
387 EFI_FILE_INFO *
388 FileInfo (
389 IN EFI_FILE_HANDLE FHand
390 )
391 {
392 EFI_STATUS Status;
393 EFI_FILE_INFO *Buffer;
394 UINTN BufferSize;
395
396 //
397 // Initialize for GrowBuffer loop
398 //
399 Buffer = NULL;
400 BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
401
402 //
403 // Call the real function
404 //
405 while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
406 Status = FHand->GetInfo (
407 FHand,
408 &gEfiFileInfoGuid,
409 &BufferSize,
410 Buffer
411 );
412 }
413
414 return Buffer;
415 }
416
417 /**
418 This function gets the file system information from an open file descriptor,
419 and stores it in a buffer allocated from pool.
420
421 @param[in] FHand The file handle.
422
423 @return A pointer to a buffer with file information.
424 @retval NULL is returned if failed to get Vaolume Label Info.
425
426 **/
427 EFI_FILE_SYSTEM_VOLUME_LABEL *
428 FileSystemVolumeLabelInfo (
429 IN EFI_FILE_HANDLE FHand
430 )
431 {
432 EFI_STATUS Status;
433 EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;
434 UINTN BufferSize;
435 //
436 // Initialize for GrowBuffer loop
437 //
438 Buffer = NULL;
439 BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
440
441 //
442 // Call the real function
443 //
444 while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
445 Status = FHand->GetInfo (
446 FHand,
447 &gEfiFileSystemVolumeLabelInfoIdGuid,
448 &BufferSize,
449 Buffer
450 );
451 }
452
453 return Buffer;
454 }
455
456 /**
457 This function will open a file or directory referenced by DevicePath.
458
459 This function opens a file with the open mode according to the file path. The
460 Attributes is valid only for EFI_FILE_MODE_CREATE.
461
462 @param[in, out] FilePath On input, the device path to the file.
463 On output, the remaining device path.
464 @param[out] FileHandle Pointer to the file handle.
465 @param[in] OpenMode The mode to open the file with.
466 @param[in] Attributes The file's file attributes.
467
468 @retval EFI_SUCCESS The information was set.
469 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
470 @retval EFI_UNSUPPORTED Could not open the file path.
471 @retval EFI_NOT_FOUND The specified file could not be found on the
472 device or the file system could not be found on
473 the device.
474 @retval EFI_NO_MEDIA The device has no medium.
475 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
476 medium is no longer supported.
477 @retval EFI_DEVICE_ERROR The device reported an error.
478 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
479 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
480 @retval EFI_ACCESS_DENIED The file was opened read only.
481 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
482 file.
483 @retval EFI_VOLUME_FULL The volume is full.
484 **/
485 EFI_STATUS
486 EFIAPI
487 OpenFileByDevicePath(
488 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
489 OUT EFI_FILE_HANDLE *FileHandle,
490 IN UINT64 OpenMode,
491 IN UINT64 Attributes
492 )
493 {
494 EFI_STATUS Status;
495 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
496 EFI_FILE_PROTOCOL *Handle1;
497 EFI_FILE_PROTOCOL *Handle2;
498 EFI_HANDLE DeviceHandle;
499
500 if ((FilePath == NULL || FileHandle == NULL)) {
501 return EFI_INVALID_PARAMETER;
502 }
503
504 Status = gBS->LocateDevicePath (
505 &gEfiSimpleFileSystemProtocolGuid,
506 FilePath,
507 &DeviceHandle
508 );
509 if (EFI_ERROR (Status)) {
510 return Status;
511 }
512
513 Status = gBS->OpenProtocol(
514 DeviceHandle,
515 &gEfiSimpleFileSystemProtocolGuid,
516 (VOID**)&EfiSimpleFileSystemProtocol,
517 gImageHandle,
518 NULL,
519 EFI_OPEN_PROTOCOL_GET_PROTOCOL
520 );
521 if (EFI_ERROR (Status)) {
522 return Status;
523 }
524
525 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
526 if (EFI_ERROR (Status)) {
527 FileHandle = NULL;
528 return Status;
529 }
530
531 //
532 // go down directories one node at a time.
533 //
534 while (!IsDevicePathEnd (*FilePath)) {
535 //
536 // For file system access each node should be a file path component
537 //
538 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
539 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
540 ) {
541 FileHandle = NULL;
542 return (EFI_INVALID_PARAMETER);
543 }
544 //
545 // Open this file path node
546 //
547 Handle2 = Handle1;
548 Handle1 = NULL;
549
550 //
551 // Try to test opening an existing file
552 //
553 Status = Handle2->Open (
554 Handle2,
555 &Handle1,
556 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
557 OpenMode &~EFI_FILE_MODE_CREATE,
558 0
559 );
560
561 //
562 // see if the error was that it needs to be created
563 //
564 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
565 Status = Handle2->Open (
566 Handle2,
567 &Handle1,
568 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
569 OpenMode,
570 Attributes
571 );
572 }
573 //
574 // Close the last node
575 //
576 Handle2->Close (Handle2);
577
578 if (EFI_ERROR(Status)) {
579 return (Status);
580 }
581
582 //
583 // Get the next node
584 //
585 *FilePath = NextDevicePathNode (*FilePath);
586 }
587
588 //
589 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
590 //
591 *FileHandle = (VOID*)Handle1;
592 return EFI_SUCCESS;
593 }
594
595 /**
596 Function opens and returns a file handle to the root directory of a volume.
597
598 @param[in] DeviceHandle A handle for a device
599
600 @return A valid file handle or NULL if error happens.
601
602 **/
603 EFI_FILE_HANDLE
604 OpenRoot (
605 IN EFI_HANDLE DeviceHandle
606 )
607 {
608 EFI_STATUS Status;
609 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
610 EFI_FILE_HANDLE File;
611
612 File = NULL;
613
614 //
615 // File the file system interface to the device
616 //
617 Status = gBS->HandleProtocol (
618 DeviceHandle,
619 &gEfiSimpleFileSystemProtocolGuid,
620 (VOID *) &Volume
621 );
622
623 //
624 // Open the root directory of the volume
625 //
626 if (!EFI_ERROR (Status)) {
627 Status = Volume->OpenVolume (
628 Volume,
629 &File
630 );
631 }
632 //
633 // Done
634 //
635 return EFI_ERROR (Status) ? NULL : File;
636 }
637
638 /**
639 This function builds the FsOptionMenu list which records all
640 available file system in the system. They include all instances
641 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
642 and all type of legacy boot device.
643
644 @retval EFI_SUCCESS Success find the file system
645 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
646
647 **/
648 EFI_STATUS
649 FindFileSystem (
650 VOID
651 )
652 {
653 UINTN NoBlkIoHandles;
654 UINTN NoSimpleFsHandles;
655 UINTN NoLoadFileHandles;
656 EFI_HANDLE *BlkIoHandle;
657 EFI_HANDLE *SimpleFsHandle;
658 UINT16 *VolumeLabel;
659 EFI_BLOCK_IO_PROTOCOL *BlkIo;
660 UINTN Index;
661 EFI_STATUS Status;
662 SECUREBOOT_MENU_ENTRY *MenuEntry;
663 SECUREBOOT_FILE_CONTEXT *FileContext;
664 UINT16 *TempStr;
665 UINTN OptionNumber;
666 VOID *Buffer;
667
668 BOOLEAN RemovableMedia;
669
670
671 NoSimpleFsHandles = 0;
672 NoLoadFileHandles = 0;
673 OptionNumber = 0;
674 InitializeListHead (&FsOptionMenu.Head);
675
676 //
677 // Locate Handles that support BlockIo protocol
678 //
679 Status = gBS->LocateHandleBuffer (
680 ByProtocol,
681 &gEfiBlockIoProtocolGuid,
682 NULL,
683 &NoBlkIoHandles,
684 &BlkIoHandle
685 );
686 if (!EFI_ERROR (Status)) {
687
688 for (Index = 0; Index < NoBlkIoHandles; Index++) {
689 Status = gBS->HandleProtocol (
690 BlkIoHandle[Index],
691 &gEfiBlockIoProtocolGuid,
692 (VOID **) &BlkIo
693 );
694
695 if (EFI_ERROR (Status)) {
696 continue;
697 }
698
699 //
700 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
701 //
702 if (BlkIo->Media->RemovableMedia) {
703 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
704 if (NULL == Buffer) {
705 FreePool (BlkIoHandle);
706 return EFI_OUT_OF_RESOURCES;
707 }
708
709 BlkIo->ReadBlocks (
710 BlkIo,
711 BlkIo->Media->MediaId,
712 0,
713 BlkIo->Media->BlockSize,
714 Buffer
715 );
716 FreePool (Buffer);
717 }
718 }
719 FreePool (BlkIoHandle);
720 }
721
722 //
723 // Locate Handles that support Simple File System protocol
724 //
725 Status = gBS->LocateHandleBuffer (
726 ByProtocol,
727 &gEfiSimpleFileSystemProtocolGuid,
728 NULL,
729 &NoSimpleFsHandles,
730 &SimpleFsHandle
731 );
732 if (!EFI_ERROR (Status)) {
733 //
734 // Find all the instances of the File System prototocol
735 //
736 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
737 Status = gBS->HandleProtocol (
738 SimpleFsHandle[Index],
739 &gEfiBlockIoProtocolGuid,
740 (VOID **) &BlkIo
741 );
742 if (EFI_ERROR (Status)) {
743 //
744 // If no block IO exists assume it's NOT a removable media
745 //
746 RemovableMedia = FALSE;
747 } else {
748 //
749 // If block IO exists check to see if it's remobable media
750 //
751 RemovableMedia = BlkIo->Media->RemovableMedia;
752 }
753
754 //
755 // Allocate pool for this instance.
756 //
757 MenuEntry = CreateMenuEntry ();
758 if (NULL == MenuEntry) {
759 FreePool (SimpleFsHandle);
760 return EFI_OUT_OF_RESOURCES;
761 }
762
763 FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
764
765 FileContext->Handle = SimpleFsHandle[Index];
766 MenuEntry->OptionNumber = Index;
767 FileContext->FHandle = OpenRoot (FileContext->Handle);
768 if (FileContext->FHandle == NULL) {
769 DestroyMenuEntry (MenuEntry);
770 continue;
771 }
772
773 MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
774 FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle);
775 FileContext->FileName = StrDuplicate (L"\\");
776 FileContext->DevicePath = FileDevicePath (
777 FileContext->Handle,
778 FileContext->FileName
779 );
780 FileContext->IsDir = TRUE;
781 FileContext->IsRoot = TRUE;
782 FileContext->IsRemovableMedia = RemovableMedia;
783 FileContext->IsLoadFile = FALSE;
784
785 //
786 // Get current file system's Volume Label
787 //
788 if (FileContext->Info == NULL) {
789 VolumeLabel = L"NO FILE SYSTEM INFO";
790 } else {
791 if (FileContext->Info->VolumeLabel == NULL) {
792 VolumeLabel = L"NULL VOLUME LABEL";
793 } else {
794 VolumeLabel = FileContext->Info->VolumeLabel;
795 if (*VolumeLabel == 0x0000) {
796 VolumeLabel = L"NO VOLUME LABEL";
797 }
798 }
799 }
800
801 TempStr = MenuEntry->HelpString;
802 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
803 ASSERT (MenuEntry->DisplayString != NULL);
804 UnicodeSPrint (
805 MenuEntry->DisplayString,
806 MAX_CHAR,
807 L"%s, [%s]",
808 VolumeLabel,
809 TempStr
810 );
811 OptionNumber++;
812 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
813 }
814 }
815
816 if (NoSimpleFsHandles != 0) {
817 FreePool (SimpleFsHandle);
818 }
819
820 //
821 // Remember how many file system options are here
822 //
823 FsOptionMenu.MenuNumber = OptionNumber;
824 return EFI_SUCCESS;
825 }
826
827
828 /**
829 Find files under the current directory. All files and sub-directories
830 in current directory will be stored in DirectoryMenu for future use.
831
832 @param[in] MenuEntry The Menu Entry.
833
834 @retval EFI_SUCCESS Get files from current dir successfully.
835 @return Other Can't get files from current dir.
836
837 **/
838 EFI_STATUS
839 FindFiles (
840 IN SECUREBOOT_MENU_ENTRY *MenuEntry
841 )
842 {
843 EFI_FILE_HANDLE NewDir;
844 EFI_FILE_HANDLE Dir;
845 EFI_FILE_INFO *DirInfo;
846 UINTN BufferSize;
847 UINTN DirBufferSize;
848 SECUREBOOT_MENU_ENTRY *NewMenuEntry;
849 SECUREBOOT_FILE_CONTEXT *FileContext;
850 SECUREBOOT_FILE_CONTEXT *NewFileContext;
851 UINTN Pass;
852 EFI_STATUS Status;
853 UINTN OptionNumber;
854
855 FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
856 Dir = FileContext->FHandle;
857 OptionNumber = 0;
858 //
859 // Open current directory to get files from it
860 //
861 Status = Dir->Open (
862 Dir,
863 &NewDir,
864 FileContext->FileName,
865 EFI_FILE_READ_ONLY,
866 0
867 );
868 if (!FileContext->IsRoot) {
869 Dir->Close (Dir);
870 }
871
872 if (EFI_ERROR (Status)) {
873 return Status;
874 }
875
876 DirInfo = FileInfo (NewDir);
877 if (DirInfo == NULL) {
878 return EFI_NOT_FOUND;
879 }
880
881 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
882 return EFI_INVALID_PARAMETER;
883 }
884
885 FileContext->DevicePath = FileDevicePath (
886 FileContext->Handle,
887 FileContext->FileName
888 );
889
890 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
891 DirInfo = AllocateZeroPool (DirBufferSize);
892 if (DirInfo == NULL) {
893 return EFI_OUT_OF_RESOURCES;
894 }
895
896 //
897 // Get all files in current directory
898 // Pass 1 to get Directories
899 // Pass 2 to get files that are EFI images
900 //
901 for (Pass = 1; Pass <= 2; Pass++) {
902 NewDir->SetPosition (NewDir, 0);
903 for (;;) {
904 BufferSize = DirBufferSize;
905 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
906 if (EFI_ERROR (Status) || BufferSize == 0) {
907 break;
908 }
909
910 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
911 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
912 ) {
913 //
914 // Pass 1 is for Directories
915 // Pass 2 is for file names
916 //
917 continue;
918 }
919
920 NewMenuEntry = CreateMenuEntry ();
921 if (NULL == NewMenuEntry) {
922 return EFI_OUT_OF_RESOURCES;
923 }
924
925 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
926 NewFileContext->Handle = FileContext->Handle;
927 NewFileContext->FileName = AppendFileName (
928 FileContext->FileName,
929 DirInfo->FileName
930 );
931 NewFileContext->FHandle = NewDir;
932 NewFileContext->DevicePath = FileDevicePath (
933 NewFileContext->Handle,
934 NewFileContext->FileName
935 );
936 NewMenuEntry->HelpString = NULL;
937
938 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
939 if (NewFileContext->IsDir) {
940 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
941 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
942
943 UnicodeSPrint (
944 NewMenuEntry->DisplayString,
945 BufferSize,
946 L"<%s>",
947 DirInfo->FileName
948 );
949
950 } else {
951 NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName);
952 }
953
954 NewFileContext->IsRoot = FALSE;
955 NewFileContext->IsLoadFile = FALSE;
956 NewFileContext->IsRemovableMedia = FALSE;
957
958 NewMenuEntry->OptionNumber = OptionNumber;
959 OptionNumber++;
960 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
961 }
962 }
963
964 DirectoryMenu.MenuNumber = OptionNumber;
965 FreePool (DirInfo);
966 return EFI_SUCCESS;
967 }
968
969 /**
970 Refresh the global UpdateData structure.
971
972 **/
973 VOID
974 RefreshUpdateData (
975 VOID
976 )
977 {
978 //
979 // Free current updated date
980 //
981 if (mStartOpCodeHandle != NULL) {
982 HiiFreeOpCodeHandle (mStartOpCodeHandle);
983 }
984
985 //
986 // Create new OpCode Handle
987 //
988 mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
989
990 //
991 // Create Hii Extend Label OpCode as the start opcode
992 //
993 mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
994 mStartOpCodeHandle,
995 &gEfiIfrTianoGuid,
996 NULL,
997 sizeof (EFI_IFR_GUID_LABEL)
998 );
999 mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1000 }
1001
1002 /**
1003 Update the File Explore page.
1004
1005 @param[in] HiiHandle Hii Handle of the package to be updated.
1006 @param[in] MenuOption The Menu whose string tokens need to be updated.
1007 @param[in] FeCurrentState Current file explorer state.
1008
1009 **/
1010 VOID
1011 UpdateFileExplorePage (
1012 IN EFI_HII_HANDLE HiiHandle,
1013 IN SECUREBOOT_MENU_OPTION *MenuOption,
1014 IN FILE_EXPLORER_STATE FeCurrentState
1015 )
1016 {
1017 UINTN Index;
1018 SECUREBOOT_MENU_ENTRY *NewMenuEntry;
1019 SECUREBOOT_FILE_CONTEXT *NewFileContext;
1020 EFI_FORM_ID FormId;
1021 EFI_FORM_ID FileFormId;
1022
1023 if (FeCurrentState == FileExplorerStateEnrollPkFile) {
1024 FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
1025 FileFormId = FORM_FILE_EXPLORER_ID_PK;
1026 } else if (FeCurrentState == FileExplorerStateEnrollKekFile) {
1027 FormId = FORMID_ENROLL_KEK_FORM;
1028 FileFormId = FORM_FILE_EXPLORER_ID_KEK;
1029 } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
1030 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
1031 FileFormId = FORM_FILE_EXPLORER_ID_DB;
1032 } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
1033 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
1034 FileFormId = FORM_FILE_EXPLORER_ID_DBX;
1035 } else {
1036 return;
1037 }
1038
1039 NewMenuEntry = NULL;
1040 NewFileContext = NULL;
1041
1042 RefreshUpdateData ();
1043 mStartLabel->Number = FORM_FILE_EXPLORER_ID;
1044
1045 for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
1046 NewMenuEntry = GetMenuEntry (MenuOption, Index);
1047 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
1048
1049 if (NewFileContext->IsDir) {
1050 //
1051 // Create Text opcode for directory.
1052 //
1053 HiiCreateActionOpCode (
1054 mStartOpCodeHandle,
1055 (UINT16) (FILE_OPTION_OFFSET + Index),
1056 NewMenuEntry->DisplayStringToken,
1057 STRING_TOKEN (STR_NULL),
1058 EFI_IFR_FLAG_CALLBACK,
1059 0
1060 );
1061 } else {
1062
1063 //
1064 // Create Goto opcode for file.
1065 //
1066 HiiCreateGotoOpCode (
1067 mStartOpCodeHandle,
1068 FormId,
1069 NewMenuEntry->DisplayStringToken,
1070 STRING_TOKEN (STR_NULL),
1071 EFI_IFR_FLAG_CALLBACK,
1072 (UINT16) (FILE_OPTION_GOTO_OFFSET + Index)
1073 );
1074 }
1075 }
1076
1077 HiiUpdateForm (
1078 HiiHandle,
1079 &gSecureBootConfigFormSetGuid,
1080 FileFormId,
1081 mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
1082 mEndOpCodeHandle // LABEL_END
1083 );
1084 }
1085
1086 /**
1087 Update the file explorer page with the refreshed file system.
1088
1089 @param[in] PrivateData Module private data.
1090 @param[in] KeyValue Key value to identify the type of data to expect.
1091
1092 @retval TRUE Inform the caller to create a callback packet to exit file explorer.
1093 @retval FALSE Indicate that there is no need to exit file explorer.
1094
1095 **/
1096 BOOLEAN
1097 UpdateFileExplorer (
1098 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
1099 IN UINT16 KeyValue
1100 )
1101 {
1102 UINT16 FileOptionMask;
1103 SECUREBOOT_MENU_ENTRY *NewMenuEntry;
1104 SECUREBOOT_FILE_CONTEXT *NewFileContext;
1105 EFI_FORM_ID FormId;
1106 BOOLEAN ExitFileExplorer;
1107 EFI_STATUS Status;
1108 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
1109
1110 NewMenuEntry = NULL;
1111 NewFileContext = NULL;
1112 ExitFileExplorer = FALSE;
1113 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
1114
1115 if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) {
1116 //
1117 // First in, display file system.
1118 //
1119 FreeMenu (&FsOptionMenu);
1120 FindFileSystem ();
1121
1122 CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu);
1123 UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState);
1124
1125 PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem;
1126 } else {
1127 if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) {
1128 NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask);
1129 } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) {
1130 NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask);
1131 }
1132
1133 NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
1134
1135 if (NewFileContext->IsDir ) {
1136 PrivateData->FeDisplayContext = FileExplorerDisplayDirectory;
1137
1138 RemoveEntryList (&NewMenuEntry->Link);
1139 FreeMenu (&DirectoryMenu);
1140 Status = FindFiles (NewMenuEntry);
1141 if (EFI_ERROR (Status)) {
1142 ExitFileExplorer = TRUE;
1143 goto OnExit;
1144 }
1145 CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu);
1146 DestroyMenuEntry (NewMenuEntry);
1147
1148 UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState);
1149
1150 } else {
1151 if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) {
1152 FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
1153 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) {
1154 FormId = FORMID_ENROLL_KEK_FORM;
1155 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
1156 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
1157 } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
1158 FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
1159 } else {
1160 return FALSE;
1161 }
1162
1163 PrivateData->MenuEntry = NewMenuEntry;
1164 PrivateData->FileContext->FileName = NewFileContext->FileName;
1165
1166 TmpDevicePath = NewFileContext->DevicePath;
1167 OpenFileByDevicePath (
1168 &TmpDevicePath,
1169 &PrivateData->FileContext->FHandle,
1170 EFI_FILE_MODE_READ,
1171 0
1172 );
1173
1174 //
1175 // Create Subtitle op-code for the display string of the option.
1176 //
1177 RefreshUpdateData ();
1178 mStartLabel->Number = FormId;
1179
1180 HiiCreateSubTitleOpCode (
1181 mStartOpCodeHandle,
1182 NewMenuEntry->DisplayStringToken,
1183 0,
1184 0,
1185 0
1186 );
1187
1188 HiiUpdateForm (
1189 PrivateData->HiiHandle,
1190 &gSecureBootConfigFormSetGuid,
1191 FormId,
1192 mStartOpCodeHandle, // Label FormId
1193 mEndOpCodeHandle // LABEL_END
1194 );
1195 }
1196 }
1197
1198 OnExit:
1199 return ExitFileExplorer;
1200 }
1201
1202 /**
1203 Clean up the dynamic opcode at label and form specified by both LabelId.
1204
1205 @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.
1206 @param[in] PrivateData Module private data.
1207
1208 **/
1209 VOID
1210 CleanUpPage (
1211 IN UINT16 LabelId,
1212 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
1213 )
1214 {
1215 RefreshUpdateData ();
1216
1217 //
1218 // Remove all op-codes from dynamic page
1219 //
1220 mStartLabel->Number = LabelId;
1221 HiiUpdateForm (
1222 PrivateData->HiiHandle,
1223 &gSecureBootConfigFormSetGuid,
1224 LabelId,
1225 mStartOpCodeHandle, // Label LabelId
1226 mEndOpCodeHandle // LABEL_END
1227 );
1228 }
1229