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