summaryrefslogtreecommitdiff
path: root/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
diff options
context:
space:
mode:
Diffstat (limited to 'SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c')
-rw-r--r--SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c1227
1 files changed, 1227 insertions, 0 deletions
diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
new file mode 100644
index 0000000000..deff87bcbd
--- /dev/null
+++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
@@ -0,0 +1,1227 @@
+/** @file
+ Internal file explorer functions for SecureBoot configuration module.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+///
+/// File system selection menu
+///
+SECUREBOOT_MENU_OPTION FsOptionMenu = {
+ SECUREBOOT_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Files and sub-directories in current directory menu
+///
+SECUREBOOT_MENU_OPTION DirectoryMenu = {
+ SECUREBOOT_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+VOID *mStartOpCodeHandle = NULL;
+VOID *mEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mEndLabel = NULL;
+
+/**
+ Duplicate a string.
+
+ @param[in] Src The source string.
+
+ @return A new string which is duplicated copy of the source,
+ or NULL if there is not enough memory.
+
+**/
+CHAR16 *
+StrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = StrSize (Src);
+ Dest = AllocateZeroPool (Size);
+ ASSERT (Dest != NULL);
+ if (Dest != NULL) {
+ CopyMem (Dest, Src, Size);
+ }
+
+ return Dest;
+}
+
+/**
+ Helper function called as part of the code needed to allocate
+ the proper sized buffer for various EFI interfaces.
+
+ @param[in, out] Status Current status
+ @param[in, out] Buffer Current allocated buffer, or NULL
+ @param[in] BufferSize Current buffer size needed
+
+ @retval TRUE If the buffer was reallocated and the caller
+ should try the API again.
+ @retval FALSE The caller should not call this function again.
+
+**/
+BOOLEAN
+GrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+{
+ BOOLEAN TryAgain;
+
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if ((*Buffer == NULL) && (BufferSize != 0)) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+ TryAgain = FALSE;
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+
+ if (*Buffer != NULL) {
+ FreePool (*Buffer);
+ }
+
+ *Buffer = AllocateZeroPool (BufferSize);
+
+ if (*Buffer != NULL) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // If there's an error, free the buffer
+ //
+ if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+
+/**
+ Append file name to existing file name, and allocate a new buffer
+ to hold the appended result.
+
+ @param[in] Str1 The existing file name
+ @param[in] Str2 The file name to be appended
+
+ @return A new string with appended result.
+
+**/
+CHAR16 *
+AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+ CHAR16 *Str;
+ CHAR16 *TmpStr;
+ CHAR16 *Ptr;
+ CHAR16 *LastSlash;
+
+ Size1 = StrSize (Str1);
+ Size2 = StrSize (Str2);
+ Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
+ ASSERT (TmpStr != NULL);
+
+ StrCat (Str, Str1);
+ if (!((*Str == '\\') && (*(Str + 1) == 0))) {
+ StrCat (Str, L"\\");
+ }
+
+ StrCat (Str, Str2);
+
+ Ptr = Str;
+ LastSlash = Str;
+ while (*Ptr != 0) {
+ if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
+ //
+ // Convert "\Name\..\" to "\"
+ // DO NOT convert the .. if it is at the end of the string. This will
+ // break the .. behavior in changing directories.
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpy (TmpStr, Ptr + 3);
+ StrCpy (LastSlash, TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
+ //
+ // Convert a "\.\" to a "\"
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpy (TmpStr, Ptr + 2);
+ StrCpy (Ptr, TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\') {
+ LastSlash = Ptr;
+ }
+
+ Ptr++;
+ }
+
+ FreePool (TmpStr);
+
+ return Str;
+}
+
+/**
+ Create a SECUREBOOT_MENU_ENTRY, and stores it in a buffer allocated from the pool.
+
+ @return The new menu entry or NULL of error happens.
+
+**/
+SECUREBOOT_MENU_ENTRY *
+CreateMenuEntry (
+ VOID
+ )
+{
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ UINTN ContextSize;
+
+ //
+ // Create new menu entry
+ //
+ MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));
+ if (MenuEntry == NULL) {
+ return NULL;
+ }
+
+ ContextSize = sizeof (SECUREBOOT_FILE_CONTEXT);
+ MenuEntry->FileContext = AllocateZeroPool (ContextSize);
+ if (MenuEntry->FileContext == NULL) {
+ FreePool (MenuEntry);
+ return NULL;
+ }
+
+ MenuEntry->Signature = SECUREBOOT_MENU_ENTRY_SIGNATURE;
+
+ return MenuEntry;
+}
+
+/**
+ Get Menu Entry from the Menu Entry List by MenuNumber.
+
+ If MenuNumber is great or equal to the number of Menu
+ Entry in the list, then ASSERT.
+
+ @param[in] MenuOption The Menu Entry List to read the menu entry.
+ @param[in] MenuNumber The index of Menu Entry.
+
+ @return The Menu Entry.
+
+**/
+SECUREBOOT_MENU_ENTRY *
+GetMenuEntry (
+ IN SECUREBOOT_MENU_OPTION *MenuOption,
+ IN UINTN MenuNumber
+ )
+{
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+ LIST_ENTRY *List;
+
+ ASSERT (MenuNumber < MenuOption->MenuNumber);
+
+ List = MenuOption->Head.ForwardLink;
+ for (Index = 0; Index < MenuNumber; Index++) {
+ List = List->ForwardLink;
+ }
+
+ NewMenuEntry = CR (List, SECUREBOOT_MENU_ENTRY, Link, SECUREBOOT_MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+/**
+ Create string tokens for a menu from its help strings and display strings.
+
+ @param[in] HiiHandle Hii Handle of the package to be updated.
+ @param[in] MenuOption The Menu whose string tokens need to be created.
+
+**/
+VOID
+CreateMenuStringToken (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN SECUREBOOT_MENU_OPTION *MenuOption
+ )
+{
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (MenuOption, Index);
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->DisplayString,
+ NULL
+ );
+
+ if (NewMenuEntry->HelpString == NULL) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ NewMenuEntry->HelpStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->HelpString,
+ NULL
+ );
+ }
+ }
+}
+
+/**
+ Free up all resources allocated for a SECUREBOOT_MENU_ENTRY.
+
+ @param[in, out] MenuEntry A pointer to SECUREBOOT_MENU_ENTRY.
+
+**/
+VOID
+DestroyMenuEntry (
+ IN OUT SECUREBOOT_MENU_ENTRY *MenuEntry
+ )
+{
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+
+ if (!FileContext->IsRoot) {
+ FreePool (FileContext->DevicePath);
+ } else {
+ if (FileContext->FHandle != NULL) {
+ FileContext->FHandle->Close (FileContext->FHandle);
+ }
+ }
+
+ if (FileContext->FileName != NULL) {
+ FreePool (FileContext->FileName);
+ }
+ if (FileContext->Info != NULL) {
+ FreePool (FileContext->Info);
+ }
+
+ FreePool (FileContext);
+
+ FreePool (MenuEntry->DisplayString);
+ if (MenuEntry->HelpString != NULL) {
+ FreePool (MenuEntry->HelpString);
+ }
+
+ FreePool (MenuEntry);
+}
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param[in, out] MenuOption Menu to be freed
+
+**/
+VOID
+FreeMenu (
+ IN OUT SECUREBOOT_MENU_OPTION *MenuOption
+ )
+{
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ while (!IsListEmpty (&MenuOption->Head)) {
+ MenuEntry = CR (
+ MenuOption->Head.ForwardLink,
+ SECUREBOOT_MENU_ENTRY,
+ Link,
+ SECUREBOOT_MENU_ENTRY_SIGNATURE
+ );
+ RemoveEntryList (&MenuEntry->Link);
+ DestroyMenuEntry (MenuEntry);
+ }
+ MenuOption->MenuNumber = 0;
+}
+
+/**
+ This function gets the file information from an open file descriptor, and stores it
+ in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ This function gets the file system information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand The file handle.
+
+ @return A pointer to a buffer with file information.
+ @retval NULL is returned if failed to get Vaolume Label Info.
+
+**/
+EFI_FILE_SYSTEM_VOLUME_LABEL *
+FileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;
+ UINTN BufferSize;
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
+
+ //
+ // Call the real function
+ //
+ while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileSystemVolumeLabelInfoIdGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ This function will open a file or directory referenced by DevicePath.
+
+ This function opens a file with the open mode according to the file path. The
+ Attributes is valid only for EFI_FILE_MODE_CREATE.
+
+ @param[in, out] FilePath On input, the device path to the file.
+ On output, the remaining device path.
+ @param[out] FileHandle Pointer to the file handle.
+ @param[in] OpenMode The mode to open the file with.
+ @param[in] Attributes The file's file attributes.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found on
+ the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+OpenFileByDevicePath(
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT EFI_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
+ EFI_FILE_PROTOCOL *Handle1;
+ EFI_FILE_PROTOCOL *Handle2;
+ EFI_HANDLE DeviceHandle;
+
+ if ((FilePath == NULL || FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ FilePath,
+ &DeviceHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol(
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**)&EfiSimpleFileSystemProtocol,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
+ if (EFI_ERROR (Status)) {
+ FileHandle = NULL;
+ return Status;
+ }
+
+ //
+ // go down directories one node at a time.
+ //
+ while (!IsDevicePathEnd (*FilePath)) {
+ //
+ // For file system access each node should be a file path component
+ //
+ if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
+ ) {
+ FileHandle = NULL;
+ return (EFI_INVALID_PARAMETER);
+ }
+ //
+ // Open this file path node
+ //
+ Handle2 = Handle1;
+ Handle1 = NULL;
+
+ //
+ // Try to test opening an existing file
+ //
+ Status = Handle2->Open (
+ Handle2,
+ &Handle1,
+ ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
+ OpenMode &~EFI_FILE_MODE_CREATE,
+ 0
+ );
+
+ //
+ // see if the error was that it needs to be created
+ //
+ if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
+ Status = Handle2->Open (
+ Handle2,
+ &Handle1,
+ ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
+ OpenMode,
+ Attributes
+ );
+ }
+ //
+ // Close the last node
+ //
+ Handle2->Close (Handle2);
+
+ if (EFI_ERROR(Status)) {
+ return (Status);
+ }
+
+ //
+ // Get the next node
+ //
+ *FilePath = NextDevicePathNode (*FilePath);
+ }
+
+ //
+ // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
+ //
+ *FileHandle = (VOID*)Handle1;
+ return EFI_SUCCESS;
+}
+
+/**
+ Function opens and returns a file handle to the root directory of a volume.
+
+ @param[in] DeviceHandle A handle for a device
+
+ @return A valid file handle or NULL if error happens.
+
+**/
+EFI_FILE_HANDLE
+OpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE File;
+
+ File = NULL;
+
+ //
+ // File the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+
+ //
+ // Open the root directory of the volume
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = Volume->OpenVolume (
+ Volume,
+ &File
+ );
+ }
+ //
+ // Done
+ //
+ return EFI_ERROR (Status) ? NULL : File;
+}
+
+/**
+ This function builds the FsOptionMenu list which records all
+ available file system in the system. They include all instances
+ of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
+ and all type of legacy boot device.
+
+ @retval EFI_SUCCESS Success find the file system
+ @retval EFI_OUT_OF_RESOURCES Can not create menu entry
+
+**/
+EFI_STATUS
+FindFileSystem (
+ VOID
+ )
+{
+ UINTN NoBlkIoHandles;
+ UINTN NoSimpleFsHandles;
+ UINTN NoLoadFileHandles;
+ EFI_HANDLE *BlkIoHandle;
+ EFI_HANDLE *SimpleFsHandle;
+ UINT16 *VolumeLabel;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Index;
+ EFI_STATUS Status;
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+ UINT16 *TempStr;
+ UINTN OptionNumber;
+ VOID *Buffer;
+
+ BOOLEAN RemovableMedia;
+
+
+ NoSimpleFsHandles = 0;
+ NoLoadFileHandles = 0;
+ OptionNumber = 0;
+ InitializeListHead (&FsOptionMenu.Head);
+
+ //
+ // Locate Handles that support BlockIo protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NoBlkIoHandles,
+ &BlkIoHandle
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = 0; Index < NoBlkIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlkIoHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
+ //
+ if (BlkIo->Media->RemovableMedia) {
+ Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
+ if (NULL == Buffer) {
+ FreePool (BlkIoHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo->ReadBlocks (
+ BlkIo,
+ BlkIo->Media->MediaId,
+ 0,
+ BlkIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
+ }
+ }
+ FreePool (BlkIoHandle);
+ }
+
+ //
+ // Locate Handles that support Simple File System protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoSimpleFsHandles,
+ &SimpleFsHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find all the instances of the File System prototocol
+ //
+ for (Index = 0; Index < NoSimpleFsHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ SimpleFsHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no block IO exists assume it's NOT a removable media
+ //
+ RemovableMedia = FALSE;
+ } else {
+ //
+ // If block IO exists check to see if it's remobable media
+ //
+ RemovableMedia = BlkIo->Media->RemovableMedia;
+ }
+
+ //
+ // Allocate pool for this instance.
+ //
+ MenuEntry = CreateMenuEntry ();
+ if (NULL == MenuEntry) {
+ FreePool (SimpleFsHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+
+ FileContext->Handle = SimpleFsHandle[Index];
+ MenuEntry->OptionNumber = Index;
+ FileContext->FHandle = OpenRoot (FileContext->Handle);
+ if (FileContext->FHandle == NULL) {
+ DestroyMenuEntry (MenuEntry);
+ continue;
+ }
+
+ MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
+ FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle);
+ FileContext->FileName = StrDuplicate (L"\\");
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+ FileContext->IsDir = TRUE;
+ FileContext->IsRoot = TRUE;
+ FileContext->IsRemovableMedia = RemovableMedia;
+ FileContext->IsLoadFile = FALSE;
+
+ //
+ // Get current file system's Volume Label
+ //
+ if (FileContext->Info == NULL) {
+ VolumeLabel = L"NO FILE SYSTEM INFO";
+ } else {
+ if (FileContext->Info->VolumeLabel == NULL) {
+ VolumeLabel = L"NULL VOLUME LABEL";
+ } else {
+ VolumeLabel = FileContext->Info->VolumeLabel;
+ if (*VolumeLabel == 0x0000) {
+ VolumeLabel = L"NO VOLUME LABEL";
+ }
+ }
+ }
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"%s, [%s]",
+ VolumeLabel,
+ TempStr
+ );
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoSimpleFsHandles != 0) {
+ FreePool (SimpleFsHandle);
+ }
+
+ //
+ // Remember how many file system options are here
+ //
+ FsOptionMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find files under the current directory. All files and sub-directories
+ in current directory will be stored in DirectoryMenu for future use.
+
+ @param[in] MenuEntry The Menu Entry.
+
+ @retval EFI_SUCCESS Get files from current dir successfully.
+ @return Other Can't get files from current dir.
+
+**/
+EFI_STATUS
+FindFiles (
+ IN SECUREBOOT_MENU_ENTRY *MenuEntry
+ )
+{
+ EFI_FILE_HANDLE NewDir;
+ EFI_FILE_HANDLE Dir;
+ EFI_FILE_INFO *DirInfo;
+ UINTN BufferSize;
+ UINTN DirBufferSize;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ UINTN Pass;
+ EFI_STATUS Status;
+ UINTN OptionNumber;
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+ Dir = FileContext->FHandle;
+ OptionNumber = 0;
+ //
+ // Open current directory to get files from it
+ //
+ Status = Dir->Open (
+ Dir,
+ &NewDir,
+ FileContext->FileName,
+ EFI_FILE_READ_ONLY,
+ 0
+ );
+ if (!FileContext->IsRoot) {
+ Dir->Close (Dir);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DirInfo = FileInfo (NewDir);
+ if (DirInfo == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+
+ DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
+ DirInfo = AllocateZeroPool (DirBufferSize);
+ if (DirInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get all files in current directory
+ // Pass 1 to get Directories
+ // Pass 2 to get files that are EFI images
+ //
+ for (Pass = 1; Pass <= 2; Pass++) {
+ NewDir->SetPosition (NewDir, 0);
+ for (;;) {
+ BufferSize = DirBufferSize;
+ Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
+ if (EFI_ERROR (Status) || BufferSize == 0) {
+ break;
+ }
+
+ if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
+ ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
+ ) {
+ //
+ // Pass 1 is for Directories
+ // Pass 2 is for file names
+ //
+ continue;
+ }
+
+ NewMenuEntry = CreateMenuEntry ();
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+ NewFileContext->Handle = FileContext->Handle;
+ NewFileContext->FileName = AppendFileName (
+ FileContext->FileName,
+ DirInfo->FileName
+ );
+ NewFileContext->FHandle = NewDir;
+ NewFileContext->DevicePath = FileDevicePath (
+ NewFileContext->Handle,
+ NewFileContext->FileName
+ );
+ NewMenuEntry->HelpString = NULL;
+
+ NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
+ if (NewFileContext->IsDir) {
+ BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
+ NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
+
+ UnicodeSPrint (
+ NewMenuEntry->DisplayString,
+ BufferSize,
+ L"<%s>",
+ DirInfo->FileName
+ );
+
+ } else {
+ NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName);
+ }
+
+ NewFileContext->IsRoot = FALSE;
+ NewFileContext->IsLoadFile = FALSE;
+ NewFileContext->IsRemovableMedia = FALSE;
+
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
+ }
+ }
+
+ DirectoryMenu.MenuNumber = OptionNumber;
+ FreePool (DirInfo);
+ return EFI_SUCCESS;
+}
+
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+RefreshUpdateData (
+ VOID
+ )
+{
+ //
+ // Free current updated date
+ //
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ //
+ // Create new OpCode Handle
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mStartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+}
+
+/**
+ Update the File Explore page.
+
+ @param[in] HiiHandle Hii Handle of the package to be updated.
+ @param[in] MenuOption The Menu whose string tokens need to be updated.
+ @param[in] FeCurrentState Current file explorer state.
+
+**/
+VOID
+UpdateFileExplorePage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN SECUREBOOT_MENU_OPTION *MenuOption,
+ IN FILE_EXPLORER_STATE FeCurrentState
+ )
+{
+ UINTN Index;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ EFI_FORM_ID FileFormId;
+
+ if (FeCurrentState == FileExplorerStateEnrollPkFile) {
+ FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ FileFormId = FORM_FILE_EXPLORER_ID_PK;
+ } else if (FeCurrentState == FileExplorerStateEnrollKekFile) {
+ FormId = FORMID_ENROLL_KEK_FORM;
+ FileFormId = FORM_FILE_EXPLORER_ID_KEK;
+ } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ FileFormId = FORM_FILE_EXPLORER_ID_DB;
+ } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ FileFormId = FORM_FILE_EXPLORER_ID_DBX;
+ } else {
+ return;
+ }
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+
+ RefreshUpdateData ();
+ mStartLabel->Number = FORM_FILE_EXPLORER_ID;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (MenuOption, Index);
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+
+ if (NewFileContext->IsDir) {
+ //
+ // Create Text opcode for directory.
+ //
+ HiiCreateActionOpCode (
+ mStartOpCodeHandle,
+ (UINT16) (FILE_OPTION_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ } else {
+
+ //
+ // Create Goto opcode for file.
+ //
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FormId,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (FILE_OPTION_OFFSET + Index)
+ );
+ }
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FileFormId,
+ mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Update the file explorer page with the refreshed file system.
+
+ @param[in] PrivateData Module private data.
+ @param[in] KeyValue Key value to identify the type of data to expect.
+
+ @retval TRUE Inform the caller to create a callback packet to exit file explorer.
+ @retval FALSE Indicate that there is no need to exit file explorer.
+
+**/
+BOOLEAN
+UpdateFileExplorer (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN UINT16 KeyValue
+ )
+{
+ UINT16 FileOptionMask;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ BOOLEAN ExitFileExplorer;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ ExitFileExplorer = FALSE;
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
+
+ if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) {
+ //
+ // First in, display file system.
+ //
+ FreeMenu (&FsOptionMenu);
+ FindFileSystem ();
+
+ CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu);
+ UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState);
+
+ PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem;
+ } else {
+ if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) {
+ NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask);
+ } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) {
+ NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask);
+ }
+
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+
+ if (NewFileContext->IsDir ) {
+ PrivateData->FeDisplayContext = FileExplorerDisplayDirectory;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ FreeMenu (&DirectoryMenu);
+ Status = FindFiles (NewMenuEntry);
+ if (EFI_ERROR (Status)) {
+ ExitFileExplorer = TRUE;
+ goto OnExit;
+ }
+ CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu);
+ DestroyMenuEntry (NewMenuEntry);
+
+ UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState);
+
+ } else {
+ if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) {
+ FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) {
+ FormId = FORMID_ENROLL_KEK_FORM;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ } else {
+ return FALSE;
+ }
+
+ PrivateData->MenuEntry = NewMenuEntry;
+ PrivateData->FileContext->FileName = NewFileContext->FileName;
+
+ TmpDevicePath = NewFileContext->DevicePath;
+ OpenFileByDevicePath (
+ &TmpDevicePath,
+ &PrivateData->FileContext->FHandle,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+
+ //
+ // Create Subtitle op-code for the display string of the option.
+ //
+ RefreshUpdateData ();
+ mStartLabel->Number = FormId;
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FormId,
+ mStartOpCodeHandle, // Label FormId
+ mEndOpCodeHandle // LABEL_END
+ );
+ }
+ }
+
+OnExit:
+ return ExitFileExplorer;
+}
+
+/**
+ Clean up the dynamic opcode at label and form specified by both LabelId.
+
+ @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.
+ @param[in] PrivateData Module private data.
+
+**/
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ RefreshUpdateData ();
+
+ //
+ // Remove all op-codes from dynamic page
+ //
+ mStartLabel->Number = LabelId;
+ HiiUpdateForm (
+ PrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ LabelId,
+ mStartOpCodeHandle, // Label LabelId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+