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