OsBootLib can create OS option after upgrade firmware.
Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ming Huang huangming23@huawei.com Signed-off-by: Heyi Guo heyi.guo@linaro.org --- Platform/Hisilicon/D03/D03.dsc | 1 + Platform/Hisilicon/D05/D05.dsc | 1 + Silicon/Hisilicon/Include/Library/OsBootLib.h | 47 ++ Silicon/Hisilicon/Library/OsBootLib/OsBoot.h | 124 +++++ Silicon/Hisilicon/Library/OsBootLib/OsBootLib.c | 217 +++++++++ Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf | 59 +++ Silicon/Hisilicon/Library/OsBootLib/OsBootLibMisc.c | 514 ++++++++++++++++++++ Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBm.c | 6 + Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 1 + 9 files changed, 970 insertions(+)
diff --git a/Platform/Hisilicon/D03/D03.dsc b/Platform/Hisilicon/D03/D03.dsc index 88c08dd..6f1164e 100644 --- a/Platform/Hisilicon/D03/D03.dsc +++ b/Platform/Hisilicon/D03/D03.dsc @@ -47,6 +47,7 @@ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf + OsBootLib|Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf
diff --git a/Platform/Hisilicon/D05/D05.dsc b/Platform/Hisilicon/D05/D05.dsc index 79890ef..52ffad5 100644 --- a/Platform/Hisilicon/D05/D05.dsc +++ b/Platform/Hisilicon/D05/D05.dsc @@ -55,6 +55,7 @@ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + OsBootLib|Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf
!if $(NETWORK_IP6_ENABLE) == TRUE TcpIoLib|MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf diff --git a/Silicon/Hisilicon/Include/Library/OsBootLib.h b/Silicon/Hisilicon/Include/Library/OsBootLib.h new file mode 100644 index 0000000..f5cbc4a --- /dev/null +++ b/Silicon/Hisilicon/Include/Library/OsBootLib.h @@ -0,0 +1,47 @@ +/** @file +* +* Copyright (c) 2017, Hisilicon Limited. All rights reserved. +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* 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. +* +**/ + +#ifndef _OS_BOOT_LIB_H_ +#define _OS_BOOT_LIB_H_ + + +/** + Remove invalid OS boot options, and then add new ones. + +*/ +EFI_STATUS +AdjustOsBootOrder ( + VOID + ); + +/** + Try to find UEFI OSs and create the boot options which haven't been listed in BootOrder. + +*/ +EFI_STATUS +CreateOsBootOptions ( + VOID + ); + +/** + Remove UEFI OS boot options when it is disappeared in system. + +*/ +EFI_STATUS +RemoveInvalidOsBootOptions ( + VOID + ); + +#endif diff --git a/Silicon/Hisilicon/Library/OsBootLib/OsBoot.h b/Silicon/Hisilicon/Library/OsBootLib/OsBoot.h new file mode 100644 index 0000000..1991471 --- /dev/null +++ b/Silicon/Hisilicon/Library/OsBootLib/OsBoot.h @@ -0,0 +1,124 @@ +/** @file +* +* Copyright (c) 2017, Hisilicon Limited. All rights reserved. +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* 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. +* +**/ + +#ifndef _OS_BOOT_H_ +#define _OS_BOOT_H_ + +#include <PiDxe.h> +#include <PlatformArch.h> +#include <Uefi.h> +#include <Guid/FileInfo.h> +#include <Guid/GlobalVariable.h> +#include <IndustryStandard/PeImage.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/OsBootLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiBootManagerLib.h> + +#include <Protocol/BlockIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/DevicePathFromText.h> +#include <Protocol/DevicePathToText.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/SimpleFileSystem.h> + + +typedef struct { + CHAR16 *FilePathString; + CHAR16 *Description; + }UEFI_OS_BOOT_FILE; + +/** + Check same boot option by device path. + +*/ +BOOLEAN +BeHaveSameBootOptionByDP ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + CHAR16 *FileName + ); + +/** + Remove UEFI OS boot options when it is disappeared in system. + +*/ +EFI_STATUS +RemoveInvalidOsBootOptions ( + VOID + ); + + +/** + Check Os Boot Option if exist in current system. + +*/ +BOOLEAN +BeInvalidOsBootOption ( + EFI_DEVICE_PATH_PROTOCOL *OptionDp + ); + +/** + Get the headers (dos, image, optional header) from an image + + @param Device SimpleFileSystem device handle + @param FileName File name for the image + @param DosHeader Pointer to dos header + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. + + @retval EFI_SUCCESS Successfully get the machine type. + @retval EFI_NOT_FOUND The file is not found. + @retval EFI_LOAD_ERROR File is not a valid image file. + +**/ +EFI_STATUS +EFIAPI +OsBootGetImageHeader ( + IN EFI_HANDLE Device, + IN CHAR16 *FileName, + OUT EFI_IMAGE_DOS_HEADER *DosHeader, + OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr + ); + +UINTN +GetOptionPositionWithoutGpt ( + VOID + ); + +VOID +PrintDevicePath ( + CHAR16 *PreStr, + EFI_DEVICE_PATH_PROTOCOL *Path + ); + +VOID +RemoveSuperfluousOption ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + UINT16 *OptionFlags, + UINTN BootOptionCount + ); + +BOOLEAN +IsOptionAddedByOsBootLib ( + UINT16 *OptionDescription + ); + +#endif diff --git a/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.c b/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.c new file mode 100644 index 0000000..29b6b62 --- /dev/null +++ b/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.c @@ -0,0 +1,217 @@ +/** @file +* +* Copyright (c) 2017, Hisilicon Limited. All rights reserved. +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* 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 "OsBoot.h" + +UEFI_OS_BOOT_FILE mUefiOsBootFiles[] = { + {EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64, L"Uefi Default Boot"}, + {L"\BOOT\EFI\EFI\CENTOS\grubaa64.efi", L"Uefi CENTOS Boot"}, + {L"\EFI\centos\grubaa64.efi", L"Uefi CentOS Grub Boot"}, + {L"\EFI\debian\grubaa64.efi", L"Uefi Debian Grub Boot"}, + {L"\EFI\GRUB2\GRUBAA64.EFI", L"Hisilicon Linux Boot"}, + {L"\EFI\Microsoft\Boot\bootmgfw.efi", L"Uefi Windows Boot"}, + {L"\EFI\redhat\grub.efi", L"Uefi Redhat Boot"}, + {L"\EFI\SuSE\elilo.efi", L"Uefi SuSE Boot"}, + {L"\EFI\ubuntu\grubaa64.efi", L"Uefi Ubuntu Grub Boot"}, + {L"\EFI\ubuntu\shimx64.efi", L"Uefi Ubuntu Shimx64 Boot"}, + {L"\EFI\ubuntu\grubx64.efi", L"Uefi Ubuntu Grubx64 Boot"}, + {L"\EFI\ubuntu\shim.efi", L"Uefi Ubuntu Shim Boot"}, + {L"\EFI\ubuntu\grub.efi", L"Uefi Ubuntu Grub Boot"}, + {L"\EFI\fedora\shim.efi", L"Uefi Fedora Shim Boot"} +}; + +BOOLEAN +IsOptionAddedByOsBootLib ( + UINT16 *OptionDescription + ) +{ + UINTN Index; + + for (Index = 0; Index < (sizeof (mUefiOsBootFiles) / sizeof (UEFI_OS_BOOT_FILE)); Index++) { + if (StrCmp (mUefiOsBootFiles[Index].Description, OptionDescription) == 0) { + return TRUE; + } + } + + return FALSE; +} + +/** + Remove invalid OS boot options, and then add new ones. + +*/ +EFI_STATUS +AdjustOsBootOrder ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RemoveInvalidOsBootOptions (); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = CreateOsBootOptions (); + return Status; +} + + +/** + Remove UEFI OS boot options when it is disappeared in system. + +*/ +EFI_STATUS +RemoveInvalidOsBootOptions ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT16 *OptionDelFlags; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + + BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + OptionDelFlags = AllocateZeroPool (BootOptionCount * sizeof(UINT16)); + if (OptionDelFlags == NULL) { + goto exit; + } + + for (Index = 0; Index < BootOptionCount; Index++) { + if (OptionDelFlags[Index] == 0) { + if (BeInvalidOsBootOption (BootOptions[Index].FilePath)) { + Status = EfiBootManagerDeleteLoadOptionVariable (BootOptions[Index].OptionNumber, LoadOptionTypeBoot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DeleteLoadOptionVariable: %r\n", Status)); + continue; + } + PrintDevicePath (L"Del Option,", BootOptions[Index].FilePath); + } else { + RemoveSuperfluousOption (&BootOptions[Index], OptionDelFlags, BootOptionCount - Index); + } + } + } + + exit: + if (OptionDelFlags != NULL) { + FreePool (OptionDelFlags); + } + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + + return EFI_SUCCESS; +} + + +/** + Try to find UEFI OSs and create the boot options which haven't been listed in BootOrder. + +*/ +EFI_STATUS +CreateOsBootOptions ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *FileSystemHandles; + UINTN NumberFileSystemHandles; + UINTN Index, Count; + EFI_DEVICE_PATH_PROTOCOL *OsFileDP; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN MaxFiles; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + + // + //Look for file system to find default Os boot load. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberFileSystemHandles, + &FileSystemHandles + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MaxFiles = sizeof (mUefiOsBootFiles) / sizeof (UEFI_OS_BOOT_FILE); + for (Index = 0; Index < NumberFileSystemHandles; Index++) { + Status = gBS->HandleProtocol ( + FileSystemHandles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + Hdr.Union = &HdrData; + for (Count = 0; Count < MaxFiles; Count++) { + // + //Read Boot File Path to check validation. + // + Status = OsBootGetImageHeader ( + FileSystemHandles[Index], + mUefiOsBootFiles[Count].FilePathString, + &DosHeader, + Hdr + ); + if (!EFI_ERROR (Status) && + EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) && + Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + + OsFileDP = NULL; + OsFileDP = FileDevicePath (FileSystemHandles[Index], mUefiOsBootFiles[Count].FilePathString); + PrintDevicePath (L"Exist", OsFileDP); + if (!BeHaveSameBootOptionByDP (OsFileDP, mUefiOsBootFiles[Count].FilePathString)) { + // + // Create new BootOption if it is not present. + // + DEBUG ((DEBUG_INFO, "CreateOsBootOptions (), Make New Boot Option :%s.\n", mUefiOsBootFiles[Count].Description)); + Status = EfiBootManagerInitializeLoadOption ( + &NewOption, + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + mUefiOsBootFiles[Count].Description, + OsFileDP, + NULL, + 0 + ); + ASSERT_EFI_ERROR (Status); + Status = EfiBootManagerAddLoadOptionVariable (&NewOption, GetOptionPositionWithoutGpt ()); + ASSERT_EFI_ERROR (Status); + EfiBootManagerFreeLoadOption (&NewOption); + } + + if(OsFileDP != NULL) { + FreePool (OsFileDP); + OsFileDP = NULL; + } + } + } + } + + if (NumberFileSystemHandles != 0) { + FreePool (FileSystemHandles); + } + + return EFI_SUCCESS; +} + diff --git a/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf b/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf new file mode 100644 index 0000000..12e6d49 --- /dev/null +++ b/Silicon/Hisilicon/Library/OsBootLib/OsBootLib.inf @@ -0,0 +1,59 @@ +## @file +# Manager Os Boot option. +# Copyright (c) 2017, Hisilicon Limited. All rights reserved. +# Copyright (c) 2017, Linaro Limited. All rights reserved. +# +# Copyright (c) 2008 - 2014, 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OsBootLib + FILE_GUID = e406c654-ccde-4d32-8362-0aec01725139 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = OsBootLib + +[Sources] + OsBootLib.c + OsBootLibMisc.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Hisilicon/HisiPkg.dec + +[LibraryClasses] + BaseMemoryLib + BaseLib + DxeServicesLib + DebugLib + DxeServicesTableLib + DevicePathLib + MemoryAllocationLib + PrintLib + UefiRuntimeServicesTableLib + UefiLib + UefiBootServicesTableLib + UefiBootManagerLib + +[Guids] + gEfiGlobalVariableGuid + gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiDevicePathProtocolGuid ## CONSUMES + gEfiDevicePathToTextProtocolGuid + +[Pcd] diff --git a/Silicon/Hisilicon/Library/OsBootLib/OsBootLibMisc.c b/Silicon/Hisilicon/Library/OsBootLib/OsBootLibMisc.c new file mode 100644 index 0000000..4e6d895 --- /dev/null +++ b/Silicon/Hisilicon/Library/OsBootLib/OsBootLibMisc.c @@ -0,0 +1,514 @@ +/** @file +* +* Copyright (c) 2017, Hisilicon Limited. All rights reserved. +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* 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 "OsBoot.h" + +extern UEFI_OS_BOOT_FILE mUefiOsBootFiles[]; + +/** + Read file the headers of dos, image, optional header. + + @param Device SimpleFileSystem device handle + @param FileSize File size + @param DosHeader Pointer to dos header + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. + + @retval EFI_SUCCESS Successfully get the File. + @retval EFI_LOAD_ERROR File is not a valid image file. + +**/ +EFI_STATUS +ReadDosHeader ( + EFI_FILE_HANDLE ThisFile, + UINT64 FileSize, + EFI_IMAGE_DOS_HEADER *DosHeader, + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION *Hdr + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + // + // Read dos header + // + BufferSize = sizeof (EFI_IMAGE_DOS_HEADER); + Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader); + if (EFI_ERROR (Status) || + BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) || + FileSize <= DosHeader->e_lfanew || + DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + Status = EFI_LOAD_ERROR; + DEBUG ((DEBUG_ERROR, "%a(%d):error!\n", __FUNCTION__,__LINE__)); + goto ErrReadDos; + } + + // + // Move to PE signature + // + Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew); + if (EFI_ERROR (Status)) { + Status = EFI_LOAD_ERROR; + DEBUG((DEBUG_ERROR, "%a(%d):error!\n", __FUNCTION__,__LINE__)); + goto ErrReadDos; + } + + // + // Read and check PE signature + // + BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); + Status = ThisFile->Read (ThisFile, &BufferSize, (VOID*)(Hdr->Pe32)); + if (EFI_ERROR (Status) || + BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) || + Hdr->Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + Status = EFI_LOAD_ERROR; + DEBUG((DEBUG_ERROR, "%a(%d):error!\n", __FUNCTION__,__LINE__)); + goto ErrReadDos; + } + +ErrReadDos: + return Status; +} + +/** + Get the headers (dos, image, optional header) from an image + + @param Device SimpleFileSystem device handle + @param FileName File name for the image + @param DosHeader Pointer to dos header + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. + + @retval EFI_SUCCESS Successfully get the machine type. + @retval EFI_NOT_FOUND The file is not found. + @retval EFI_LOAD_ERROR File is not a valid image file. + +**/ +EFI_STATUS +EFIAPI +OsBootGetImageHeader ( + IN EFI_HANDLE Device, + IN CHAR16 *FileName, + OUT EFI_IMAGE_DOS_HEADER *DosHeader, + OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE Root; + EFI_FILE_HANDLE ThisFile; + UINTN BufferSize; + UINT64 FileSize; + EFI_FILE_INFO *Info; + BOOLEAN Condition = TRUE;//pclint + + Root = NULL; + ThisFile = NULL; + // + // Handle the file system interface to the device + // + Status = gBS->HandleProtocol ( + Device, + &gEfiSimpleFileSystemProtocolGuid, + (VOID *) &Volume + ); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + goto Done; + } + + Status = Volume->OpenVolume ( + Volume, + &Root + ); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + Root = NULL; + goto Done; + } + + if (Root == NULL) { + Status = EFI_LOAD_ERROR; + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + goto Done; + } + Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(%d):file not found ret :%r !\n", __FUNCTION__,__LINE__,Status)); + goto Done; + } + + if (ThisFile == NULL) { + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + Status = EFI_LOAD_ERROR; + goto Done; + } + // + // Get file size + // + BufferSize = SIZE_OF_EFI_FILE_INFO + 200; + do { + Info = NULL; + Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info); + if (EFI_ERROR (Status)) { + goto Done; + } + Status = ThisFile->GetInfo ( + ThisFile, + &gEfiFileInfoGuid, + &BufferSize, + Info + ); + if (!EFI_ERROR (Status)) { + break; + } + if (Status != EFI_BUFFER_TOO_SMALL) { + FreePool (Info); + goto Done; + } + FreePool (Info); + } while (Condition); + + FileSize = Info->FileSize; + FreePool (Info); + + Status = ReadDosHeader(ThisFile, FileSize, DosHeader, &Hdr); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + goto Done; + } + // + // Check PE32 or PE32+ magic + // + if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC && + Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + Status = EFI_LOAD_ERROR; + DEBUG((DEBUG_ERROR, "%a(%d):error ret :%r !\n", __FUNCTION__,__LINE__,Status)); + goto Done; + } + + Done: + if (ThisFile != NULL) { + ThisFile->Close (ThisFile); + } + if (Root != NULL) { + Root->Close (Root); + } + return Status; +} + + +VOID +PrintDevicePath ( + CHAR16 *PreStr, + EFI_DEVICE_PATH_PROTOCOL *Path + ) +{ + CHAR16 *DevicePathTxt; + EFI_STATUS Status; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToTextProtocol; + + DevicePathTxt = NULL; + Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); + if (!EFI_ERROR (Status)) { + DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (Path, FALSE, TRUE); + DEBUG ((DEBUG_ERROR, "%s DevPath:[%s]\n", PreStr, DevicePathTxt)); + } + + if (DevicePathTxt != NULL) { + FreePool (DevicePathTxt); + } + + return ; +} + +CHAR16 * +GetGptNodeText ( + EFI_DEVICE_PATH_PROTOCOL *Path + ) +{ + CHAR16 *NodeText; + + while (!IsDevicePathEnd (Path)) { + NodeText = ConvertDeviceNodeToText (Path, TRUE, TRUE); + if (StrStr (NodeText, L"GPT") != NULL) { + return NodeText; + } + + if (NodeText != NULL) { + FreePool (NodeText); + } + + Path = NextDevicePathNode (Path); + } + + return NULL; +} + +BOOLEAN +IsPartitionGuidEqual ( + EFI_DEVICE_PATH_PROTOCOL *OptionPath, + EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + CHAR16 *OptionGptText; + CHAR16 *FileGptText; + + OptionGptText = GetGptNodeText (OptionPath); + FileGptText = GetGptNodeText (FilePath); + if ((OptionGptText != NULL) && (FileGptText != NULL) && (StrCmp (OptionGptText, FileGptText) == 0)) { + return TRUE; + } + + if (OptionGptText != NULL) { + FreePool (OptionGptText); + } + if (FileGptText != NULL) { + FreePool (FileGptText); + } + + return FALSE; +} + +/* If a partition exist a valid grub, OsBootLib will create a Option after bios firmware upgraded, + * and then installing the same OS on the same partition will create anothor Option. the two Options + * are superfluous, the Option added by OsBootLib should be remove. + * + * It's allowed of creating several Option in the same GPT by installing OS. + */ +VOID +RemoveSuperfluousOption ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + UINT16 *OptionDelFlags, + UINTN BootOptionCount + ) +{ + EFI_STATUS Status; + UINTN Index; + + for (Index = 1; Index < BootOptionCount; Index++) { + if (OptionDelFlags[Index] == 0) { + if ((IsPartitionGuidEqual (BootOptions[0].FilePath, BootOptions[Index].FilePath)) && + (IsOptionAddedByOsBootLib (BootOptions[Index].Description))) { + OptionDelFlags[Index] = 1; + + Status = EfiBootManagerDeleteLoadOptionVariable (BootOptions[Index].OptionNumber, LoadOptionTypeBoot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DeleteLoadOptionVariable: %r\n", Status)); + continue; + } + + PrintDevicePath (L"Del Option(du),", BootOptions[Index].FilePath); + } + } + } + + return; +} + +UINTN +GetOptionPositionWithoutGpt ( + VOID + ) +{ + UINTN Index; + UINTN BootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + + BootOptions = EfiBootManagerGetLoadOptions ( + &BootOptionCount, LoadOptionTypeBoot + ); + for (Index = 0; Index < BootOptionCount; Index++) { + if (GetGptNodeText (BootOptions[Index].FilePath) == NULL) { + return Index; + } + } + + return 0; +} + +CHAR16 * +GetFileTextByDevicePath ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + CHAR16 *FileString; + + FileString = NULL; + + while (!IsDevicePathEnd (DevicePath)) { + if (MEDIA_DEVICE_PATH == DevicePathType (DevicePath) && + MEDIA_FILEPATH_DP == DevicePathSubType (DevicePath)) { + FileString = ConvertDeviceNodeToText (DevicePath, TRUE, TRUE); + break; + } + DevicePath = NextDevicePathNode (DevicePath); + } + + return FileString; +} + + +/** + Check same boot option by device path. + +*/ +BOOLEAN +BeHaveSameBootOptionByDP ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + CHAR16 *FileName + ) +{ + UINTN Index; + UINTN ValidPathSize; + BOOLEAN Found; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + + if (NULL == DevicePath) { + return FALSE; + } + + BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + + Found = FALSE; + for (Index = 0; Index < BootOptionCount; Index++) { + /* If a partition exist a valid Option, then the new Option should not be added. + * After installation, some iso will create several valid grub file, like + * \EFI\centos\shimaa64.efi, \EFI\BOOT\BOOTAA64.EFI. + */ + if(IsPartitionGuidEqual (BootOptions[Index].FilePath, DevicePath)) { + DEBUG ((DEBUG_ERROR, "Get the same Option(GPT).\n")); + Found = TRUE; + break; + } + + /* If DevicePath of new Option is matched in exist Option and file name of + * new Option is EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64, then the new Option should be ignored. + */ + ValidPathSize = GetDevicePathSize (BootOptions[Index].FilePath) - END_DEVICE_PATH_LENGTH; + if ((CompareMem (BootOptions[Index].FilePath, DevicePath, ValidPathSize) == 0) && + (StrCmp (FileName, EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64) == 0)) + { + DEBUG ((DEBUG_ERROR, "Get the same Option.\n")); + Found = TRUE; + break; + } + } + + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + + return Found; +} + +/** + Check Os Boot Option if exist in current system. + +*/ +BOOLEAN +BeInvalidOsBootOption ( + EFI_DEVICE_PATH_PROTOCOL *OptionDp + ) +{ + EFI_STATUS Status; + EFI_HANDLE *FileSystemHandles; + UINTN NumberFileSystemHandles; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *FileSystemDP; + UINTN OptionDpSize; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DOS_HEADER DosHeader; + BOOLEAN Invalid; + EFI_DEVICE_PATH_PROTOCOL* DevicePathNode; + CHAR16 *FileString; + + Invalid = TRUE; + if (NULL == OptionDp) { + return FALSE; + } + + OptionDpSize = GetDevicePathSize (OptionDp); + if (OptionDpSize == 0) { + return FALSE; + } + + // + // Os BootOption should be File Device Path. + // + DevicePathNode = OptionDp; + FileString = GetFileTextByDevicePath (DevicePathNode); + if (FileString == NULL) { + return FALSE; + } + + // + // File should be exsiting in system. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberFileSystemHandles, + &FileSystemHandles + ); + if (EFI_ERROR (Status)) { + FreePool (FileString); + return FALSE; + } + + for (Index = 0; Index < NumberFileSystemHandles; Index++) { + Status = gBS->HandleProtocol ( + FileSystemHandles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + FileSystemDP = FileDevicePath (FileSystemHandles[Index], FileString); + /* If Partition is existed and the grub file is existed, then the Option is valid. */ + if ((CompareMem ((VOID *) OptionDp, (VOID *) FileSystemDP, OptionDpSize) == 0) || + (IsPartitionGuidEqual (OptionDp, FileSystemDP))) { + Hdr.Union = &HdrData; + Status = OsBootGetImageHeader ( + FileSystemHandles[Index], + FileString, + &DosHeader, + Hdr + ); + if (!EFI_ERROR (Status) && + EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) && + Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + DEBUG ((DEBUG_ERROR, "BeValidOsBootOption (),Get Bootable file :%s.\n", FileString)); + Invalid = FALSE; + break; + } + } + + if (FileSystemDP != NULL) { + FreePool (FileSystemDP); + } + } + + if (NumberFileSystemHandles != 0) { + FreePool (FileSystemHandles); + } + if (FileString != NULL) { + FreePool (FileString); + } + + return Invalid; +} + diff --git a/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBm.c b/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBm.c index 845519f..1c6e8bf 100644 --- a/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBm.c +++ b/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBm.c @@ -18,6 +18,7 @@ #include <IndustryStandard/Pci22.h> #include <Library/BmcConfigBootLib.h> #include <Library/DevicePathLib.h> +#include <Library/OsBootLib.h> #include <Library/PcdLib.h> #include <Library/UefiBootManagerLib.h> #include <Library/UefiLib.h> @@ -576,6 +577,11 @@ PlatformBootManagerAfterConsole ( PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE );
+ Status = AdjustOsBootOrder (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:%r\n", __FUNCTION__, Status)); + } + HandleBmcBootType (); }
diff --git a/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index 7b151a9..a6d597d 100644 --- a/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/Silicon/Hisilicon/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -49,6 +49,7 @@ DevicePathLib DxeServicesLib MemoryAllocationLib + OsBootLib PcdLib PrintLib UefiBootManagerLib