Better Slot Handling + Slot Switch from EDK2
authorCaramel <goldrenard@gmail.com>
星期一, 30 Aug 2021 14:12:05 +0000 (17:12 +0300)
committerCaramel <goldrenard@gmail.com>
星期一, 30 Aug 2021 14:12:05 +0000 (17:12 +0300)
22 files changed:
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c [new file with mode: 0644]
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf [new file with mode: 0644]
sdm845Pkg/Devices/fajita-8g.dsc
sdm845Pkg/Devices/fajita.dsc
sdm845Pkg/Devices/fajita.fdf
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c [new file with mode: 0644]
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib.h [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h [new file with mode: 0644]
sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h [new file with mode: 0644]
sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c [new file with mode: 0644]
sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf [new file with mode: 0644]
sdm845Pkg/Library/BootSlotLib/EFIUtils.c [new file with mode: 0644]
sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c [new file with mode: 0644]
sdm845Pkg/Library/BootSlotLib/StorageUtils.c [new file with mode: 0644]
sdm845Pkg/Library/PlatformBootManagerLib/PlatformBm.c
sdm845Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
sdm845Pkg/sdm845Pkg.dec
sdm845Pkg/sdm845Pkg.dsc

diff --git a/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c b/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c
new file mode 100644 (file)
index 0000000..3ebbc06
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SwitchSlotsApp Module
+ * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/
+ */
+
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/BootSlotLib.h>
+
+EFI_STATUS
+EFIAPI
+SwitchSlotsAppEntryPoint (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+
+  MemCardType Type = CheckRootDeviceType();
+  if (Type == UNKNOWN) {
+    PrintAndWaitAnyKey(SystemTable, L"Unknown device storage. Press any key to exit.\n");
+    return EFI_UNSUPPORTED;
+  }
+
+  EFI_STATUS Status = EnumeratePartitions();
+
+  if (EFI_ERROR (Status)) {
+    Print (L"Could not enumerate partitions. Code %d\n", Status);
+    WaitAnyKey(SystemTable);
+    return Status;
+  }
+
+  UpdatePartitionEntries();
+
+  /*Check for multislot boot support*/
+  BOOLEAN MultiSlotSupported = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
+  if (!MultiSlotSupported) {
+    PrintAndWaitAnyKey(SystemTable, L"A/B slots aren't supported on this device. Press any key to exit.\n");
+    return EFI_UNSUPPORTED;
+  }
+
+  Slot CurrentSlot = GetCurrentSlotSuffix();
+  if (IsSuffixEmpty(&CurrentSlot)) {
+    PrintAndWaitAnyKey(SystemTable, L"Current active slot not found, try to boot Android first. Press any key to exit.\n");
+    return EFI_NOT_READY;
+  }
+
+  Slot *NewSlot = NULL;
+  Slot Slots[] = {{L"_a"}, {L"_b"}};
+  if (StrnCmp (CurrentSlot.Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == 0) {
+    NewSlot = &Slots[1];
+  } else {
+    NewSlot = &Slots[0];
+  }
+
+  //Print (L"Current active slot suffix is: %s, next slot suffix is: %s\n", &CurrentSlot.Suffix, &NewSlot->Suffix);
+
+  Status = SetActiveSlot(NewSlot, TRUE, FALSE);
+
+  if (EFI_ERROR(Status)) {
+    Print (L"Could not update active slot. Code %d\n", Status);
+    WaitAnyKey(SystemTable);
+    return Status;
+  }
+
+  //Print (L"Current active slot has been updated successfully! Press any key to reboot.\n");
+  //WaitAnyKey(SystemTable);
+  gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+  CpuDeadLoop ();
+  return EFI_SUCCESS;
+}
\ No newline at end of file
diff --git a/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf b/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
new file mode 100644 (file)
index 0000000..26544f0
--- /dev/null
@@ -0,0 +1,37 @@
+# SwitchSlotsApp Application
+# Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = SwitchSlotsApp
+  FILE_GUID                      = D5BC0FB1-A833-4607-B7B6-5EF9D10BEEB7
+  MODULE_TYPE                    = UEFI_APPLICATION
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = SwitchSlotsAppEntryPoint
+
+[Sources.common]
+  SwitchSlotsApp.c
+
+[LibraryClasses]
+  UefiLib
+  UefiApplicationEntryPoint
+  BootSlotLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  sdm845Pkg/sdm845Pkg.dec
index 12008182de8737f57766d5b5878bf02a5004c47b..0013d8b31d9117fe79875fd2c57388a71450600c 100644 (file)
@@ -9,10 +9,13 @@
   SKUID_IDENTIFIER               = DEFAULT
   FLASH_DEFINITION               = sdm845Pkg/Devices/fajita.fdf
 
+  # Enable A/B Slot Environment
+  DEFINE AB_SLOTS_SUPPORT        = TRUE
+
 !include sdm845Pkg/sdm845Pkg.dsc
 
 [BuildOptions.common]
-  GCC:*_*_AARCH64_CC_FLAGS = -DMEMORY_8G=1
+  GCC:*_*_AARCH64_CC_FLAGS = -DMEMORY_8G=1 -DAB_SLOTS_SUPPORT=1
 
 [PcdsFixedAtBuild.common]
   # System Memory (7GB)
index 3ccda08f355369572c288d5b2a231606f7faddf3..8c0ac774ff721d1c16f11097d0c9877d698751d8 100644 (file)
@@ -9,8 +9,14 @@
   SKUID_IDENTIFIER               = DEFAULT
   FLASH_DEFINITION               = sdm845Pkg/Devices/fajita.fdf
 
+  # Enable A/B Slot Environment
+  DEFINE AB_SLOTS_SUPPORT        = TRUE
+
 !include sdm845Pkg/sdm845Pkg.dsc
 
+[BuildOptions.common]
+  GCC:*_*_AARCH64_CC_FLAGS = -DAB_SLOTS_SUPPORT=1
+
 [PcdsFixedAtBuild.common]
   # System Memory (5GB)
   gArmTokenSpaceGuid.PcdSystemMemorySize|0x15AE00000
index 646119e8d310484bde433d92bb2e6509b40f4e26..26b54c5f90fdcc1a221de22c5d9a98efc5450971 100644 (file)
@@ -580,11 +580,17 @@ APRIORI DXE {
   INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
   INF MdeModulePkg/Application/UiApp/UiApp.inf
   INF sdm845Pkg/Drivers/LogoDxe/LogoDxe.inf
-  
+
   #
   # OnePlus 6(T) A/B Slot Support
   #
+!ifdef $(AB_SLOTS_SUPPORT)
+  INF sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
+  INF sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
+!else
+  # Old unstable solution
   INF sdm845Pkg/Drivers/Op6tSlotDxe/Op6tSlotDxe.inf
+!endif #$(AB_SLOTS_SUPPORT)
 
 [FV.FVMAIN_COMPACT]
 FvAlignment        = 8
diff --git a/sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c b/sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c
new file mode 100644 (file)
index 0000000..72addb0
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * BootSlot DXE Driver
+ * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/
+ */
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/BootSlotLib.h>
+
+EFI_STATUS 
+EFIAPI 
+BootSlotMain(
+  IN EFI_HANDLE ImageHandle, 
+  IN EFI_SYSTEM_TABLE *SystemTable
+) {
+  MemCardType Type = CheckRootDeviceType();
+  if (Type == UNKNOWN) {
+    DEBUG ((EFI_D_ERROR, "Device storage is not supported \n"));
+    return EFI_SUCCESS;
+  }
+
+  EFI_STATUS Status = EnumeratePartitions();
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Could not enumerate partitions. Code %d\n", Status));
+    return Status;
+  }
+
+  UpdatePartitionEntries();
+
+  /*Check for multislot boot support*/
+  BOOLEAN MultiSlotSupported = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
+  if (!MultiSlotSupported) {
+    DEBUG ((EFI_D_ERROR, "A/B slots aren't supported on this device. Press any key to exit.\n"));
+    return EFI_SUCCESS;
+  }
+
+  Slot Slots[] = {{L"_a"}, {L"_b"}};
+
+  Slot CurrentSlot = GetCurrentSlotSuffix();
+  if (IsSuffixEmpty(&CurrentSlot)) {
+    CurrentSlot = Slots[0]; // Set A as active if there is no slot available (shouldn't happen though)
+  }
+
+  // Clear all unbootable bits if exists
+  for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) {
+    Slot *SlotEntry = &Slots[SlotIndex];
+    if (!IsSlotBootable(SlotEntry)) {
+      ClearUnbootable(SlotEntry);
+    }
+  }
+
+  // Set current slot as active again just refresh its attributes + mark it successful
+  Status = SetActiveSlot(&CurrentSlot, FALSE, TRUE);
+
+  if (EFI_ERROR(Status)) {
+    DEBUG ((EFI_D_ERROR, "Could not update active slot. Code %d\n", Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
\ No newline at end of file
diff --git a/sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf b/sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
new file mode 100644 (file)
index 0000000..8e4de27
--- /dev/null
@@ -0,0 +1,40 @@
+# BootSlot DXE DRIVER
+# Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/
+
+[Defines]
+  INF_VERSION                    = 0x0010005
+  BASE_NAME                      = BootSlotDxe
+  FILE_GUID                      = BA325AC5-10AB-44E3-B6C1-5BD273A3BF2D
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = BootSlotMain
+
+[Sources.common]
+  BootSlotDxe.c
+
+[LibraryClasses]
+  UefiLib
+  UefiDriverEntryPoint
+  BootSlotLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  sdm845Pkg/sdm845Pkg.dec
+
+[Depex]
+  TRUE
\ No newline at end of file
diff --git a/sdm845Pkg/Include/Library/BootSlotLib.h b/sdm845Pkg/Include/Library/BootSlotLib.h
new file mode 100644 (file)
index 0000000..a1c0ae3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * BootSlot Library
+ * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/
+ */
+
+#ifndef __BOOT_SLOT_LIB_BASE_H__
+#define __BOOT_SLOT_LIB_BASE_H__
+
+#include <Library/BootSlotLib/EFIUtils.h>
+#include <Library/BootSlotLib/PartitionTableUpdate.h>
+#include <Library/BootSlotLib/StorageUtils.h>
+
+#endif
\ No newline at end of file
diff --git a/sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h b/sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h
new file mode 100644 (file)
index 0000000..772a9fe
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSL_BLOCK_UTILS_H__
+#define __BSL_BLOCK_UTILS_H__
+
+#include <Uefi.h>
+
+#include <Guid/FileSystemInfo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/SimpleFileSystem.h>
+
+/* Selection attributes for selecting the BlkIo handles */
+#define BLK_IO_SEL_MEDIA_TYPE_REMOVABLE 0x0001
+#define BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE 0x0002
+#define BLK_IO_SEL_PARTITIONED_GPT 0x0004
+#define BLK_IO_SEL_PARTITIONED_MBR 0x0008
+#define BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID 0x0010
+#define BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM 0x0020
+#define BLK_IO_SEL_SELECT_BY_VOLUME_NAME 0x0040
+
+/* Select only the root device handle indicated. Doesn't return
+ * any partitions within.
+ * Currently this filter applies only for eMMC device, not the external
+ * device connected via USB */
+#define BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY 0x0080
+/* Select the handle that's on the indicated root device.
+ * Currently this filter applies only for eMMC device, not the external
+ * device connected via USB */
+#define BLK_IO_SEL_MATCH_ROOT_DEVICE 0x0100
+
+/* Select through partition name*/
+#define BLK_IO_SEL_MATCH_PARTITION_LABEL 0x0200
+
+/* Do case insensetive string comparisons */
+#define BLK_IO_SEL_STRING_CASE_INSENSITIVE 0x0400
+
+/* Partitioning scheme types for selecting the BlkIo handles */
+#define PARTITIONED_TYPE_MBR 0x01
+#define PARTITIONED_TYPE_GPT 0x02
+
+#define MAX_HANDLE_INFO_LIST 128
+#define BOOT_DEV_NAME_SIZE_MAX 10
+
+/* Output data providing more information about the device handle */
+typedef struct {
+  /* Handle that has BlkIO protocol installed, returned for all type of filters
+   */
+  EFI_HANDLE *Handle;
+
+  /* Block IO protocol interface is returned for all type of filters */
+  EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+  /* This HDD dev path is returned only if Matching Partition type is requested
+   * It should be noted that the contents of this memory should NOT be changed
+   */
+  const HARDDRIVE_DEVICE_PATH *PartitionInfo;
+} HandleInfo;
+
+/* Return True if integer overflow will occur */
+#define CHECK_ADD64(a, b) ((MAX_UINT64 - b < a) ? TRUE : FALSE)
+
+/* Any data specific to additional attributes can be added here. */
+typedef struct {
+  EFI_GUID *RootDeviceType; /* GUID Selecting the root device type */
+  EFI_GUID *PartitionType;  /* Partition Type to match */
+  CHAR8 *VolumeName;        /* Mounted filesystem volume name to match */
+  CHAR16 *PartitionLabel;   /* Partition label to match */
+} PartiSelectFilter;
+
+EFI_STATUS
+EFIAPI
+GetPartitionEntry (IN EFI_HANDLE Handle, 
+                   OUT EFI_PARTITION_ENTRY **PartEntry);
+
+/**
+  Returns a list of BlkIo handles based on required criteria
+  SelectionAttrib : Bitmask representing the conditions that need
+                    to be met for the handles returned. Based on the
+                    selections filter members should have valid values.
+  FilterData      : Instance of Partition Select Filter structure that
+                    needs extended data for certain type flags. For example
+                    Partition type and/or Volume name can be specified.
+  HandleInfoPtr   : Pointer Handle info where the information can be returned
+  MaxBlkIopCnt    : On input, max number of handles the buffer can hold,
+                    On output, the number of handles returned.
+
+  @retval EFI_SUCCESS if the operation was successful
+ */
+EFI_STATUS
+EFIAPI
+GetBlkIOHandles (IN UINT32 SelectionAttrib,
+                 IN PartiSelectFilter *FilterData,
+                 OUT HandleInfo *HandleInfoPtr,
+                 IN OUT UINT32 *MaxBlkIopCnt);
+
+#endif
\ No newline at end of file
diff --git a/sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h b/sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h
new file mode 100644 (file)
index 0000000..95b87a3
--- /dev/null
@@ -0,0 +1,168 @@
+/* Copyright (c) 2015-2016,2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __BSL_EFICARDINFO_H__
+#define __BSL_EFICARDINFO_H__
+
+/*===========================================================================
+  INCLUDE FILES
+===========================================================================*/
+
+/*===========================================================================
+  MACRO DECLARATIONS
+===========================================================================*/
+/** @addtogroup efi_cardInfo_constants
+@{ */
+/**
+  Protocol version.
+*/
+#define EFI_MEM_CARD_INFO_PROTOCOL_REVISION 0x0000000000010003
+/** @} */ /* end_addtogroup efi_cardInfo_constants */
+
+/*  Protocol GUID definition */
+/** @ingroup efi_cardInfo_protocol */
+#define EFI_CARD_INFO_PROTOCOL_GUID \
+   { 0x85C1F7D2, 0xBCE6, 0x4F31, { 0x8F, 0x4D, 0xD3, 0x7E, 0x03, 0xD0, 0x5E, 0xAA } }
+
+/** @cond */
+/*===========================================================================
+  EXTERNAL VARIABLES
+===========================================================================*/
+/**
+  External reference to the EFICardInfo Protocol GUID.
+ */
+extern EFI_GUID gEfiMemCardInfoProtocolGuid;
+
+/*===========================================================================
+  TYPE DEFINITIONS
+===========================================================================*/
+/**
+  Protocol declaration.
+ */
+typedef struct _EFI_MEM_CARDINFO_PROTOCOL EFI_MEM_CARDINFO_PROTOCOL;
+/** @endcond */
+
+/** @addtogroup efi_cardInfo_data_types
+@{ */
+
+/**
+ SDCC/UFS unified Card information.
+*/
+typedef struct _CARD_INFO {
+  UINT16 mfr_id;                 /**< Manufacturer ID. */
+  UINT16 oem_id;                 /**< Original equipment manufacturer ID. */
+  UINT8 mfr_date[8];             /**< Manufacture date. */
+  UINT8 product_serial_num[252]; /**< Product serial number. */
+  UINT32 serial_num_len;         /**< Product serial number length. */
+  UINT8 inquiry_str[29];         /**< Output from SCSI inquiry command. */
+  UINT32 rpmb_size_in_byte;      /**< Replay protected memory block partition
+                                      size in bytes. */
+  UINT32 reliable_write_count;   /**< Reliable write count. */
+  UINT8 card_type[4];            /**< Type of the card. 'UFS' or 'MMC' */
+} /** @cond */ MEM_CARD_INFO /** @endcond */;
+/** @} */ /* end_addtogroup efi_cardInfo_data_types */
+
+/*===========================================================================
+  FUNCTION DEFINITIONS
+===========================================================================*/
+/* GET_MEM_CARD_INFO */
+/** @ingroup efi_cardInfo_get_card_info
+  @par Summary
+  Gets the card information.
+
+  @param[in]   This              Pointer to the
+                                 EFI_MEM_CARDINFO_PROTOCOL
+                                 instance.
+  @param[out]  card_info         Pointer to a variable that the driver returns
+                                 with the retrieved card information; see
+                                 #_MEM_CARD_INFO for details.
+
+  @return
+  EFI_SUCCESS           -- Function completed successfully. \n
+  EFI_INVALID_PARAMETER -- Parameter is invalid.
+*/
+typedef EFI_STATUS (EFIAPI *GET_MEM_CARD_INFO) (
+    IN EFI_MEM_CARDINFO_PROTOCOL *This,
+    OUT MEM_CARD_INFO *card_info);
+
+/* GET_BOOT_LU */
+/** @ingroup efi_cardInfo_get_boot_lu
+  @par Summary
+  Gets the BOOT LU
+
+  @param[in]   This              Pointer to the
+                                 EFI_MEM_CARDINFO_PROTOCOL
+                                 instance.
+  @param[out]  BootLU            Pointer to a variable
+                                 that indicates the BOOT LU
+                 (0 = disable BOOT LU, 1 = BOOT for A,
+                  2 = BOOT for B)
+
+  @return
+  EFI_SUCCESS           -- Function completed successfully. \n
+  EFI_INVALID_PARAMETER -- Parameter is invalid.
+*/
+typedef EFI_STATUS (EFIAPI *GET_BOOT_LU) (IN EFI_MEM_CARDINFO_PROTOCOL *This,
+                                          OUT UINT32 *BootLU);
+/* SET_BOOT_LU */
+/** @ingroup efi_cardInfo_set_boot_lu
+  @par Summary
+  Set the BOOT LU.
+
+  @param[in]   This              Pointer to the
+                                 EFI_MEM_CARDINFO_PROTOCOL
+                                 instance.
+  @param[in]   BootLU            Boot LU to switch to
+                 (0 = disable BOOT LU, 1 = BOOT for A,
+                  2 = BOOT for B)
+
+  @return
+  EFI_SUCCESS           -- Function completed successfully. \n
+  EFI_INVALID_PARAMETER -- Parameter is invalid.
+*/
+typedef EFI_STATUS (EFIAPI *SET_BOOT_LU) (IN EFI_MEM_CARDINFO_PROTOCOL *This,
+                                          IN UINT32 BootLU);
+
+/*===========================================================================
+  PROTOCOL INTERFACE
+===========================================================================*/
+/** @ingroup efi_cardInfo_protocol
+  @par Summary
+  Secure Digital Card Controller (SDCC) Card/Universal Flash Storage (UFS) Card
+  Information Protocol interface.
+
+  @par Parameters
+  @inputprotoparams{card_info_proto_params.tex}
+*/
+struct _EFI_MEM_CARDINFO_PROTOCOL {
+  UINT64 Revision;
+  GET_MEM_CARD_INFO GetCardInfo;
+  GET_BOOT_LU GetBootLU;
+  SET_BOOT_LU SetBootLU;
+};
+
+#endif /* __EFICARDINFO_H__ */
diff --git a/sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h b/sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h
new file mode 100644 (file)
index 0000000..5f5e8c1
--- /dev/null
@@ -0,0 +1,29 @@
+
+/*
+ * SwitchSlotsApp Module
+ * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/
+ */
+
+#ifndef __BSL_EFIUTILS_H__
+#define __BSL_EFIUTILS_H__
+
+#include <Uefi.h>
+
+void WaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable);
+
+void PrintAndWaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable, CHAR16 *Message);
+
+#endif
\ No newline at end of file
diff --git a/sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h b/sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h
new file mode 100644 (file)
index 0000000..8ab08c1
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of The Linux Foundation nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __BSL_PARTITION_TABLE_H__
+#define __BSL_PARTITION_TABLE_H__
+
+#include <Library/BootSlotLib/BlockIoUtils.h>
+
+enum ReturnVal {
+  SUCCESS = 0,
+  FAILURE,
+};
+
+typedef enum {
+  PARTITION_ATTRIBUTES = 1,
+  PARTITION_GUID,
+  PARTITION_ALL,
+} UPDATE_TYPE;
+
+typedef enum {
+  PTN_ENTRIES_TO_MISC = 1,
+  PTN_ENTRIES_FROM_MISC,
+} NANDAB_UPDATE_TYPE;
+
+#define NANDAB_MAX_SLOTNAME_LEN 7
+
+#define PARTITION_ATTRIBUTES_MASK 0x1
+#define PARTITION_GUID_MASK 0x2
+
+#define MAX_HANDLEINF_LST_SIZE 128
+
+#define PARTITION_TYPE_MBR 0
+#define PARTITION_TYPE_GPT 1
+#define PARTITION_TYPE_GPT_BACKUP 2
+#define GPT_PROTECTIVE 0xEE
+#define MBR_PARTITION_RECORD 446
+#define OS_TYPE 4
+#define MBR_SIGNATURE 510
+#define MBR_SIGNATURE_BYTE_0 0x55
+#define MBR_SIGNATURE_BYTE_1 0xAA
+#define MIBIB_MAGIC1 0xFE569FAC
+#define MIBIB_MAGIC2 0xCD7F127A
+
+/* GPT Signature should be 0x5452415020494645 */
+#define GPT_SIGNATURE_1 0x54524150
+#define GPT_SIGNATURE_2 0x20494645
+#define GPT_HEADER_SIZE 92
+#define GPT_LBA 1
+#define GPT_PART_ENTRY_SIZE 128
+#define MAX_GPT_NAME_SIZE 72
+
+/* GPT Offsets */
+#define HEADER_SIZE_OFFSET 12
+#define HEADER_CRC_OFFSET 16
+#define PRIMARY_HEADER_OFFSET 24
+#define BACKUP_HEADER_OFFSET 32
+#define FIRST_USABLE_LBA_OFFSET 40
+#define LAST_USABLE_LBA_OFFSET 48
+#define PARTITION_ENTRIES_OFFSET 72
+#define PARTITION_COUNT_OFFSET 80
+#define PENTRY_SIZE_OFFSET 84
+#define PARTITION_CRC_OFFSET 88
+#define PARTITION_ENTRY_LAST_LBA 40
+#define PARTITION_TYPE_GUID_SIZE 4
+#define UNIQUE_PARTITION_GUID_SIZE 16
+
+#define PARTITION_ENTRY_SIZE 128
+#define PART_ATT_READONLY_OFFSET 60
+/*
+The attributes like Priority, Active bit,
+Max retry count, Success bit and Unabootable bits will be
+stored in attributes filed of the each partition in partition
+table in the respective position mentioned below.
+*/
+/* Partition Attribute fields*/
+#define PART_ATT_PRIORITY_BIT 48
+#define PART_ATT_ACTIVE_BIT 50
+#define PART_ATT_MAX_RETRY_CNT_BIT 51
+#define PART_ATT_SUCCESS_BIT 54
+#define PART_ATT_UNBOOTABLE_BIT 55
+
+#define PART_ATT_PRIORITY_VAL ((UINT64)0x3 << PART_ATT_PRIORITY_BIT)
+#define PART_ATT_ACTIVE_VAL ((UINT64)0x1 << PART_ATT_ACTIVE_BIT)
+#define PART_ATT_MAX_RETRY_COUNT_VAL ((UINT64)0x7 << PART_ATT_MAX_RETRY_CNT_BIT)
+#define PART_ATT_SUCCESSFUL_VAL ((UINT64)0x1 << PART_ATT_SUCCESS_BIT)
+#define PART_ATT_UNBOOTABLE_VAL ((UINT64)0x1 << PART_ATT_UNBOOTABLE_BIT)
+#define MAX_PRIORITY 3
+#define MAX_RETRY_COUNT 7
+#define MAX_NUM_PARTITIONS 128
+#define MIN_PARTITION_ARRAY_SIZE 0x4000
+#define ATTRIBUTE_FLAG_OFFSET 48
+#define INVALID_PTN -1
+#define GPT_HDR_BLOCKS 0x1
+#define MAX_PARTITION_ENTRIES_SZ (MAX_NUM_PARTITIONS * PARTITION_ENTRY_SIZE)
+#define GUID_SIZE 16
+#define PRIMARY_HDR_LBA 0x1
+#define BOOT_PART_SIZE 32
+
+/*Slot specific macros*/
+#define MAX_SLOT_SUFFIX_SZ 3
+#define MIN_SLOTS 1
+#define MAX_SLOTS 2
+#define MAX_LUNS 8
+#define NO_LUN -1
+
+#define GET_LWORD_FROM_BYTE(x)                                                 \
+  ((UINT32) * (x) | ((UINT32) * (x + 1) << 8) | ((UINT32) * (x + 2) << 16) |   \
+   ((UINT32) * (x + 3) << 24))
+
+#define GET_LLWORD_FROM_BYTE(x)                                                \
+  ((UINT64) * (x) | ((UINT64) * (x + 1) << 8) | ((UINT64) * (x + 2) << 16) |   \
+   ((UINT64) * (x + 3) << 24) | ((UINT64) * (x + 4) << 32) |                   \
+   ((UINT64) * (x + 5) << 40) | ((UINT64) * (x + 6) << 48) |                   \
+   ((UINT64) * (x + 7) << 56))
+
+#define GET_LONG(x)                                                            \
+  ((UINT32) * (x) | ((UINT32) * (x + 1) << 8) | ((UINT32) * (x + 2) << 16) |   \
+   ((UINT32) * (x + 3) << 24))
+
+#define PUT_LONG(x, y)                                                         \
+  *(x) = y & 0xff;                                                             \
+  *(x + 1) = (y >> 8) & 0xff;                                                  \
+  *(x + 2) = (y >> 16) & 0xff;                                                 \
+  *(x + 3) = (y >> 24) & 0xff;
+
+#define PUT_LONG_LONG(x, y)                                                    \
+  (*(x) = (y)&0xff);                                                           \
+  (*((x) + 1) = (((y) >> 8) & 0xff));                                          \
+  (*((x) + 2) = (((y) >> 16) & 0xff));                                         \
+  (*((x) + 3) = (((y) >> 24) & 0xff));                                         \
+  (*((x) + 4) = (((y) >> 32) & 0xff));                                         \
+  (*((x) + 5) = (((y) >> 40) & 0xff));                                         \
+  (*((x) + 6) = (((y) >> 48) & 0xff));                                         \
+  (*((x) + 7) = (((y) >> 56) & 0xff));
+
+#define GUARD(code)                                                            \
+  do {                                                                         \
+    Status = (code);                                                           \
+    if (Status != EFI_SUCCESS) {                                               \
+      DEBUG ((EFI_D_ERROR, "Err: line:%d %a() status: %r\n", __LINE__,         \
+              __FUNCTION__, Status));                                          \
+      return Status;                                                           \
+    }                                                                          \
+  } while (0)
+
+struct StoragePartInfo {
+  HandleInfo HandleInfoList[MAX_NUM_PARTITIONS];
+  UINT32 MaxHandles;
+};
+extern struct StoragePartInfo Ptable[MAX_LUNS];
+
+typedef struct {
+  CHAR16 Suffix[MAX_SLOT_SUFFIX_SZ];
+} Slot;
+
+Slot GetCurrentSlotSuffix ();
+UINT32 GetMaxLuns ();
+VOID GetPartitionCount (UINT32 *Val);
+VOID SetMultiSlotBootVal (BOOLEAN Val);
+
+struct PartitionEntry {
+  EFI_PARTITION_ENTRY PartEntry;
+  UINT32 lun;
+};
+extern struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
+
+struct BootPartsLinkedList {
+  CHAR16 PartName[BOOT_PART_SIZE];
+  struct BootPartsLinkedList *Next;
+};
+
+INT32 GetPartitionIndex (CHAR16 *PartitionName);
+BOOLEAN PartitionHasMultiSlot (CONST CHAR16 *Pname);
+EFI_STATUS EnumeratePartitions (VOID);
+VOID UpdatePartitionEntries (VOID);
+VOID UpdatePartitionAttributes (UINT32 UpdateType);
+BOOLEAN IsSuffixEmpty (Slot *CheckSlot);
+EFI_STATUS SetActiveSlot (Slot *NewSlot, BOOLEAN ResetSuccessBit, BOOLEAN SetSuccessBit);
+BOOLEAN IsSlotBootable (Slot *CheckSlot);
+EFI_STATUS ClearUnbootable (Slot *CheckSlot);
+UINT64 GetPartitionSize (EFI_BLOCK_IO_PROTOCOL *BlockIo);
+
+#endif
diff --git a/sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h b/sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h
new file mode 100644 (file)
index 0000000..11597f2
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSL_BOARD_H__
+#define __BSL_BOARD_H__
+
+#include <Uefi.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BootSlotLib/EFICardInfo.h>
+
+#define HANDLE_MAX_INFO_LIST 128
+
+typedef enum {
+  EMMC = 0,
+  UFS = 1,
+  UNKNOWN,
+} MemCardType;
+
+VOID
+GetRootDeviceType (CHAR8 *StrDeviceType, UINT32 Len);
+MemCardType
+CheckRootDeviceType (VOID);
+EFI_STATUS
+UfsGetSetBootLun (UINT32 *UfsBootlun, BOOLEAN IsGet);
+
+#endif
\ No newline at end of file
diff --git a/sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c b/sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c
new file mode 100644 (file)
index 0000000..069e09d
--- /dev/null
@@ -0,0 +1,361 @@
+/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "AutoGen.h"
+#include <Library/BootSlotLib/BlockIoUtils.h>
+#include <Library/BootSlotLib/EFIUtils.h>
+#include <Protocol/PartitionInfo.h>
+
+/* Volume Label size 11 chars, round off to 16 */
+#define VOLUME_LABEL_SIZE 16
+
+/* List of all the filters that need device path protocol in the handle to
+ * filter */
+#define FILTERS_NEEDING_DEVICEPATH                                             \
+  (BLK_IO_SEL_PARTITIONED_MBR | BLK_IO_SEL_PARTITIONED_GPT |                   \
+   BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID | BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY | \
+   BLK_IO_SEL_MATCH_ROOT_DEVICE)
+
+/* Returns 0 if the volume label matches otherwise non zero */
+STATIC UINTN
+CompareVolumeLabel (IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL*   Fs,
+                    IN CHAR8*                             ReqVolumeName)
+{
+  INT32 CmpResult;
+  UINT32 j;
+  UINT16 VolumeLabel[VOLUME_LABEL_SIZE];
+  EFI_FILE_PROTOCOL  *FsVolume = NULL;
+  EFI_STATUS         Status;
+  UINTN                               Size;
+  EFI_FILE_SYSTEM_INFO                *FsInfo;
+
+  // Get information about the volume
+  Status = Fs->OpenVolume (Fs, &FsVolume);
+
+  if (Status != EFI_SUCCESS) {
+    return 1;
+  }
+
+  /* Get the Volume name */
+  Size = 0;
+  FsInfo = NULL;
+  Status = FsVolume->GetInfo (FsVolume, &gEfiFileSystemInfoGuid, &Size, FsInfo);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    FsInfo = AllocateZeroPool (Size);
+    Status = FsVolume->GetInfo (FsVolume,
+                                &gEfiFileSystemInfoGuid, &Size, FsInfo);
+    if (Status != EFI_SUCCESS) {
+      FreePool (FsInfo);
+      return 1;
+    }
+  }
+
+  if (FsInfo == NULL) {
+    return 1;
+  }
+
+  /* Convert the passed in Volume name to Wide char and upper case */
+  for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && ReqVolumeName[j]; ++j) {
+    VolumeLabel[j] = ReqVolumeName[j];
+
+    if ((VolumeLabel[j] >= 'a') &&
+        (VolumeLabel[j] <= 'z')) {
+      VolumeLabel[j] -= ('a' - 'A');
+    }
+  }
+
+  /* Null termination */
+  VolumeLabel[j] = 0;
+
+  /* Change any lower chars in volume name to upper
+   * (ideally this is not needed) */
+  for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && FsInfo->VolumeLabel[j]; ++j) {
+    if ((FsInfo->VolumeLabel[j] >= 'a') &&
+          (FsInfo->VolumeLabel[j] <= 'z')) {
+      FsInfo->VolumeLabel[j] -= ('a' - 'A');
+    }
+  }
+
+  CmpResult = StrnCmp (FsInfo->VolumeLabel, VolumeLabel, VOLUME_LABEL_SIZE);
+
+  FreePool (FsInfo);
+  FsVolume->Close (FsVolume);
+
+  return CmpResult;
+}
+
+EFI_STATUS
+EFIAPI
+GetPartitionEntry (IN EFI_HANDLE Handle, 
+                   OUT EFI_PARTITION_ENTRY **PartEntry)
+{
+  EFI_PARTITION_INFO_PROTOCOL *PartInfo;
+  EFI_STATUS Status = gBS->HandleProtocol (Handle, &gEfiPartitionInfoProtocolGuid, (VOID **)&PartInfo);
+  if (!EFI_ERROR(Status)) {
+    *PartEntry = &PartInfo->Info.Gpt;
+  }
+  return Status;
+}
+
+/**
+  Returns a list of BlkIo handles based on required criteria
+SelectionAttrib : Bitmask representing the conditions that need
+to be met for the handles returned. Based on the
+selections filter members should have valid values.
+FilterData      : Instance of Partition Select Filter structure that
+needs extended data for certain type flags. For example
+Partition type and/or Volume name can be specified.
+HandleInfoPtr   : Pointer to array of HandleInfo structures in which the
+output is returned.
+MaxBlkIopCnt    : On input, max number of handle structures the buffer can hold,
+On output, the number of handle structures returned.
+
+@retval EFI_SUCCESS if the operation was successful
+*/
+EFI_STATUS
+EFIAPI
+GetBlkIOHandles (IN UINT32 SelectionAttrib,
+                 IN PartiSelectFilter *FilterData,
+                 OUT HandleInfo *HandleInfoPtr,
+                 IN OUT UINT32* MaxBlkIopCnt)
+{
+  EFI_BLOCK_IO_PROTOCOL *BlkIo;
+  EFI_HANDLE *BlkIoHandles;
+  UINTN BlkIoHandleCount;
+  UINTN i;
+  UINTN DevicePathDepth;
+  HARDDRIVE_DEVICE_PATH *Partition, *PartitionOut;
+  EFI_STATUS Status;
+  EFI_DEVICE_PATH_PROTOCOL *DevPathInst;
+  EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+  VENDOR_DEVICE_PATH *RootDevicePath;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *Fs;
+  UINT32 BlkIoCnt = 0;
+  EFI_PARTITION_ENTRY *PartEntry;
+
+  if ((MaxBlkIopCnt == NULL) || (HandleInfoPtr == NULL))
+    return EFI_INVALID_PARAMETER;
+
+  /* Adjust some defaults first */
+  if ((SelectionAttrib & (BLK_IO_SEL_MEDIA_TYPE_REMOVABLE |
+                          BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE)) == 0)
+    SelectionAttrib |=
+        (BLK_IO_SEL_MEDIA_TYPE_REMOVABLE | BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE);
+
+  if (((BLK_IO_SEL_PARTITIONED_GPT | BLK_IO_SEL_PARTITIONED_MBR) &
+       SelectionAttrib) == 0)
+    SelectionAttrib |=
+        (BLK_IO_SEL_PARTITIONED_GPT | BLK_IO_SEL_PARTITIONED_MBR);
+
+  /* If we need Filesystem handle then search based on that its narrower search
+   * than BlkIo */
+  if (SelectionAttrib & (BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM |
+                         BLK_IO_SEL_SELECT_BY_VOLUME_NAME)) {
+    Status =
+        gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
+                                 NULL, &BlkIoHandleCount, &BlkIoHandles);
+  } else {
+    Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
+                                      NULL, &BlkIoHandleCount, &BlkIoHandles);
+  }
+
+  if (Status != EFI_SUCCESS) {
+    DEBUG (
+        (EFI_D_ERROR, "Unable to get Filesystem Handle buffer %r\n", Status));
+    return Status;
+  }
+
+  /* Loop through to search for the ones we are interested in. */
+  for (i = 0; i < BlkIoHandleCount; i++) {
+
+    Status = gBS->HandleProtocol (BlkIoHandles[i], &gEfiBlockIoProtocolGuid,
+                                  (VOID **)&BlkIo);
+    /* Fv volumes will not support Blk I/O protocol */
+    if (Status == EFI_UNSUPPORTED) {
+      continue;
+    }
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_ERROR, "Unable to get Filesystem Handle %r\n", Status));
+      return Status;
+    }
+
+    /* Check if the media type criteria (for removable/not) satisfies */
+    if (BlkIo->Media->RemovableMedia) {
+      if ((SelectionAttrib & BLK_IO_SEL_MEDIA_TYPE_REMOVABLE) == 0)
+        continue;
+    } else {
+      if ((SelectionAttrib & BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE) == 0)
+        continue;
+    }
+
+    /* Clear the pointer, we can get it if the filter is set */
+    PartitionOut = NULL;
+
+    /* Check if partition related criteria satisfies */
+    if ((SelectionAttrib & FILTERS_NEEDING_DEVICEPATH) != 0) {
+      Status = gBS->HandleProtocol (
+          BlkIoHandles[i], &gEfiDevicePathProtocolGuid, (VOID **)&DevPathInst);
+
+      /* If we didn't get the DevicePath Protocol then this handle
+       * cannot be used */
+      if (EFI_ERROR (Status))
+        continue;
+
+      DevicePathDepth = 0;
+
+      /* Get the device path */
+      TempDevicePath = DevPathInst;
+      RootDevicePath = (VENDOR_DEVICE_PATH *)DevPathInst;
+      Partition = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+
+      if ((SelectionAttrib & (BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY |
+                              BLK_IO_SEL_MATCH_ROOT_DEVICE)) != 0) {
+        if (!FilterData) {
+          return EFI_INVALID_PARAMETER;
+        }
+        /* If this is not the root device that we are looking for, ignore this
+         * handle */
+        if (RootDevicePath->Header.Type != HARDWARE_DEVICE_PATH ||
+            RootDevicePath->Header.SubType != HW_VENDOR_DP ||
+            (RootDevicePath->Header.Length[0] |
+             (RootDevicePath->Header.Length[1] << 8)) !=
+                sizeof (VENDOR_DEVICE_PATH) ||
+            ((FilterData->RootDeviceType != NULL) &&
+             (CompareGuid (FilterData->RootDeviceType,
+                           &RootDevicePath->Guid) == FALSE)))
+          continue;
+      }
+
+      /* Locate the last Device Path Node */
+      while (!IsDevicePathEnd (TempDevicePath)) {
+        DevicePathDepth++;
+        Partition = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+        TempDevicePath = NextDevicePathNode (TempDevicePath);
+      }
+
+      /* If we need the handle for root device only and if this is representing
+       * a sub partition in the root device then ignore this handle */
+      if (SelectionAttrib & BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY)
+        if (DevicePathDepth > 1)
+          continue;
+
+      /* Check if the last node is Harddrive Device path that contains the
+       * Partition information */
+      if (Partition->Header.Type == MEDIA_DEVICE_PATH &&
+          Partition->Header.SubType == MEDIA_HARDDRIVE_DP &&
+          (Partition->Header.Length[0] | (Partition->Header.Length[1] << 8)) ==
+              sizeof (*Partition)) {
+        PartitionOut = Partition;
+
+        if ((SelectionAttrib & BLK_IO_SEL_PARTITIONED_GPT) == 0)
+          if (Partition->MBRType == PARTITIONED_TYPE_GPT)
+            continue;
+
+        if ((SelectionAttrib & BLK_IO_SEL_PARTITIONED_MBR) == 0)
+          if (Partition->MBRType == PARTITIONED_TYPE_MBR)
+            continue;
+
+        /* PartitionDxe implementation should return partition type also */
+        if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0) {
+          VOID *Interface;
+
+          if (!FilterData ||
+                FilterData->PartitionType == NULL) {
+            return EFI_INVALID_PARAMETER;
+          }
+
+          Status = gBS->HandleProtocol (BlkIoHandles[i],
+                                        FilterData->PartitionType,
+                                        (VOID**)&Interface);
+          if (EFI_ERROR (Status)) {
+              Status = GetPartitionEntry(BlkIoHandles[i], &PartEntry);
+              if (EFI_ERROR (Status)) {
+                continue;
+              }
+              if (CompareGuid (&PartEntry->PartitionTypeGUID, FilterData->PartitionType) == FALSE) {
+                continue;
+              }
+          }
+        }
+      }
+      /* If we wanted a particular partition and didn't get the HDD DP,
+         then this handle is probably not the interested ones */
+      else if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0)
+          continue;
+    }
+
+    /* Check if the Filesystem related criteria satisfies */
+    if ((SelectionAttrib & BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM) != 0) {
+      Status = gBS->HandleProtocol (BlkIoHandles[i],
+                               &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      if ((SelectionAttrib & BLK_IO_SEL_SELECT_BY_VOLUME_NAME) != 0) {
+        if (!FilterData ||
+             FilterData->VolumeName == NULL) {
+          return EFI_INVALID_PARAMETER;
+        }
+        if (CompareVolumeLabel (Fs, FilterData->VolumeName) != 0) {
+          continue;
+        }
+      }
+    }
+
+    /* Check if the Partition name related criteria satisfies */
+    if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_LABEL) != 0) {
+      Status = GetPartitionEntry(BlkIoHandles[i], &PartEntry);
+      if (Status != EFI_SUCCESS)
+        continue;
+      if (StrnCmp (PartEntry->PartitionName, FilterData->PartitionLabel,
+                   MAX (StrLen (PartEntry->PartitionName),
+                        StrLen (FilterData->PartitionLabel))))
+        continue;
+    }
+    /* We came here means, this handle satisfies all the conditions needed,
+     * Add it into the list */
+    HandleInfoPtr[BlkIoCnt].Handle = BlkIoHandles[i];
+    HandleInfoPtr[BlkIoCnt].BlkIo = BlkIo;
+    HandleInfoPtr[BlkIoCnt].PartitionInfo = PartitionOut;
+    BlkIoCnt++;
+    if (BlkIoCnt >= *MaxBlkIopCnt)
+      break;
+  }
+
+  *MaxBlkIopCnt = BlkIoCnt;
+
+  /* Free the handle buffer */
+  if (BlkIoHandles != NULL) {
+    FreePool (BlkIoHandles);
+    BlkIoHandles = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
\ No newline at end of file
diff --git a/sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf b/sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf
new file mode 100644 (file)
index 0000000..d47c143
--- /dev/null
@@ -0,0 +1,68 @@
+# /*
+#  * BootSlot Library
+#  * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+#  *
+#  * This program is free software: you can redistribute it and/or modify
+#  * it under the terms of the GNU General Public License as published by
+#  * the Free Software Foundation, either version 3 of the License, or
+#  * (at your option) any later version.
+#  *
+#  * This program is distributed in the hope that it will be useful,
+#  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  * GNU General Public License for more details.
+#  *
+#  * You should have received a copy of the GNU General Public License
+#  * along with this program.  If not, see <https://www.gnu.org/licenses/
+#  */
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BootSlotLib
+  FILE_GUID                      = 6071c048-1de6-4141-ba0a-4500e1096572
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = BootSlotLib
+
+[Sources]
+  EFIUtils.c
+  StorageUtils.c
+  BlockIoUtils.c
+  PartitionTableUpdate.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  sdm845Pkg/sdm845Pkg.dec
+
+[LibraryClasses]
+  UefiLib
+  BaseLib
+  DebugLib
+  DevicePathLib
+
+[Guids]
+  gEfiFileSystemInfoGuid
+  gEfiEmmcUserPartitionGuid
+  gEfiUfsLU0Guid
+  gEfiUfsLU1Guid
+  gEfiUfsLU2Guid
+  gEfiUfsLU3Guid
+  gEfiUfsLU4Guid
+  gEfiUfsLU5Guid
+  gEfiUfsLU6Guid
+  gEfiUfsLU7Guid
+
+[Protocols]
+  gEfiBlockIoProtocolGuid
+  gEfiDiskIoProtocolGuid
+  gEfiPartitionInfoProtocolGuid
+  gEfiDevicePathToTextProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEfiDevicePathFromTextProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiMemCardInfoProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/sdm845Pkg/Library/BootSlotLib/EFIUtils.c b/sdm845Pkg/Library/BootSlotLib/EFIUtils.c
new file mode 100644 (file)
index 0000000..21021e6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SwitchSlotsApp Module
+ * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/
+ */
+
+#include <Library/BootSlotLib/EFIUtils.h>
+#include <Library/UefiLib.h>
+
+void WaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable) {
+    UINTN index = 0;
+    EFI_INPUT_KEY Key;
+    mSystemTable->BootServices->WaitForEvent(1, &mSystemTable->ConIn->WaitForKey, &index);
+    mSystemTable->ConIn->ReadKeyStroke(mSystemTable->ConIn, &Key);
+}
+
+void PrintAndWaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable, CHAR16 *Message) {
+    Print(Message);
+    WaitAnyKey(mSystemTable);
+}
\ No newline at end of file
diff --git a/sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c b/sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c
new file mode 100644 (file)
index 0000000..9176a7d
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of The Linux Foundation nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "AutoGen.h"
+#include <Uefi.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BootSlotLib.h>
+
+struct StoragePartInfo Ptable[MAX_LUNS];
+struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
+STATIC UINT32 MaxLuns;
+STATIC UINT32 PartitionCount;
+STATIC struct PartitionEntry PtnEntriesBak[MAX_NUM_PARTITIONS];
+
+STATIC struct BootPartsLinkedList *HeadNode;
+STATIC EFI_STATUS
+GetActiveSlot (Slot *ActiveSlot);
+
+Slot GetCurrentSlotSuffix (VOID)
+{
+  Slot CurrentSlot = {{0}};
+  BOOLEAN IsMultiSlot = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
+
+  if (IsMultiSlot == FALSE) {
+    return CurrentSlot;
+  }
+
+  GetActiveSlot (&CurrentSlot);
+  return CurrentSlot;
+}
+
+VOID
+GetPartitionCount (UINT32 *Val)
+{
+  *Val = PartitionCount;
+  return;
+}
+
+VOID UpdatePartitionEntries (VOID)
+{
+  UINT32 i;
+  UINT32 j;
+  UINT32 Index = 0;
+  EFI_STATUS Status;
+  EFI_PARTITION_ENTRY *PartEntry;
+
+  PartitionCount = 0;
+  /*Nullify the PtnEntries array before using it*/
+  gBS->SetMem ((VOID *)PtnEntries,
+               (sizeof (PtnEntries[0]) * MAX_NUM_PARTITIONS), 0);
+
+  for (i = 0; i < MaxLuns; i++) {
+    for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS);
+         j++, Index++) {
+      Status = GetPartitionEntry(Ptable[i].HandleInfoList[j].Handle, &PartEntry);
+      PartitionCount++;
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_VERBOSE, "Selected Lun : %d, handle: %d does not have "
+                               "partition record, ignore\n",
+                i, j));
+        PtnEntries[Index].lun = i;
+        continue;
+      }
+      gBS->CopyMem ((&PtnEntries[Index]), PartEntry, sizeof (PartEntry[0]));
+      PtnEntries[Index].lun = i;
+    }
+  }
+  /* Back up the ptn entries */
+  gBS->CopyMem (PtnEntriesBak, PtnEntries, sizeof (PtnEntries));
+}
+
+INT32
+GetPartitionIndex (CHAR16 *Pname)
+{
+  INT32 i;
+
+  for (i = 0; i < PartitionCount; i++) {
+    if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname,
+                  ARRAY_SIZE (PtnEntries[i].PartEntry.PartitionName))) {
+      return i;
+    }
+  }
+
+  return INVALID_PTN;
+}
+
+STATIC EFI_STATUS
+GetStorageHandle (INT32 Lun, HandleInfo *BlockIoHandle, UINT32 *MaxHandles)
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  UINT32 Attribs = 0;
+  PartiSelectFilter HandleFilter;
+  // UFS LUN GUIDs
+  EFI_GUID LunGuids[] = {
+      gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid,
+      gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid,
+  };
+
+  Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY;
+  HandleFilter.PartitionType = NULL;
+  HandleFilter.VolumeName = NULL;
+
+  if (Lun == NO_LUN) {
+    HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
+    Status =
+        GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Emmc\n"));
+      return Status;
+    }
+  } else {
+    HandleFilter.RootDeviceType = &LunGuids[Lun];
+    Status =
+        GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun));
+      return Status;
+    }
+  }
+
+  return Status;
+}
+
+STATIC BOOLEAN IsUpdatePartitionAttributes ()
+{
+  if (CompareMem (PtnEntries, PtnEntriesBak, sizeof (PtnEntries))) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+UINT64 GetPartitionSize (EFI_BLOCK_IO_PROTOCOL *BlockIo)
+{
+  UINT64 PartitionSize;
+
+  if (!BlockIo) {
+    DEBUG ((EFI_D_ERROR, "Invalid parameter, pleae check BlockIo info!!!\n"));
+    return 0;
+  }
+
+  if (CHECK_ADD64 (BlockIo->Media->LastBlock, 1)) {
+    DEBUG ((EFI_D_ERROR, "Integer overflow while adding LastBlock and 1\n"));
+    return 0;
+  }
+
+  if ((MAX_UINT64 / (BlockIo->Media->LastBlock + 1)) <
+    (UINT64)BlockIo->Media->BlockSize) {
+    DEBUG ((EFI_D_ERROR,
+     "Integer overflow while multiplying LastBlock and BlockSize\n"));
+    return 0;
+  }
+
+  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
+  return  PartitionSize;
+}
+
+VOID UpdatePartitionAttributes (UINT32 UpdateType)
+{
+  UINT32 BlkSz;
+  UINT8 *GptHdr = NULL;
+  UINT8 *GptHdrPtr = NULL;
+  UINTN MaxGptPartEntrySzBytes;
+  UINT32 Offset;
+  UINT32 MaxPtnCount = 0;
+  UINT32 PtnEntrySz = 0;
+  UINT32 i = 0;
+  UINT8 *PtnEntriesPtr;
+  UINT8 *Ptn_Entries;
+  UINT32 CrcVal = 0;
+  UINT32 Iter;
+  UINT32 HdrSz = GPT_HEADER_SIZE;
+  UINT64 DeviceDensity;
+  UINT64 CardSizeSec;
+  EFI_STATUS Status;
+  INT32 Lun;
+  EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
+  HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
+  UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
+  CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
+  UINT32 PartEntriesblocks = 0;
+  BOOLEAN SkipUpdation;
+  UINT64 Attr;
+  struct PartitionEntry *InMemPtnEnt;
+
+  /* The PtnEntries is the same as PtnEntriesBak by default
+   *  It needs to update attributes or GUID when PtnEntries is changed
+   */
+  if (!IsUpdatePartitionAttributes ()) {
+    return;
+  }
+
+  GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
+  for (Lun = 0; Lun < MaxLuns; Lun++) {
+
+    if (!AsciiStrnCmp (BootDeviceType, "EMMC", AsciiStrLen ("EMMC"))) {
+      Status = GetStorageHandle (NO_LUN, BlockIoHandle, &MaxHandles);
+    } else if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
+      Status = GetStorageHandle (Lun, BlockIoHandle, &MaxHandles);
+    } else {
+      DEBUG ((EFI_D_ERROR, "Unsupported  boot device type\n"));
+      return;
+    }
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_ERROR,
+              "Failed to get BlkIo for device. MaxHandles:%d - %r\n",
+              MaxHandles, Status));
+      return;
+    }
+    if (MaxHandles != 1) {
+      DEBUG ((EFI_D_VERBOSE,
+              "Failed to get the BlockIo for device. MaxHandle:%d, %r\n",
+              MaxHandles, Status));
+      continue;
+    }
+
+    BlockIo = BlockIoHandle[0].BlkIo;
+    DeviceDensity = GetPartitionSize (BlockIo);
+    if (!DeviceDensity) {
+      return;
+    }
+    BlkSz = BlockIo->Media->BlockSize;
+    PartEntriesblocks = MAX_PARTITION_ENTRIES_SZ / BlkSz;
+    MaxGptPartEntrySzBytes = (GPT_HDR_BLOCKS + PartEntriesblocks) * BlkSz;
+    CardSizeSec = (DeviceDensity) / BlkSz;
+    Offset = PRIMARY_HDR_LBA;
+    GptHdr = AllocateZeroPool (MaxGptPartEntrySzBytes);
+    if (!GptHdr) {
+      DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n"));
+      return;
+    }
+
+    GptHdrPtr = GptHdr;
+
+    /* This loop iterates twice to update both primary and backup Gpt*/
+    for (Iter = 0; Iter < 2;
+         Iter++, (Offset = CardSizeSec - MaxGptPartEntrySzBytes / BlkSz)) {
+      SkipUpdation = TRUE;
+      Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
+                                    MaxGptPartEntrySzBytes, GptHdr);
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "Unable to read the media \n"));
+        goto Exit;
+      }
+
+      if (Iter == 0x1) {
+        /* This is the back up GPT */
+        Ptn_Entries = GptHdr;
+        GptHdr = GptHdr + ((PartEntriesblocks)*BlkSz);
+      } else
+        /* otherwise we are at the primary gpt */
+        Ptn_Entries = GptHdr + BlkSz;
+
+      PtnEntriesPtr = Ptn_Entries;
+
+      for (i = 0; i < PartitionCount; i++) {
+        InMemPtnEnt = (struct PartitionEntry *)PtnEntriesPtr;
+        /*If GUID is not present, then it is BlkIo Handle of the Lun. Skip*/
+        if (!(PtnEntries[i].PartEntry.PartitionTypeGUID.Data1)) {
+          DEBUG ((EFI_D_VERBOSE, " Skipping Lun:%d, i=%d\n", Lun, i));
+          continue;
+        }
+
+        if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
+          /* Partition table is populated with entries from lun 0 to max lun.
+           * break out of the loop once we see the partition lun is > current
+           * lun */
+          if (PtnEntries[i].lun > Lun)
+            break;
+          /* Find the entry where the partition table for 'lun' starts and then
+           * update the attributes */
+          if (PtnEntries[i].lun != Lun)
+            continue;
+        }
+        Attr = GET_LLWORD_FROM_BYTE (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET]);
+        if (UpdateType & PARTITION_GUID_MASK) {
+          if (CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID,
+              &PtnEntries[i].PartEntry.PartitionTypeGUID,
+              sizeof (EFI_GUID))) {
+            /* Update the partition GUID values */
+            gBS->CopyMem ((VOID *)PtnEntriesPtr,
+                          (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID,
+                          GUID_SIZE);
+            /* Update the PtnEntriesBak for next comparison */
+            gBS->CopyMem (
+                        (VOID *)&PtnEntriesBak[i].PartEntry.PartitionTypeGUID,
+                        (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID,
+                        GUID_SIZE);
+            SkipUpdation = FALSE;
+          }
+        }
+
+        if (UpdateType & PARTITION_ATTRIBUTES_MASK) {
+          /*  If GUID is not present, then it is back up GPT, update it
+           *  If GUID is present,  and the GUID is matched, update it
+           */
+          if (!(InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) ||
+              !CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID,
+              &PtnEntries[i].PartEntry.PartitionTypeGUID,
+              sizeof (EFI_GUID))) {
+            if (Attr != PtnEntries[i].PartEntry.Attributes) {
+              /* Update the partition attributes */
+              PUT_LONG_LONG (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET],
+                              PtnEntries[i].PartEntry.Attributes);
+              /* Update the PtnEntriesBak for next comparison */
+              PtnEntriesBak[i].PartEntry.Attributes =
+                              PtnEntries[i].PartEntry.Attributes;
+              SkipUpdation = FALSE;
+            }
+          } else {
+            if (InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) {
+              DEBUG ((EFI_D_ERROR,
+                    "Error in GPT header, GUID is not match!\n"));
+              continue;
+            }
+          }
+        }
+
+        /* point to the next partition entry */
+        PtnEntriesPtr += PARTITION_ENTRY_SIZE;
+      }
+
+      if (SkipUpdation)
+        continue;
+
+      MaxPtnCount = GET_LWORD_FROM_BYTE (&GptHdr[PARTITION_COUNT_OFFSET]);
+      PtnEntrySz = GET_LWORD_FROM_BYTE (&GptHdr[PENTRY_SIZE_OFFSET]);
+
+      if (((UINT64) (MaxPtnCount)*PtnEntrySz) > MAX_PARTITION_ENTRIES_SZ) {
+        DEBUG ((EFI_D_ERROR,
+                "Invalid GPT header fields MaxPtnCount = %x, PtnEntrySz = %x\n",
+                MaxPtnCount, PtnEntrySz));
+        goto Exit;
+      }
+
+      Status = gBS->CalculateCrc32 (Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)),
+                                    &CrcVal);
+      if (Status != EFI_SUCCESS) {
+        DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n",
+                Status));
+        goto Exit;
+      }
+
+      PUT_LONG (&GptHdr[PARTITION_CRC_OFFSET], CrcVal);
+
+      /*Write CRC to 0 before we calculate the crc of the GPT header*/
+      CrcVal = 0;
+      PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal);
+
+      Status = gBS->CalculateCrc32 (GptHdr, HdrSz, &CrcVal);
+      if (Status != EFI_SUCCESS) {
+        DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n",
+                Status));
+        goto Exit;
+      }
+
+      PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal);
+
+      if (Iter == 0x1)
+        /* Write the backup GPT header, which is at an offset of CardSizeSec -
+         * MaxGptPartEntrySzBytes/BlkSz in blocks*/
+        Status =
+            BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
+                                  MaxGptPartEntrySzBytes, (VOID *)Ptn_Entries);
+      else
+        /* Write the primary GPT header, which is at an offset of BlkSz */
+        Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
+                                       MaxGptPartEntrySzBytes, (VOID *)GptHdr);
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
+        goto Exit;
+      }
+    }
+    FreePool (GptHdrPtr);
+    GptHdrPtr = NULL;
+  }
+
+Exit:
+  if (GptHdrPtr) {
+    FreePool (GptHdrPtr);
+    GptHdrPtr = NULL;
+  }
+}
+
+STATIC VOID
+MarkPtnActive (CHAR16 *ActiveSlot)
+{
+  UINT32 i;
+  for (i = 0; i < PartitionCount; i++) {
+    /* Mark all the slots with current ActiveSlot as active */
+    if (StrStr (PtnEntries[i].PartEntry.PartitionName, ActiveSlot))
+      PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL;
+    else
+      PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL;
+  }
+
+  /* Update the partition table */
+  UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
+}
+
+STATIC VOID
+SwapPtnGuid (EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2)
+{
+  EFI_GUID Temp;
+
+  if (p1 == NULL || p2 == NULL)
+    return;
+  gBS->CopyMem ((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID,
+                sizeof (EFI_GUID));
+  gBS->CopyMem ((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID,
+                sizeof (EFI_GUID));
+  gBS->CopyMem ((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp,
+                sizeof (EFI_GUID));
+}
+
+STATIC EFI_STATUS GetMultiSlotPartsList (VOID)
+{
+  UINT32 i = 0;
+  UINT32 j = 0;
+  UINT32 Len = 0;
+  UINT32 PtnLen = 0;
+  CHAR16 *SearchString = NULL;
+  struct BootPartsLinkedList *TempNode = NULL;
+
+  for (i = 0; i < PartitionCount; i++) {
+    SearchString = PtnEntries[i].PartEntry.PartitionName;
+    if (!SearchString[0])
+      continue;
+
+    for (j = i + 1; j < PartitionCount; j++) {
+      if (!PtnEntries[j].PartEntry.PartitionName[0])
+        continue;
+      Len = StrLen (SearchString);
+      PtnLen = StrLen (PtnEntries[j].PartEntry.PartitionName);
+
+      /*Need to compare till "boot_"a hence skip last Char from StrLen value*/
+      if ((PtnLen == Len) &&
+          !StrnCmp (PtnEntries[j].PartEntry.PartitionName,
+          SearchString, Len - 1) &&
+          (StrStr (SearchString, (CONST CHAR16 *)L"_a") ||
+          StrStr (SearchString, (CONST CHAR16 *)L"_b"))) {
+        TempNode = AllocateZeroPool (sizeof (struct BootPartsLinkedList));
+        if (TempNode) {
+          /*Skip _a/_b from partition name*/
+          StrnCpyS (TempNode->PartName, sizeof (TempNode->PartName),
+                    SearchString, Len - 2);
+          TempNode->Next = HeadNode;
+          HeadNode = TempNode;
+        } else {
+          DEBUG ((EFI_D_ERROR,
+                  "Unable to Allocate Memory for MultiSlot Partition list\n"));
+          return EFI_OUT_OF_RESOURCES;
+        }
+        break;
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC VOID
+SwitchPtnSlots (CONST CHAR16 *SetActive)
+{
+  UINT32 i;
+  struct PartitionEntry *PtnCurrent = NULL;
+  struct PartitionEntry *PtnNew = NULL;
+  CHAR16 CurSlot[BOOT_PART_SIZE];
+  CHAR16 NewSlot[BOOT_PART_SIZE];
+  CHAR16 SetInactive[MAX_SLOT_SUFFIX_SZ];
+  UINT32 UfsBootLun = 0;
+  BOOLEAN UfsGet = TRUE;
+  BOOLEAN UfsSet = FALSE;
+  struct BootPartsLinkedList *TempNode = NULL;
+  EFI_STATUS Status;
+  CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
+
+  /* Create the partition name string for active and non active slots*/
+  if (!StrnCmp (SetActive, (CONST CHAR16 *)L"_a",
+                StrLen ((CONST CHAR16 *)L"_a")))
+    StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_b",
+              StrLen ((CONST CHAR16 *)L"_b"));
+  else
+    StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_a",
+              StrLen ((CONST CHAR16 *)L"_a"));
+
+  if (!HeadNode) {
+    Status = GetMultiSlotPartsList ();
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_INFO, "Unable to get GetMultiSlotPartsList\n"));
+      return;
+    }
+  }
+
+  for (TempNode = HeadNode; TempNode; TempNode = TempNode->Next) {
+    gBS->SetMem (CurSlot, BOOT_PART_SIZE, 0);
+    gBS->SetMem (NewSlot, BOOT_PART_SIZE, 0);
+
+    StrnCpyS (CurSlot, BOOT_PART_SIZE, TempNode->PartName,
+              StrLen (TempNode->PartName));
+    StrnCatS (CurSlot, BOOT_PART_SIZE, SetInactive, StrLen (SetInactive));
+
+    StrnCpyS (NewSlot, BOOT_PART_SIZE, TempNode->PartName,
+              StrLen (TempNode->PartName));
+    StrnCatS (NewSlot, BOOT_PART_SIZE, SetActive, StrLen (SetActive));
+
+    /* Find the pointer to partition table entry for active and non-active
+     * slots*/
+    for (i = 0; i < PartitionCount; i++) {
+      if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, CurSlot,
+                    StrLen (CurSlot))) {
+        PtnCurrent = &PtnEntries[i];
+      } else if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, NewSlot,
+                           StrLen (NewSlot))) {
+        PtnNew = &PtnEntries[i];
+      }
+    }
+    /* Swap the guids for the slots */
+    SwapPtnGuid (&PtnCurrent->PartEntry, &PtnNew->PartEntry);
+    PtnCurrent = PtnNew = NULL;
+  }
+
+  GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
+  if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
+    UfsGetSetBootLun (&UfsBootLun, UfsGet);
+    // Special case for XBL is to change the bootlun instead of swapping the
+    // guid
+    if (UfsBootLun == 0x1 &&
+        !StrnCmp (SetActive, (CONST CHAR16 *)L"_b",
+                  StrLen ((CONST CHAR16 *)L"_b"))) {
+      DEBUG ((EFI_D_INFO, "Switching the boot lun from 1 to 2\n"));
+      UfsBootLun = 0x2;
+    } else if (UfsBootLun == 0x2 &&
+               !StrnCmp (SetActive, (CONST CHAR16 *)L"_a",
+                         StrLen ((CONST CHAR16 *)L"_a"))) {
+      DEBUG ((EFI_D_INFO, "Switching the boot lun from 2 to 1\n"));
+      UfsBootLun = 0x1;
+    }
+    UfsGetSetBootLun (&UfsBootLun, UfsSet);
+  }
+
+  UpdatePartitionAttributes (PARTITION_GUID);
+}
+
+EFI_STATUS
+EnumeratePartitions (VOID)
+{
+  EFI_STATUS Status;
+  PartiSelectFilter HandleFilter;
+  UINT32 Attribs = 0;
+  UINT32 i;
+  // UFS LUN GUIDs
+  EFI_GUID LunGuids[] = {
+      gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid,
+      gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid,
+  };
+
+  gBS->SetMem ((VOID *)Ptable, (sizeof (struct StoragePartInfo) * MAX_LUNS), 0);
+
+  /* By default look for emmc partitions if not found look for UFS */
+  Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
+
+  Ptable[0].MaxHandles = ARRAY_SIZE (Ptable[0].HandleInfoList);
+  HandleFilter.PartitionType = NULL;
+  HandleFilter.VolumeName = NULL;
+  HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
+
+  Status =
+      GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0],
+                       &Ptable[0].MaxHandles);
+  if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
+    MaxLuns = 1;
+  }
+  /* If the media is not emmc then look for UFS */
+  else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) {
+    /* By default max 8 luns are supported but HW could be configured to use
+     * only few of them or all of them
+     * Based on the information read update the MaxLuns to reflect the max
+     * supported luns */
+    for (i = 0; i < MAX_LUNS; i++) {
+      Ptable[i].MaxHandles = ARRAY_SIZE (Ptable[i].HandleInfoList);
+      HandleFilter.PartitionType = NULL;
+      HandleFilter.VolumeName = NULL;
+      HandleFilter.RootDeviceType = &LunGuids[i];
+
+      Status =
+          GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0],
+                           &Ptable[i].MaxHandles);
+      /* If we fail to get block for a lun that means the lun is not configured
+       * and unsed, ignore the error
+       * and continue with the next Lun */
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR,
+                "Error getting block IO handle for %d lun, Lun may be unused\n",
+                i));
+        continue;
+      }
+    }
+    MaxLuns = i;
+  } else {
+    DEBUG ((EFI_D_ERROR, "Error populating block IO handles\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  return Status;
+}
+
+/*Function to provide has-slot info
+ *Pname: the partition name
+ *return: 1 or 0.
+ */
+BOOLEAN
+PartitionHasMultiSlot (CONST CHAR16 *Pname)
+{
+  UINT32 i;
+  UINT32 SlotCount = 0;
+  UINT32 Len = StrLen (Pname);
+
+  for (i = 0; i < PartitionCount; i++) {
+    if (!(StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname, Len))) {
+      if (PtnEntries[i].PartEntry.PartitionName[Len] == L'_' &&
+          (PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'a' ||
+           PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'b'))
+        if (++SlotCount > MIN_SLOTS) {
+          return TRUE;
+        }
+    }
+  }
+  return FALSE;
+}
+
+STATIC struct PartitionEntry *
+GetBootPartitionEntry (Slot *BootSlot)
+{
+  INT32 Index = INVALID_PTN;
+
+  if (StrnCmp ((CONST CHAR16 *)L"_a", BootSlot->Suffix,
+               StrLen (BootSlot->Suffix)) == 0) {
+    Index = GetPartitionIndex ((CHAR16 *)L"boot_a");
+  } else if (StrnCmp ((CONST CHAR16 *)L"_b", BootSlot->Suffix,
+                      StrLen (BootSlot->Suffix)) == 0) {
+    Index = GetPartitionIndex ((CHAR16 *)L"boot_b");
+  } else {
+    DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition "
+                         "entry for slot %s\n",
+            BootSlot->Suffix));
+    return NULL;
+  }
+
+  if (Index == INVALID_PTN) {
+    DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition entry "
+                         "for slot %s, invalid index\n",
+            BootSlot->Suffix));
+    return NULL;
+  }
+  return &PtnEntries[Index];
+}
+
+BOOLEAN IsSlotBootable (Slot *BootSlot)
+{
+  struct PartitionEntry *BootPartition = NULL;
+  BootPartition = GetBootPartitionEntry (BootSlot);
+  if (BootPartition == NULL) {
+    DEBUG ((EFI_D_ERROR, "IsCurrentSlotBootable: No boot partition "
+                         "entry for slot %s\n",
+            BootSlot->Suffix));
+    return FALSE;
+  }
+  DEBUG ((EFI_D_VERBOSE, "Slot suffix %s Part Attr 0x%lx\n", BootSlot->Suffix,
+          BootPartition->PartEntry.Attributes));
+
+  if (!(BootPartition->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) &&
+      BootPartition->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) {
+    DEBUG ((EFI_D_VERBOSE, "Slot %s is bootable\n", BootSlot->Suffix));
+    return TRUE;
+  }
+
+  DEBUG ((EFI_D_VERBOSE, "Slot %s is unbootable \n", BootSlot->Suffix));
+  return FALSE;
+}
+
+EFI_STATUS ClearUnbootable (Slot *BootSlot)
+{
+  struct PartitionEntry *BootEntry = NULL;
+  BootEntry = GetBootPartitionEntry (BootSlot);
+  if (BootEntry == NULL) {
+    DEBUG ((EFI_D_ERROR,
+            "ClearUnbootable: No boot partition entry for slot %s\n",
+            BootSlot->Suffix));
+    return EFI_NOT_FOUND;
+  }
+  BootEntry->PartEntry.Attributes &= ~PART_ATT_UNBOOTABLE_VAL;
+  BootEntry->PartEntry.Attributes |= PART_ATT_MAX_RETRY_COUNT_VAL;
+  UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
+  return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsSuffixEmpty (Slot *CheckSlot)
+{
+  if (CheckSlot == NULL) {
+    return TRUE;
+  }
+
+  if (StrLen (CheckSlot->Suffix) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+STATIC EFI_STATUS
+GetActiveSlot (Slot *ActiveSlot)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  Slot Slots[] = {{L"_a"}, {L"_b"}};
+  UINT64 Priority = 0;
+
+  if (ActiveSlot == NULL) {
+    DEBUG ((EFI_D_ERROR, "GetActiveSlot: bad parameter\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) {
+    struct PartitionEntry *BootPartition =
+        GetBootPartitionEntry (&Slots[SlotIndex]);
+    UINT64 BootPriority = 0;
+    if (BootPartition == NULL) {
+      DEBUG ((EFI_D_ERROR, "GetActiveSlot: No boot partition "
+                           "entry for slot %s\n",
+              Slots[SlotIndex].Suffix));
+      return EFI_NOT_FOUND;
+    }
+
+    BootPriority =
+        (BootPartition->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
+        PART_ATT_PRIORITY_BIT;
+
+    if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) &&
+        (BootPriority > Priority)) {
+      GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),
+                       Slots[SlotIndex].Suffix,
+                       StrLen (Slots[SlotIndex].Suffix)));
+      Priority = BootPriority;
+    }
+  }
+
+  DEBUG ((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n",
+          ActiveSlot->Suffix, Priority));
+
+  if (IsSuffixEmpty (ActiveSlot) == TRUE) {
+    /* Check for first boot and set default slot */
+    /* For First boot all A/B attributes for the slot would be 0 */
+    UINT64 BootPriority = 0;
+    UINT64 RetryCount = 0;
+    struct PartitionEntry *SlotA = GetBootPartitionEntry (&Slots[0]);
+    if (SlotA == NULL) {
+      DEBUG ((EFI_D_ERROR, "GetActiveSlot: First Boot: No boot partition "
+                           "entry for slot %s\n",
+              Slots[0].Suffix));
+      return EFI_NOT_FOUND;
+    }
+
+    BootPriority = (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
+                   PART_ATT_PRIORITY_BIT;
+    RetryCount = (SlotA->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>
+                 PART_ATT_MAX_RETRY_CNT_BIT;
+
+    if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 &&
+        (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 &&
+        (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 &&
+        BootPriority == 0) {
+
+      DEBUG ((EFI_D_INFO, "GetActiveSlot: First boot: set "
+                          "default slot _a\n"));
+      SlotA->PartEntry.Attributes &=
+          (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
+      SlotA->PartEntry.Attributes |=
+          (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
+           PART_ATT_MAX_RETRY_COUNT_VAL);
+
+      GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),
+                       Slots[0].Suffix, StrLen (Slots[0].Suffix)));
+      UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
+      return EFI_SUCCESS;
+    }
+
+    DEBUG ((EFI_D_ERROR, "GetActiveSlot: No active slot found\n"));
+    DEBUG ((EFI_D_ERROR, "GetActiveSlot: Slot attr: Priority %ld, Retry "
+                         "%ld, Active %ld, Success %ld, unboot %ld\n",
+            BootPriority, RetryCount,
+            (SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >>
+                PART_ATT_ACTIVE_BIT,
+            (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL),
+            (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL)));
+
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetActiveSlot (Slot *NewSlot, BOOLEAN ResetSuccessBit, BOOLEAN SetSuccessBit)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  Slot CurrentSlot = {{0}};
+  Slot *AlternateSlot = NULL;
+  Slot Slots[] = {{L"_a"}, {L"_b"}};
+  BOOLEAN UfsGet = TRUE;
+  BOOLEAN UfsSet = FALSE;
+  UINT32 UfsBootLun = 0;
+  CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
+  struct PartitionEntry *BootEntry = NULL;
+
+  if (NewSlot == NULL) {
+    DEBUG ((EFI_D_ERROR, "SetActiveSlot: input parameter invalid\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GUARD (GetActiveSlot (&CurrentSlot));
+
+  if (StrnCmp (NewSlot->Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == 0) {
+    AlternateSlot = &Slots[1];
+  } else {
+    AlternateSlot = &Slots[0];
+  }
+
+  BootEntry = GetBootPartitionEntry (NewSlot);
+  if (BootEntry == NULL) {
+    DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n",
+            NewSlot->Suffix));
+    return EFI_NOT_FOUND;
+  }
+
+  BootEntry->PartEntry.Attributes |=
+      (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
+       PART_ATT_MAX_RETRY_COUNT_VAL);
+
+  BootEntry->PartEntry.Attributes &= (~PART_ATT_UNBOOTABLE_VAL);
+
+  if (ResetSuccessBit &&
+      (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL)) {
+    BootEntry->PartEntry.Attributes &= (~PART_ATT_SUCCESSFUL_VAL);
+  }
+
+  if (SetSuccessBit &&
+      ((BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0)) {
+    BootEntry->PartEntry.Attributes |= PART_ATT_SUCCESSFUL_VAL;
+  }
+
+  /* Reduce the priority and clear the active flag for alternate slot*/
+  BootEntry = GetBootPartitionEntry (AlternateSlot);
+  if (BootEntry == NULL) {
+    DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n",
+            AlternateSlot->Suffix));
+    return EFI_NOT_FOUND;
+  }
+
+  BootEntry->PartEntry.Attributes &=
+      (~PART_ATT_PRIORITY_VAL & ~PART_ATT_ACTIVE_VAL);
+  BootEntry->PartEntry.Attributes |=
+      (((UINT64)MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT);
+
+  UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
+  if (StrnCmp (CurrentSlot.Suffix, NewSlot->Suffix,
+               StrLen (CurrentSlot.Suffix)) == 0) {
+    DEBUG ((EFI_D_INFO, "SetActiveSlot: %s already active slot\n",
+            NewSlot->Suffix));
+
+    /* Check if BootLun is matching with Slot */
+    GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
+    if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
+      UfsGetSetBootLun (&UfsBootLun, UfsGet);
+      if (UfsBootLun == 0x1 &&
+          !StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_b",
+          StrLen ((CONST CHAR16 *)L"_b"))) {
+        DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 1 to 2\n"));
+        DEBUG ((EFI_D_INFO, "Reboot Required\n"));
+        UfsBootLun = 0x2;
+        UfsGetSetBootLun (&UfsBootLun, UfsSet);
+      } else if (UfsBootLun == 0x2 &&
+               !StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_a",
+               StrLen ((CONST CHAR16 *)L"_a"))) {
+        DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 2 to 1\n"));
+        DEBUG ((EFI_D_INFO, "Reboot Required\n"));
+        UfsBootLun = 0x1;
+        UfsGetSetBootLun (&UfsBootLun, UfsSet);
+      }
+    }
+  } else {
+    DEBUG ((EFI_D_INFO, "Alternate slot %s, New slot %s\n",
+            AlternateSlot->Suffix, NewSlot->Suffix));
+    SwitchPtnSlots (NewSlot->Suffix);
+    MarkPtnActive (NewSlot->Suffix);
+  }
+  return EFI_SUCCESS;
+}
\ No newline at end of file
diff --git a/sdm845Pkg/Library/BootSlotLib/StorageUtils.c b/sdm845Pkg/Library/BootSlotLib/StorageUtils.c
new file mode 100644 (file)
index 0000000..5c9e3c5
--- /dev/null
@@ -0,0 +1,201 @@
+/* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "AutoGen.h"
+
+#include <Library/BootSlotLib/StorageUtils.h>
+#include <Library/BootSlotLib/BlockIoUtils.h>
+
+STATIC CONST CHAR8 *DeviceType[] = {
+        [EMMC] = "EMMC", [UFS] = "UFS", [UNKNOWN] = "Unknown",
+};
+
+/**
+ Device Handler Info
+
+ @param[out]     HndlInfo  : Pointer to array of HandleInfo structures
+                               in which the output is returned.
+ @param[in, out] MaxHandles  : On input, max number of handle structures
+                               the buffer can hold, On output, the number
+                               of handle structures returned.
+ @param[in]      Type        : Device Type : UNKNOWN, UFS, EMMC, NAND
+ @retval         EFI_STATUS  : Return Success on getting Handler Info
+ **/
+
+STATIC EFI_STATUS
+GetDeviceHandleInfo (VOID *HndlInfo, UINT32 MaxHandles, MemCardType Type)
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  UINT32 Attribs = 0;
+  PartiSelectFilter HandleFilter;
+  HandleInfo *HandleInfoList = HndlInfo;
+
+  Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
+  HandleFilter.PartitionType = NULL;
+  HandleFilter.VolumeName = NULL;
+
+  switch (Type) {
+  case UFS:
+    HandleFilter.RootDeviceType = &gEfiUfsLU0Guid;
+    break;
+  case EMMC:
+    HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
+    break;
+  case UNKNOWN:
+    DEBUG ((EFI_D_ERROR, "Device type unknown\n"));
+    return Status;
+  }
+
+  Status =
+     GetBlkIOHandles (Attribs, &HandleFilter, HandleInfoList, &MaxHandles);
+  if (EFI_ERROR (Status) ||
+     MaxHandles == 0) {
+    DEBUG ((EFI_D_ERROR, "Get BlkIohandles failed\n"));
+    return Status;
+  }
+  return Status;
+}
+
+/**
+ Return a device type
+ @retval         Device type : UNKNOWN | UFS | EMMC | NAND
+ **/
+STATIC UINT32
+GetCompatibleRootDeviceType (VOID)
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  HandleInfo HandleInfoList[HANDLE_MAX_INFO_LIST];
+  UINT32 MaxHandles = ARRAY_SIZE (HandleInfoList);
+  UINT32 Index;
+
+  for (Index = 0; Index < UNKNOWN; Index++) {
+    Status = GetDeviceHandleInfo (HandleInfoList, MaxHandles, Index);
+    if (Status == EFI_SUCCESS) {
+      return Index;
+    }
+  }
+
+  return Index;
+}
+
+/**
+ Return a device type
+ @retval         Device type : UNKNOWN | UFS | EMMC, default is UNKNOWN
+ **/
+
+MemCardType
+CheckRootDeviceType (VOID)
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  STATIC MemCardType Type = UNKNOWN;
+  MEM_CARD_INFO CardInfoData;
+  EFI_MEM_CARDINFO_PROTOCOL *CardInfo;
+
+  if (Type == UNKNOWN) {
+    Status = gBS->LocateProtocol (&gEfiMemCardInfoProtocolGuid, NULL,
+                                  (VOID **)&CardInfo);
+    if (!EFI_ERROR (Status)) {
+
+      Status = CardInfo->GetCardInfo (CardInfo, &CardInfoData);
+
+      if (!EFI_ERROR (Status)) {
+
+        if (!AsciiStrnCmp ((CHAR8 *)CardInfoData.card_type, "UFS",
+                           AsciiStrLen ("UFS"))) {
+          Type = UFS;
+        } else if (!AsciiStrnCmp ((CHAR8 *)CardInfoData.card_type, "EMMC",
+                                  AsciiStrLen ("EMMC"))) {
+          Type = EMMC;
+        } else {
+          Type = GetCompatibleRootDeviceType ();
+        }
+      }
+    }
+  }
+  return Type;
+}
+
+/**
+ Get device type
+ @param[out]  StrDeviceType  : Pointer to array of device type string.
+ @param[in]   Len            : The size of the device type string
+ **/
+VOID
+GetRootDeviceType (CHAR8 *StrDeviceType, UINT32 Len)
+{
+  UINT32 Type;
+
+  Type = CheckRootDeviceType ();
+  AsciiSPrint (StrDeviceType, Len, "%a", DeviceType[Type]);
+}
+
+EFI_STATUS
+UfsGetSetBootLun (UINT32 *UfsBootlun, BOOLEAN IsGet)
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  EFI_MEM_CARDINFO_PROTOCOL *CardInfo;
+  HandleInfo HandleInfoList[MAX_HANDLE_INFO_LIST];
+  UINT32 Attribs = 0;
+  UINT32 MaxHandles;
+  PartiSelectFilter HandleFilter;
+
+  Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
+  MaxHandles = ARRAY_SIZE (HandleInfoList);
+  HandleFilter.PartitionType = NULL;
+  HandleFilter.VolumeName = NULL;
+  HandleFilter.RootDeviceType = &gEfiUfsLU0Guid;
+
+  Status =
+      GetBlkIOHandles (Attribs, &HandleFilter, HandleInfoList, &MaxHandles);
+  if (EFI_ERROR (Status))
+    return EFI_NOT_FOUND;
+
+  Status =
+      gBS->HandleProtocol (HandleInfoList[0].Handle,
+                           &gEfiMemCardInfoProtocolGuid, (VOID **)&CardInfo);
+
+  if (Status != EFI_SUCCESS) {
+    DEBUG ((EFI_D_ERROR, "Error locating MemCardInfoProtocol:%x\n", Status));
+    return Status;
+  }
+
+  if (CardInfo->Revision < EFI_MEM_CARD_INFO_PROTOCOL_REVISION) {
+    DEBUG ((EFI_D_ERROR, "This API not supported in Revision =%u\n",
+            CardInfo->Revision));
+    return EFI_NOT_FOUND;
+  }
+
+  if (IsGet == TRUE) {
+    if (CardInfo->GetBootLU (CardInfo, UfsBootlun) == EFI_SUCCESS)
+      DEBUG ((EFI_D_VERBOSE, "Get BootLun =%u\n", *UfsBootlun));
+  } else {
+    if (CardInfo->SetBootLU (CardInfo, *UfsBootlun) == EFI_SUCCESS)
+      DEBUG ((EFI_D_VERBOSE, "SetBootLun =%u\n", *UfsBootlun));
+  }
+  return Status;
+}
\ No newline at end of file
index 318456f127929c247853aa61cfb6e96f8b80b304..4b18d2d0f2cc77125331d3c789cb35ee37b2b7b4 100644 (file)
@@ -754,6 +754,15 @@ PlatformBootManagerAfterConsole (
   PlatformRegisterFvBootOption (
   &gUsbfnMsdAppFileGuid, L"Mass Storage", LOAD_OPTION_ACTIVE
   );
+   
+#ifdef AB_SLOTS_SUPPORT
+  //
+  // Register Switch Slots App
+  //
+  PlatformRegisterFvBootOption (
+  &gSwitchSlotsAppFileGuid, L"Reboot to other slot", LOAD_OPTION_ACTIVE
+  );
+#endif
 }
 
 /**
index ed079639059adabb8e3ea26dca9901729fffeb79..3a284b2072b4b697b48b5f58d65c75f74abd59aa 100644 (file)
@@ -78,6 +78,7 @@
   gEfiTtyTermGuid
   gUefiShellFileGuid
   gUsbfnMsdAppFileGuid
+  gSwitchSlotsAppFileGuid
 
 [Protocols]
   gEdkiiNonDiscoverableDeviceProtocolGuid
index 2dc23cf7eeae793e717fa24c7c2b2f4b778ec800..7cf85626f7bffb017c290875edfe36f4e2af04c6 100644 (file)
 
 [Guids.common]
   gsdm845PkgTokenSpaceGuid        = { 0x99a14446, 0xaad7, 0xe460, {0xb4, 0xe5, 0x1f, 0x79, 0xaa, 0xa4, 0x93, 0xfd } }
+  gEfiEmmcUserPartitionGuid       = { 0xb615f1f5, 0x5088, 0x43cd, { 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 } }
+  gEfiUfsLU0Guid                  = { 0x860845c1, 0xbe09, 0x4355, { 0x8b, 0xc1, 0x30, 0xd6, 0x4f, 0xf8, 0xe6, 0x3a } }
+  gEfiUfsLU1Guid                  = { 0x8d90d477, 0x39a3, 0x4a38, { 0xab, 0x9e, 0x58, 0x6f, 0xf6, 0x9e, 0xd0, 0x51 } }
+  gEfiUfsLU2Guid                  = { 0xedf85868, 0x87ec, 0x4f77, { 0x9c, 0xda, 0x5f, 0x10, 0xdf, 0x2f, 0xe6, 0x01 } }
+  gEfiUfsLU3Guid                  = { 0x1ae69024, 0x8aeb, 0x4df8, { 0xbc, 0x98, 0x00, 0x32, 0xdb, 0xdf, 0x50, 0x24 } }
+  gEfiUfsLU4Guid                  = { 0xd33f1985, 0xf107, 0x4a85, { 0xbe, 0x38, 0x68, 0xdc, 0x7a, 0xd3, 0x2c, 0xea } }
+  gEfiUfsLU5Guid                  = { 0x4ba1d05f, 0x088e, 0x483f, { 0xa9, 0x7e, 0xb1, 0x9b, 0x9c, 0xcf, 0x59, 0xb0 } }
+  gEfiUfsLU6Guid                  = { 0x4acf98f6, 0x26fa, 0x44d2, { 0x81, 0x32, 0x28, 0x2f, 0x2d, 0x19, 0xa4, 0xc5 } }
+  gEfiUfsLU7Guid                  = { 0x8598155f, 0x34de, 0x415c, { 0x8b, 0x55, 0x84, 0x3e, 0x33, 0x22, 0xd3, 0x6f } }
 
 [Protocols]
   gEFIDroidKeypadDeviceProtocolGuid = { 0xb27625b5, 0x0b6c, 0x4614, { 0xaa, 0x3c, 0x33, 0x13, 0xb5, 0x1d, 0x36, 0x46 } }
+  gEfiMemCardInfoProtocolGuid       = { 0x85c1f7d2, 0xbce6, 0x4f31, { 0x8f, 0x4d, 0xd3, 0x7e, 0x03, 0xd0, 0x5e, 0xaa } }
 
 [Guids]
-gUsbfnMsdAppFileGuid                = { 0x1C207232, 0x4086, 0x9BE7, { 0xDB, 0x16, 0x15, 0x9D, 0x66, 0xAB, 0x46, 0x6A } }
+  gUsbfnMsdAppFileGuid                = { 0x1C207232, 0x4086, 0x9BE7, { 0xDB, 0x16, 0x15, 0x9D, 0x66, 0xAB, 0x46, 0x6A } }
+  gSwitchSlotsAppFileGuid             = { 0xD5BC0FB1, 0xA833, 0x4607, { 0xB7, 0xB6, 0x5E, 0xF9, 0xD1, 0x0B, 0xEE, 0xB7 } }
 
 [PcdsFixedAtBuild.common]
   # Simple FrameBuffer
index 2a21a9236d154ba1bfca5b2656ca19a45af52258..0ac826de9d99f86763d540b1c51cbd6b6fbd85d6 100644 (file)
   MemoryInitPeiLib|sdm845Pkg/Library/MemoryInitPeiLib/PeiMemoryAllocationLib.inf
   PlatformPeiLib|sdm845Pkg/Library/PlatformPeiLib/PlatformPeiLib.inf
 
+!ifdef $(AB_SLOTS_SUPPORT)
+  BootSlotLib|sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf
+!endif #$(AB_SLOTS_SUPPORT)
+
 [LibraryClasses.common.SEC]
   PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
   ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
   
   #
   # OnePlus 6T A/B Slot Support
+  # Op6tSlotDxe and BootSlotDxe have the same goal, do not use them both at the same time in device fdf.
   #
   sdm845Pkg/Drivers/Op6tSlotDxe/Op6tSlotDxe.inf
+  sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
+  sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
   
   #
   # Bds