public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ming Huang <heyi.guo@linaro.org>
To: leif.lindholm@linaro.org, linaro-uefi@lists.linaro.org,
	edk2-devel@lists.01.org, graeme.gregory@linaro.org
Cc: ard.biesheuvel@linaro.org, guoheyi@huawei.com,
	wanghuiqiang@huawei.com, huangming23@huawei.com,
	zhangjinsong2@huawei.com, mengfanrong@huawei.com, waip23@126.com,
	Heyi Guo <heyi.guo@linaro.org>
Subject: [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib
Date: Thu, 18 Jan 2018 23:01:42 +0800	[thread overview]
Message-ID: <1516287703-35516-14-git-send-email-huangming23@huawei.com> (raw)
In-Reply-To: <1516287703-35516-1-git-send-email-huangming23@huawei.com>

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



  parent reply	other threads:[~2018-01-18 14:57 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-18 15:01 [PATCH edk2-platforms v1 00/14] Improve D0x platforms and bug fix Ming Huang
2018-01-18 15:01 ` [PATCH edk2-platforms v1 01/14] Hisilicon/D05: Add PPTT support Ming Huang
2018-01-20 10:16   ` Ard Biesheuvel
2018-01-22  9:16     ` Huangming (Mark)
2018-01-23  6:00     ` Huangming (Mark)
2018-01-22 13:53   ` Leif Lindholm
2018-01-22 14:15     ` Leif Lindholm
2018-01-24 13:49     ` graeme.gregory
2018-01-23 21:29   ` Jeremy Linton
2018-01-24  7:57     ` Huangming (Mark)
2018-01-25  5:56     ` Huangming (Mark)
2018-01-25 15:27       ` Jeremy Linton
2018-01-18 15:01 ` [PATCH edk2-platforms v1 02/14] Hisilicon D03/D05:Switch to Generic BDS driver Ming Huang
2018-01-20 10:27   ` Ard Biesheuvel
2018-01-22 18:38   ` Leif Lindholm
2018-01-23  6:03     ` Huangming (Mark)
2018-01-18 15:01 ` [PATCH edk2-platforms v1 03/14] Hisilicon D03/D05: Optimize the feature of BMC set boot option Ming Huang
2018-01-20 10:41   ` Ard Biesheuvel
2018-01-23  8:28     ` Huangming (Mark)
2018-01-23 10:28   ` Leif Lindholm
2018-01-23 10:51     ` Huangming (Mark)
2018-01-18 15:01 ` [PATCH edk2-platforms v1 04/14] Hisilicon D03/D05: Add capsule upgrade support Ming Huang
2018-01-20 10:50   ` Ard Biesheuvel
2018-01-23  8:53     ` Huangming (Mark)
2018-01-23  9:33       ` Ard Biesheuvel
2018-01-24 11:10     ` Huangming (Mark)
2018-01-24 11:21       ` Ard Biesheuvel
2018-01-25  0:53         ` Huangming (Mark)
2018-01-23 14:06   ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 05/14] Hisilicon D03/D05: Open SasPlatform source code Ming Huang
2018-01-20 10:57   ` Ard Biesheuvel
2018-01-23 11:01     ` Huangming (Mark)
2018-01-23 14:04   ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 06/14] Hisilicon D03/D05: Open SnpPlatform " Ming Huang
2018-01-20 11:00   ` Ard Biesheuvel
2018-01-23 11:01     ` Huangming (Mark)
2018-01-23 14:07   ` Leif Lindholm
2018-01-24 12:31     ` Huangming (Mark)
2018-01-24 13:47       ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 07/14] Hisilicon/Smbios: modify type 4 Ming Huang
2018-01-20 11:01   ` Ard Biesheuvel
2018-01-23 14:15   ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 08/14] Hisilicon/PCIe: Disable PCIe ASPM Ming Huang
2018-01-20 11:04   ` Ard Biesheuvel
2018-01-18 15:01 ` [PATCH edk2-platforms v1 09/14] Hisilicon/D05: Replace SP805Watchdog by WatchdogTimer driver Ming Huang
2018-01-20 11:05   ` Ard Biesheuvel
2018-01-23 14:21   ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 10/14] Hisilicon/D03: " Ming Huang
2018-01-20 11:05   ` Ard Biesheuvel
2018-01-23 14:21   ` Leif Lindholm
2018-01-18 15:01 ` [PATCH edk2-platforms v1 11/14] Hisilicon/D05/ACPI: Add ITS PXM Ming Huang
2018-01-20 11:06   ` Ard Biesheuvel
2018-01-18 15:01 ` [PATCH edk2-platforms v1 12/14] Hisilicon/D05/ACPI: Add Pcie, HNS and SAS PXM Ming Huang
2018-01-20 11:08   ` Ard Biesheuvel
2018-01-18 15:01 ` Ming Huang [this message]
2018-01-20 11:11   ` [PATCH edk2-platforms v1 13/14] Hisilicon/Library: Add OsBootLib Ard Biesheuvel
2018-01-23 10:23   ` Leif Lindholm
2018-01-27  1:47     ` Huangming (Mark)
2018-01-27 10:37       ` Ard Biesheuvel
2018-01-29  8:55         ` Huangming (Mark)
2018-01-29 10:19           ` Ard Biesheuvel
2018-01-29 11:16       ` Leif Lindholm
2018-02-07 21:16         ` Peter Jones
2018-02-11  6:03           ` Huangming (Mark)
2018-02-26  1:12           ` Guo Heyi
2018-01-18 15:01 ` [PATCH edk2-platforms v1 14/14] Hisilicon D03/D05: Update firmware version to 18.02 Ming Huang
2018-01-20 11:11   ` Ard Biesheuvel
2018-01-23 10:18   ` Leif Lindholm
2018-01-24  1:17     ` Huangming (Mark)
2018-01-24  7:54       ` Leif Lindholm
2018-01-22 13:26 ` [PATCH edk2-platforms v1 00/14] Improve D0x platforms and bug fix Leif Lindholm
2018-01-23 14:24 ` Leif Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1516287703-35516-14-git-send-email-huangming23@huawei.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox