[edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib

Ming Huang posted 14 patches 6 years, 11 months ago
There is a newer version of this series
[edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Ming Huang 6 years, 11 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Ard Biesheuvel 6 years, 11 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Leif Lindholm 6 years, 11 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Huangming (Mark) 6 years, 11 months ago

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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Ard Biesheuvel 6 years, 11 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Huangming (Mark) 6 years, 10 months ago

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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Ard Biesheuvel 6 years, 10 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Leif Lindholm 6 years, 10 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Peter Jones 6 years, 10 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Huangming (Mark) 6 years, 10 months ago
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
Re: [edk2] [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Posted by Guo Heyi 6 years, 10 months ago
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