From 7597ee34c5e935d02930d3756f6f114703ebf53e Mon Sep 17 00:00:00 2001 From: Caramel Date: Mon, 30 Aug 2021 17:12:05 +0300 Subject: [PATCH] Better Slot Handling + Slot Switch from EDK2 --- .../SwitchSlotsApp/SwitchSlotsApp.c | 82 ++ .../SwitchSlotsApp/SwitchSlotsApp.inf | 37 + sdm845Pkg/Devices/fajita-8g.dsc | 5 +- sdm845Pkg/Devices/fajita.dsc | 6 + sdm845Pkg/Devices/fajita.fdf | 8 +- sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c | 75 ++ sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf | 40 + sdm845Pkg/Include/Library/BootSlotLib.h | 26 + .../Library/BootSlotLib/BlockIoUtils.h | 130 +++ .../Include/Library/BootSlotLib/EFICardInfo.h | 168 ++++ .../Include/Library/BootSlotLib/EFIUtils.h | 29 + .../BootSlotLib/PartitionTableUpdate.h | 209 ++++ .../Library/BootSlotLib/StorageUtils.h | 55 ++ sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c | 361 +++++++ sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf | 68 ++ sdm845Pkg/Library/BootSlotLib/EFIUtils.c | 32 + .../BootSlotLib/PartitionTableUpdate.c | 926 ++++++++++++++++++ sdm845Pkg/Library/BootSlotLib/StorageUtils.c | 201 ++++ .../PlatformBootManagerLib/PlatformBm.c | 9 + .../PlatformBootManagerLib.inf | 1 + sdm845Pkg/sdm845Pkg.dec | 13 +- sdm845Pkg/sdm845Pkg.dsc | 7 + 22 files changed, 2485 insertions(+), 3 deletions(-) create mode 100644 sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c create mode 100644 sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf create mode 100644 sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c create mode 100644 sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf create mode 100644 sdm845Pkg/Include/Library/BootSlotLib.h create mode 100644 sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h create mode 100644 sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h create mode 100644 sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h create mode 100644 sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h create mode 100644 sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h create mode 100644 sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c create mode 100644 sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf create mode 100644 sdm845Pkg/Library/BootSlotLib/EFIUtils.c create mode 100644 sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c create mode 100644 sdm845Pkg/Library/BootSlotLib/StorageUtils.c diff --git a/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c b/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c new file mode 100644 index 0000000..3ebbc06 --- /dev/null +++ b/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c @@ -0,0 +1,82 @@ +/* + * SwitchSlotsApp Module + * Copyright (C) 2021 Renard Gold + * + * 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 +#include + +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 index 0000000..26544f0 --- /dev/null +++ b/sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf @@ -0,0 +1,37 @@ +# SwitchSlotsApp Application +# Copyright (C) 2021 Renard Gold + +# 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 + * + * 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 +#include +#include + +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 index 0000000..8e4de27 --- /dev/null +++ b/sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf @@ -0,0 +1,40 @@ +# BootSlot DXE DRIVER +# Copyright (C) 2021 Renard Gold + +# 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 + * + * 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 +#include +#include + +#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 index 0000000..772a9fe --- /dev/null +++ b/sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 index 0000000..95b87a3 --- /dev/null +++ b/sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h @@ -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 index 0000000..5f5e8c1 --- /dev/null +++ b/sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h @@ -0,0 +1,29 @@ + +/* + * SwitchSlotsApp Module + * Copyright (C) 2021 Renard Gold + * + * 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 + +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 index 0000000..8ab08c1 --- /dev/null +++ b/sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h @@ -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 + +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 index 0000000..11597f2 --- /dev/null +++ b/sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h @@ -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 +#include +#include +#include +#include +#include +#include + +#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 index 0000000..069e09d --- /dev/null +++ b/sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c @@ -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 +#include +#include + +/* 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 index 0000000..d47c143 --- /dev/null +++ b/sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf @@ -0,0 +1,68 @@ +# /* +# * BootSlot Library +# * Copyright (C) 2021 Renard Gold +# * +# * 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 + * + * 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 +#include + +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 index 0000000..9176a7d --- /dev/null +++ b/sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c @@ -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 +#include +#include +#include +#include + +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 index 0000000..5c9e3c5 --- /dev/null +++ b/sdm845Pkg/Library/BootSlotLib/StorageUtils.c @@ -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 +#include + +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 diff --git a/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBm.c b/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBm.c index 318456f..4b18d2d 100644 --- a/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBm.c +++ b/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBm.c @@ -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 } /** diff --git a/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index ed07963..3a284b2 100644 --- a/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/sdm845Pkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -78,6 +78,7 @@ gEfiTtyTermGuid gUefiShellFileGuid gUsbfnMsdAppFileGuid + gSwitchSlotsAppFileGuid [Protocols] gEdkiiNonDiscoverableDeviceProtocolGuid diff --git a/sdm845Pkg/sdm845Pkg.dec b/sdm845Pkg/sdm845Pkg.dec index 2dc23cf..7cf8562 100644 --- a/sdm845Pkg/sdm845Pkg.dec +++ b/sdm845Pkg/sdm845Pkg.dec @@ -30,12 +30,23 @@ [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 diff --git a/sdm845Pkg/sdm845Pkg.dsc b/sdm845Pkg/sdm845Pkg.dsc index 2a21a92..0ac826d 100644 --- a/sdm845Pkg/sdm845Pkg.dsc +++ b/sdm845Pkg/sdm845Pkg.dsc @@ -69,6 +69,10 @@ 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 @@ -259,8 +263,11 @@ # # 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