mirror of https://github.com/acidanthera/audk.git
1228 lines
34 KiB
C
1228 lines
34 KiB
C
/** @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
|
|
);
|
|
}
|
|
|