--- /dev/null
+/*
+ * 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
--- /dev/null
+# 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
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)
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
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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__ */
--- /dev/null
+
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+# /*
+# * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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
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
}
/**
gEfiTtyTermGuid
gUefiShellFileGuid
gUsbfnMsdAppFileGuid
+ gSwitchSlotsAppFileGuid
[Protocols]
gEdkiiNonDiscoverableDeviceProtocolGuid
[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
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