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
--
1.9.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
On 18 January 2018 at 15:01, Ming Huang <heyi.guo@linaro.org> wrote: > OsBootLib can create OS option after upgrade firmware. > Can you add a bit more explanation why you need this? > 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 > -- > 1.9.1 > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On Thu, Jan 18, 2018 at 11:01:42PM +0800, Ming Huang wrote: > OsBootLib can create OS option after upgrade firmware. I will respond more strongly that Ard did: I have seen functionality like this implemented in publicly available systems - laptops, desktops. Without exception, they end up in bug reports saying "my system refuses to boot after installation/upgrade". Without exception, they add to existing negative perceptions of UEFI in general in certain market spaces. Presumably this is trying to address a real problem you have faced. Please bring this issue to the table for discussion, so that we can agree on an appropriate way of resolving it. Regardless, this code will not be included in 18.02. / Leif _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 2018/1/23 18:23, Leif Lindholm wrote: > On Thu, Jan 18, 2018 at 11:01:42PM +0800, Ming Huang wrote: >> OsBootLib can create OS option after upgrade firmware. > > I will respond more strongly that Ard did: > > I have seen functionality like this implemented in publicly available > systems - laptops, desktops. > Without exception, they end up in bug reports saying "my system > refuses to boot after installation/upgrade". > Without exception, they add to existing negative perceptions of UEFI > in general in certain market spaces. > > Presumably this is trying to address a real problem you have faced. > Please bring this issue to the table for discussion, so that we can > agree on an appropriate way of resolving it. > > Regardless, this code will not be included in 18.02. > > / > Leif > > . > The problem is that OS boot option is lost after upgrade firmware. It is inconvenient for using. OsBootLib can help this. OsBootLib retain the options installed by OS, and create OS boot option after upgrade firmware if grub file is existed in EFI partition and in mUefiOsBootFiles, and delete redundant options in the same GPT. -- Best Regards, Ming _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 27 January 2018 at 01:47, Huangming (Mark) <huangming23@huawei.com> wrote: > > > On 2018/1/23 18:23, Leif Lindholm wrote: >> On Thu, Jan 18, 2018 at 11:01:42PM +0800, Ming Huang wrote: >>> OsBootLib can create OS option after upgrade firmware. >> >> I will respond more strongly that Ard did: >> >> I have seen functionality like this implemented in publicly available >> systems - laptops, desktops. >> Without exception, they end up in bug reports saying "my system >> refuses to boot after installation/upgrade". >> Without exception, they add to existing negative perceptions of UEFI >> in general in certain market spaces. >> >> Presumably this is trying to address a real problem you have faced. >> Please bring this issue to the table for discussion, so that we can >> agree on an appropriate way of resolving it. >> >> Regardless, this code will not be included in 18.02. >> >> / >> Leif >> >> . >> > > The problem is that OS boot option is lost after upgrade firmware. Why is that? There is no need to clear the variable store if you upgrade the executable image. If you fix this issue, you don't need this patch. > It is inconvenient for using. OsBootLib can help this. > > OsBootLib retain the options installed by OS, and create OS boot option > after upgrade firmware if grub file is existed in EFI partition and in mUefiOsBootFiles, > and delete redundant options in the same GPT. > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 2018/1/27 18:37, Ard Biesheuvel wrote: > On 27 January 2018 at 01:47, Huangming (Mark) <huangming23@huawei.com> wrote: >> >> >> On 2018/1/23 18:23, Leif Lindholm wrote: >>> On Thu, Jan 18, 2018 at 11:01:42PM +0800, Ming Huang wrote: >>>> OsBootLib can create OS option after upgrade firmware. >>> >>> I will respond more strongly that Ard did: >>> >>> I have seen functionality like this implemented in publicly available >>> systems - laptops, desktops. >>> Without exception, they end up in bug reports saying "my system >>> refuses to boot after installation/upgrade". >>> Without exception, they add to existing negative perceptions of UEFI >>> in general in certain market spaces. >>> >>> Presumably this is trying to address a real problem you have faced. >>> Please bring this issue to the table for discussion, so that we can >>> agree on an appropriate way of resolving it. >>> >>> Regardless, this code will not be included in 18.02. >>> >>> / >>> Leif >>> >>> . >>> >> >> The problem is that OS boot option is lost after upgrade firmware. > > Why is that? There is no need to clear the variable store if you > upgrade the executable image. If you fix this issue, you don't need > this patch. > Ok, retaining the variable store can solve the problem also. But retaining the variable store have some issues, like,if the struct stored in variable is different between new firmware and old firmware, this situation may cause a problem. If OsBootLib is not needed for community, It will use for internal project in hisilicon. Thanks. >> It is inconvenient for using. OsBootLib can help this. >> >> OsBootLib retain the options installed by OS, and create OS boot option >> after upgrade firmware if grub file is existed in EFI partition and in mUefiOsBootFiles, >> and delete redundant options in the same GPT. >> > > . > -- Best Regards, Ming _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 29 January 2018 at 08:55, Huangming (Mark) <huangming23@huawei.com> wrote: > > > On 2018/1/27 18:37, Ard Biesheuvel wrote: >> On 27 January 2018 at 01:47, Huangming (Mark) <huangming23@huawei.com> wrote: >>> >>> >>> On 2018/1/23 18:23, Leif Lindholm wrote: >>>> On Thu, Jan 18, 2018 at 11:01:42PM +0800, Ming Huang wrote: >>>>> OsBootLib can create OS option after upgrade firmware. >>>> >>>> I will respond more strongly that Ard did: >>>> >>>> I have seen functionality like this implemented in publicly available >>>> systems - laptops, desktops. >>>> Without exception, they end up in bug reports saying "my system >>>> refuses to boot after installation/upgrade". >>>> Without exception, they add to existing negative perceptions of UEFI >>>> in general in certain market spaces. >>>> >>>> Presumably this is trying to address a real problem you have faced. >>>> Please bring this issue to the table for discussion, so that we can >>>> agree on an appropriate way of resolving it. >>>> >>>> Regardless, this code will not be included in 18.02. >>>> >>>> / >>>> Leif >>>> >>>> . >>>> >>> >>> The problem is that OS boot option is lost after upgrade firmware. >> >> Why is that? There is no need to clear the variable store if you >> upgrade the executable image. If you fix this issue, you don't need >> this patch. >> > > Ok, retaining the variable store can solve the problem also. > But retaining the variable store have some issues, like,if the struct stored in > variable is different between new firmware and old firmware, this situation may cause > a problem. > Yes. That means you have to design it with forward compatibility in mind, i.e., add reserved fields that default to zero, and use zero as a reasonable default when you add new fields. > If OsBootLib is not needed for community, It will use for internal project in hisilicon. > Well, that is up to you to decide. But I highly recommend not hardcoding this kind of knowledge into the firmware to begin with. > >>> It is inconvenient for using. OsBootLib can help this. >>> >>> OsBootLib retain the options installed by OS, and create OS boot option >>> after upgrade firmware if grub file is existed in EFI partition and in mUefiOsBootFiles, >>> and delete redundant options in the same GPT. >>> >> >> . >> > > -- > Best Regards, > > Ming > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On Sat, Jan 27, 2018 at 09:47:31AM +0800, Huangming (Mark) wrote: > The problem is that OS boot option is lost after upgrade firmware. > It is inconvenient for using. OsBootLib can help this. > > OsBootLib retain the options installed by OS, and create OS boot option > after upgrade firmware if grub file is existed in EFI partition and in mUefiOsBootFiles, > and delete redundant options in the same GPT. "Redundant" such as if the user installs a new Linux distribution on the same system without manually cleaning the ESP? This type of system behaviour has been seen multiple times to break installations in the real world. Note: my main objections here are really with regards to: 1) the expectation that variable store is erased on fw update 2) automatically rewriting boot variables If (1) was resolved, then I could potentially see a use for a last-ditch fallback option (but even then, I don't think it should be enabled by default). Regards, Leif _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Coming late to the party because Leif called my attention to this thread... On Mon, Jan 29, 2018 at 11:16:21AM +0000, Leif Lindholm wrote: > This type of system behaviour has been seen multiple times to break > installations in the real world. I can't agree more; that's why there's a pile of language in 2.6 and later that says how to do a better job of this. > Note: my main objections here are really with regards to: > 1) the expectation that variable store is erased on fw update > 2) automatically rewriting boot variables > > If (1) was resolved, then I could potentially see a use for a > last-ditch fallback option (but even then, I don't think it should be > enabled by default). I certainly agree resolving #1 is the thing to do here, but there is is actually useful functionality to have in general on the fallback path - though I don't think this patch implements it in a correct or preferred way. In particular, it would be better to follow the advice in 3.1.1 of the UEFI 2.7 spec, where we say that while yes, the firmware is allowed to do boot order maintenance, it shouldn't remove anything or change the order itself except in the most dire of circumstances. In particular: | The firmware should not, under normal operation, automatically remove | any correctly formed Boot#### variable currently referenced by the | BootOrder or BootNext variables. Such removal should be limited to | scenarios where the firmware is guided by direct user interaction. The right thing to do here is to publish some PlatformRecovery#### variables as specified in 3.4.2, which can be a static list that's the same every time you boot up, and when there's a failure here BootNext and BootOrder have been exhausted, proceed according to 3.4.1 and 3.4.2, which I'll attempt to summarize below. The PlatformRecovery#### variables here should have device paths that are something like: PlatformRecovery0000: File(\EFI\BOOT\BOOTAA64.EFI) PlatformRecovery0001: File(\EFI\centos\grubaa64.efi)/EndInstance/File(\EFI\debian\grubaa64.efi)/EndInstance/File(\EFI\GRUB2\GRUBAA64.EFI)/EndInstance/File(\EFI\Microsoft\Boot\bootmgfw.efi)/EndInstance/File(\EFI\redhat\grub.efi)/EndInstance/... etc .../EndEntire The EFI_OS_INDICATIONS_START_OS_RECOVERY and EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY bits should be set in OsIndicationsSupported. (As an aside, I don't think we've explicitly said that multi-instance device paths do or don't work in boot variables, so that may require some work, or if you have a stronger preference about order you could just make each one its own PlatformRecovery#### variable. For what it's worth, I don't think that the list in this patch is great - at the least the arch suffixes should be generated according to what the build target is, and what you've got currently doesn't correctly match several shipping OSes - many of which *do* provide a file at \EFI\BOOT\BOOT${ARCH}.EFI which will fix the BootOrder for you.) If you supply those static variables, then in the normal boot path, if you've exhausted BootNext and all of BootOrder, continue according to chapter 3.4.2 and then 3.4.3 of the spec. That basically says there's a list of things to try as if they're Boot#### options: - If OsRecoveryOrder exists, it's a list of GUIDs under which there may be OsRecovery#### variables. The GUIDs are processed in the order they're listed, and the OsRecovery#### variables under each GUID are processed in hexadecimal numerical order. - PlatformRecovery#### variables are processed in hexadecimal numerical order if OsRecovery variables are exhausted without successfully booting anything. For everything in that list, the variables basically get treated exactly like Boot#### variables. For each #### variable: - parse the variable like you'd parse Boot####, and use the normal discovery method to iterate across any files that match it. - if so, see if there's a Boot#### that matches that (it isn't necessarily in BootOrder); if not create one. - Try to boot it like any other boot entry: set BootCurrent to the Boot#### number, do LoadImage() and StartImage(), etc. There's no modification of BootOrder here. - If the binary there can't be found, loaded, or returns an error, continue iterating the normal way to see if there are more matching files, and if there aren't, then proceed to the next variable. If you exhaust this list, it's time for an error message and a menu or something ;) There are some important characteristics here that we need to maintain: 1) We haven't really talked enough about when it's really okay to Boot#### entries, because in general removing them is undoing something that was done on purpose (even if that purpose has been obviated now.) A pretty good rule is: don't remove Boot#### variables unless there are dire circumstances, like you've nearly completely run out of flash. The user or the OS set these for a reason. If you absolutely must prune them, start with the ones that aren't in BootOrder or BootNext, and then proceed to the high-numbered ones that are duplicates of other ones. And even then, only remove until you're under some known safe storage threshold. 2) Don't change BootOrder ever. The user set that for a reason. If you absolutely have to change it, append to the end. But you really don't need to change it unless the user told you to. 3) Don't probe the disk except to try to match a boot entry you're attempting to boot from. If you need to read a partition table to match an HD(), that's fine. If you need to read a disk to match a File(), that's fine. But only when you're trying to boot those device paths and they require iterating the disks. All probing the disk accomplishes in other cases is slowing things down and powering up devices unnecessarily. -- Peter _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Thank you for your detailed reply, I will think about your suggestions. On 2018/2/8 5:16, Peter Jones wrote: > Coming late to the party because Leif called my attention to this > thread... > > On Mon, Jan 29, 2018 at 11:16:21AM +0000, Leif Lindholm wrote: >> This type of system behaviour has been seen multiple times to break >> installations in the real world. > > I can't agree more; that's why there's a pile of language in 2.6 and > later that says how to do a better job of this. > >> Note: my main objections here are really with regards to: >> 1) the expectation that variable store is erased on fw update >> 2) automatically rewriting boot variables >> >> If (1) was resolved, then I could potentially see a use for a >> last-ditch fallback option (but even then, I don't think it should be >> enabled by default). > > I certainly agree resolving #1 is the thing to do here, but there is is > actually useful functionality to have in general on the fallback path - > though I don't think this patch implements it in a correct or preferred > way. In particular, it would be better to follow the advice in 3.1.1 of > the UEFI 2.7 spec, where we say that while yes, the firmware is allowed > to do boot order maintenance, it shouldn't remove anything or change the > order itself except in the most dire of circumstances. In particular: > > | The firmware should not, under normal operation, automatically remove > | any correctly formed Boot#### variable currently referenced by the > | BootOrder or BootNext variables. Such removal should be limited to > | scenarios where the firmware is guided by direct user interaction. > > The right thing to do here is to publish some PlatformRecovery#### > variables as specified in 3.4.2, which can be a static list that's the > same every time you boot up, and when there's a failure here BootNext > and BootOrder have been exhausted, proceed according to 3.4.1 and 3.4.2, > which I'll attempt to summarize below. > > The PlatformRecovery#### variables here should have device paths that > are something like: > > PlatformRecovery0000: File(\EFI\BOOT\BOOTAA64.EFI) > PlatformRecovery0001: > File(\EFI\centos\grubaa64.efi)/EndInstance/File(\EFI\debian\grubaa64.efi)/EndInstance/File(\EFI\GRUB2\GRUBAA64.EFI)/EndInstance/File(\EFI\Microsoft\Boot\bootmgfw.efi)/EndInstance/File(\EFI\redhat\grub.efi)/EndInstance/... etc .../EndEntire > > The EFI_OS_INDICATIONS_START_OS_RECOVERY and > EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY bits should be set in > OsIndicationsSupported. > > (As an aside, I don't think we've explicitly said that multi-instance > device paths do or don't work in boot variables, so that may require > some work, or if you have a stronger preference about order you could > just make each one its own PlatformRecovery#### variable. For what it's > worth, I don't think that the list in this patch is great - at the least > the arch suffixes should be generated according to what the build target > is, and what you've got currently doesn't correctly match several > shipping OSes - many of which *do* provide a file at > \EFI\BOOT\BOOT${ARCH}.EFI which will fix the BootOrder for you.) > > If you supply those static variables, then in the normal boot path, if > you've exhausted BootNext and all of BootOrder, continue according to > chapter 3.4.2 and then 3.4.3 of the spec. That basically says there's a > list of things to try as if they're Boot#### options: > > - If OsRecoveryOrder exists, it's a list of GUIDs under which there may > be OsRecovery#### variables. The GUIDs are processed in the order > they're listed, and the OsRecovery#### variables under each GUID are > processed in hexadecimal numerical order. > - PlatformRecovery#### variables are processed in hexadecimal numerical > order if OsRecovery variables are exhausted without successfully > booting anything. > > For everything in that list, the variables basically get treated exactly > like Boot#### variables. For each #### variable: > - parse the variable like you'd parse Boot####, and use the normal > discovery method to iterate across any files that match it. > - if so, see if there's a Boot#### that matches that (it isn't > necessarily in BootOrder); if not create one. > - Try to boot it like any other boot entry: set BootCurrent to the > Boot#### number, do LoadImage() and StartImage(), etc. There's no > modification of BootOrder here. > - If the binary there can't be found, loaded, or returns an > error, continue iterating the normal way to see if there are more > matching files, and if there aren't, then proceed to the next > variable. > > If you exhaust this list, it's time for an error message and a > menu or something ;) > > There are some important characteristics here that we need to maintain: > 1) We haven't really talked enough about when it's really okay to > Boot#### entries, because in general removing them is undoing > something that was done on purpose (even if that purpose has been > obviated now.) A pretty good rule is: don't remove Boot#### variables > unless there are dire circumstances, like you've nearly completely > run out of flash. The user or the OS set these for a reason. If you > absolutely must prune them, start with the ones that aren't in > BootOrder or BootNext, and then proceed to the high-numbered ones > that are duplicates of other ones. And even then, only remove until > you're under some known safe storage threshold. > 2) Don't change BootOrder ever. The user set that for a reason. If you > absolutely have to change it, append to the end. But you really > don't need to change it unless the user told you to. > 3) Don't probe the disk except to try to match a boot entry you're > attempting to boot from. If you need to read a partition table to > match an HD(), that's fine. If you need to read a disk to match a > File(), that's fine. But only when you're trying to boot those > device paths and they require iterating the disks. All probing the > disk accomplishes in other cases is slowing things down and powering > up devices unnecessarily. > -- Best Regards, Ming _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Peter, Thanks for your detailed explanation. I still have one question: On normal platforms, there are more boot options created by UEFI other than the hard disk boot option created by OS installation, like PXE network boot, USB stick boot, etc. If we use the PlatformRecovery#### method, will UEFI first try all normal boot options like PXE and USB? If PXE boot environment is always available, then the system may enter PXE OS installation again, which is not what we expect. Thanks and regards, Gary (Heyi Guo) On Wed, Feb 07, 2018 at 04:16:55PM -0500, Peter Jones wrote: > Coming late to the party because Leif called my attention to this > thread... > > On Mon, Jan 29, 2018 at 11:16:21AM +0000, Leif Lindholm wrote: > > This type of system behaviour has been seen multiple times to break > > installations in the real world. > > I can't agree more; that's why there's a pile of language in 2.6 and > later that says how to do a better job of this. > > > Note: my main objections here are really with regards to: > > 1) the expectation that variable store is erased on fw update > > 2) automatically rewriting boot variables > > > > If (1) was resolved, then I could potentially see a use for a > > last-ditch fallback option (but even then, I don't think it should be > > enabled by default). > > I certainly agree resolving #1 is the thing to do here, but there is is > actually useful functionality to have in general on the fallback path - > though I don't think this patch implements it in a correct or preferred > way. In particular, it would be better to follow the advice in 3.1.1 of > the UEFI 2.7 spec, where we say that while yes, the firmware is allowed > to do boot order maintenance, it shouldn't remove anything or change the > order itself except in the most dire of circumstances. In particular: > > | The firmware should not, under normal operation, automatically remove > | any correctly formed Boot#### variable currently referenced by the > | BootOrder or BootNext variables. Such removal should be limited to > | scenarios where the firmware is guided by direct user interaction. > > The right thing to do here is to publish some PlatformRecovery#### > variables as specified in 3.4.2, which can be a static list that's the > same every time you boot up, and when there's a failure here BootNext > and BootOrder have been exhausted, proceed according to 3.4.1 and 3.4.2, > which I'll attempt to summarize below. > > The PlatformRecovery#### variables here should have device paths that > are something like: > > PlatformRecovery0000: File(\EFI\BOOT\BOOTAA64.EFI) > PlatformRecovery0001: > File(\EFI\centos\grubaa64.efi)/EndInstance/File(\EFI\debian\grubaa64.efi)/EndInstance/File(\EFI\GRUB2\GRUBAA64.EFI)/EndInstance/File(\EFI\Microsoft\Boot\bootmgfw.efi)/EndInstance/File(\EFI\redhat\grub.efi)/EndInstance/... etc .../EndEntire > > The EFI_OS_INDICATIONS_START_OS_RECOVERY and > EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY bits should be set in > OsIndicationsSupported. > > (As an aside, I don't think we've explicitly said that multi-instance > device paths do or don't work in boot variables, so that may require > some work, or if you have a stronger preference about order you could > just make each one its own PlatformRecovery#### variable. For what it's > worth, I don't think that the list in this patch is great - at the least > the arch suffixes should be generated according to what the build target > is, and what you've got currently doesn't correctly match several > shipping OSes - many of which *do* provide a file at > \EFI\BOOT\BOOT${ARCH}.EFI which will fix the BootOrder for you.) > > If you supply those static variables, then in the normal boot path, if > you've exhausted BootNext and all of BootOrder, continue according to > chapter 3.4.2 and then 3.4.3 of the spec. That basically says there's a > list of things to try as if they're Boot#### options: > > - If OsRecoveryOrder exists, it's a list of GUIDs under which there may > be OsRecovery#### variables. The GUIDs are processed in the order > they're listed, and the OsRecovery#### variables under each GUID are > processed in hexadecimal numerical order. > - PlatformRecovery#### variables are processed in hexadecimal numerical > order if OsRecovery variables are exhausted without successfully > booting anything. > > For everything in that list, the variables basically get treated exactly > like Boot#### variables. For each #### variable: > - parse the variable like you'd parse Boot####, and use the normal > discovery method to iterate across any files that match it. > - if so, see if there's a Boot#### that matches that (it isn't > necessarily in BootOrder); if not create one. > - Try to boot it like any other boot entry: set BootCurrent to the > Boot#### number, do LoadImage() and StartImage(), etc. There's no > modification of BootOrder here. > - If the binary there can't be found, loaded, or returns an > error, continue iterating the normal way to see if there are more > matching files, and if there aren't, then proceed to the next > variable. > > If you exhaust this list, it's time for an error message and a > menu or something ;) > > There are some important characteristics here that we need to maintain: > 1) We haven't really talked enough about when it's really okay to > Boot#### entries, because in general removing them is undoing > something that was done on purpose (even if that purpose has been > obviated now.) A pretty good rule is: don't remove Boot#### variables > unless there are dire circumstances, like you've nearly completely > run out of flash. The user or the OS set these for a reason. If you > absolutely must prune them, start with the ones that aren't in > BootOrder or BootNext, and then proceed to the high-numbered ones > that are duplicates of other ones. And even then, only remove until > you're under some known safe storage threshold. > 2) Don't change BootOrder ever. The user set that for a reason. If you > absolutely have to change it, append to the end. But you really > don't need to change it unless the user told you to. > 3) Don't probe the disk except to try to match a boot entry you're > attempting to boot from. If you need to read a partition table to > match an HD(), that's fine. If you need to read a disk to match a > File(), that's fine. But only when you're trying to boot those > device paths and they require iterating the disks. All probing the > disk accomplishes in other cases is slowing things down and powering > up devices unnecessarily. > > -- > Peter _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.