Better Slot Handling + Slot Switch from EDK2

This commit is contained in:
Caramel 2021-08-30 17:12:05 +03:00
parent 713bb23f06
commit 7597ee34c5
22 changed files with 2485 additions and 3 deletions

View File

@ -0,0 +1,82 @@
/*
* SwitchSlotsApp Module
* Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/
*/
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/BootSlotLib.h>
EFI_STATUS
EFIAPI
SwitchSlotsAppEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
MemCardType Type = CheckRootDeviceType();
if (Type == UNKNOWN) {
PrintAndWaitAnyKey(SystemTable, L"Unknown device storage. Press any key to exit.\n");
return EFI_UNSUPPORTED;
}
EFI_STATUS Status = EnumeratePartitions();
if (EFI_ERROR (Status)) {
Print (L"Could not enumerate partitions. Code %d\n", Status);
WaitAnyKey(SystemTable);
return Status;
}
UpdatePartitionEntries();
/*Check for multislot boot support*/
BOOLEAN MultiSlotSupported = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
if (!MultiSlotSupported) {
PrintAndWaitAnyKey(SystemTable, L"A/B slots aren't supported on this device. Press any key to exit.\n");
return EFI_UNSUPPORTED;
}
Slot CurrentSlot = GetCurrentSlotSuffix();
if (IsSuffixEmpty(&CurrentSlot)) {
PrintAndWaitAnyKey(SystemTable, L"Current active slot not found, try to boot Android first. Press any key to exit.\n");
return EFI_NOT_READY;
}
Slot *NewSlot = NULL;
Slot Slots[] = {{L"_a"}, {L"_b"}};
if (StrnCmp (CurrentSlot.Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == 0) {
NewSlot = &Slots[1];
} else {
NewSlot = &Slots[0];
}
//Print (L"Current active slot suffix is: %s, next slot suffix is: %s\n", &CurrentSlot.Suffix, &NewSlot->Suffix);
Status = SetActiveSlot(NewSlot, TRUE, FALSE);
if (EFI_ERROR(Status)) {
Print (L"Could not update active slot. Code %d\n", Status);
WaitAnyKey(SystemTable);
return Status;
}
//Print (L"Current active slot has been updated successfully! Press any key to reboot.\n");
//WaitAnyKey(SystemTable);
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
CpuDeadLoop ();
return EFI_SUCCESS;
}

View File

@ -0,0 +1,37 @@
# SwitchSlotsApp Application
# Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/
[Defines]
INF_VERSION = 0x00010019
BASE_NAME = SwitchSlotsApp
FILE_GUID = D5BC0FB1-A833-4607-B7B6-5EF9D10BEEB7
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = SwitchSlotsAppEntryPoint
[Sources.common]
SwitchSlotsApp.c
[LibraryClasses]
UefiLib
UefiApplicationEntryPoint
BootSlotLib
[Packages]
MdePkg/MdePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
sdm845Pkg/sdm845Pkg.dec

View File

@ -9,10 +9,13 @@
SKUID_IDENTIFIER = DEFAULT
FLASH_DEFINITION = sdm845Pkg/Devices/fajita.fdf
# Enable A/B Slot Environment
DEFINE AB_SLOTS_SUPPORT = TRUE
!include sdm845Pkg/sdm845Pkg.dsc
[BuildOptions.common]
GCC:*_*_AARCH64_CC_FLAGS = -DMEMORY_8G=1
GCC:*_*_AARCH64_CC_FLAGS = -DMEMORY_8G=1 -DAB_SLOTS_SUPPORT=1
[PcdsFixedAtBuild.common]
# System Memory (7GB)

View File

@ -9,8 +9,14 @@
SKUID_IDENTIFIER = DEFAULT
FLASH_DEFINITION = sdm845Pkg/Devices/fajita.fdf
# Enable A/B Slot Environment
DEFINE AB_SLOTS_SUPPORT = TRUE
!include sdm845Pkg/sdm845Pkg.dsc
[BuildOptions.common]
GCC:*_*_AARCH64_CC_FLAGS = -DAB_SLOTS_SUPPORT=1
[PcdsFixedAtBuild.common]
# System Memory (5GB)
gArmTokenSpaceGuid.PcdSystemMemorySize|0x15AE00000

View File

@ -580,11 +580,17 @@ APRIORI DXE {
INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
INF MdeModulePkg/Application/UiApp/UiApp.inf
INF sdm845Pkg/Drivers/LogoDxe/LogoDxe.inf
#
# OnePlus 6(T) A/B Slot Support
#
!ifdef $(AB_SLOTS_SUPPORT)
INF sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
INF sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
!else
# Old unstable solution
INF sdm845Pkg/Drivers/Op6tSlotDxe/Op6tSlotDxe.inf
!endif #$(AB_SLOTS_SUPPORT)
[FV.FVMAIN_COMPACT]
FvAlignment = 8

View File

@ -0,0 +1,75 @@
/*
* BootSlot DXE Driver
* Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/
*/
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/BootSlotLib.h>
EFI_STATUS
EFIAPI
BootSlotMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
) {
MemCardType Type = CheckRootDeviceType();
if (Type == UNKNOWN) {
DEBUG ((EFI_D_ERROR, "Device storage is not supported \n"));
return EFI_SUCCESS;
}
EFI_STATUS Status = EnumeratePartitions();
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Could not enumerate partitions. Code %d\n", Status));
return Status;
}
UpdatePartitionEntries();
/*Check for multislot boot support*/
BOOLEAN MultiSlotSupported = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
if (!MultiSlotSupported) {
DEBUG ((EFI_D_ERROR, "A/B slots aren't supported on this device. Press any key to exit.\n"));
return EFI_SUCCESS;
}
Slot Slots[] = {{L"_a"}, {L"_b"}};
Slot CurrentSlot = GetCurrentSlotSuffix();
if (IsSuffixEmpty(&CurrentSlot)) {
CurrentSlot = Slots[0]; // Set A as active if there is no slot available (shouldn't happen though)
}
// Clear all unbootable bits if exists
for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) {
Slot *SlotEntry = &Slots[SlotIndex];
if (!IsSlotBootable(SlotEntry)) {
ClearUnbootable(SlotEntry);
}
}
// Set current slot as active again just refresh its attributes + mark it successful
Status = SetActiveSlot(&CurrentSlot, FALSE, TRUE);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "Could not update active slot. Code %d\n", Status));
return Status;
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,40 @@
# BootSlot DXE DRIVER
# Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/
[Defines]
INF_VERSION = 0x0010005
BASE_NAME = BootSlotDxe
FILE_GUID = BA325AC5-10AB-44E3-B6C1-5BD273A3BF2D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = BootSlotMain
[Sources.common]
BootSlotDxe.c
[LibraryClasses]
UefiLib
UefiDriverEntryPoint
BootSlotLib
[Packages]
MdePkg/MdePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
sdm845Pkg/sdm845Pkg.dec
[Depex]
TRUE

View File

@ -0,0 +1,26 @@
/*
* BootSlot Library
* Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/
*/
#ifndef __BOOT_SLOT_LIB_BASE_H__
#define __BOOT_SLOT_LIB_BASE_H__
#include <Library/BootSlotLib/EFIUtils.h>
#include <Library/BootSlotLib/PartitionTableUpdate.h>
#include <Library/BootSlotLib/StorageUtils.h>
#endif

View File

@ -0,0 +1,130 @@
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BSL_BLOCK_UTILS_H__
#define __BSL_BLOCK_UTILS_H__
#include <Uefi.h>
#include <Guid/FileSystemInfo.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/BlockIo.h>
#include <Protocol/SimpleFileSystem.h>
/* Selection attributes for selecting the BlkIo handles */
#define BLK_IO_SEL_MEDIA_TYPE_REMOVABLE 0x0001
#define BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE 0x0002
#define BLK_IO_SEL_PARTITIONED_GPT 0x0004
#define BLK_IO_SEL_PARTITIONED_MBR 0x0008
#define BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID 0x0010
#define BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM 0x0020
#define BLK_IO_SEL_SELECT_BY_VOLUME_NAME 0x0040
/* Select only the root device handle indicated. Doesn't return
* any partitions within.
* Currently this filter applies only for eMMC device, not the external
* device connected via USB */
#define BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY 0x0080
/* Select the handle that's on the indicated root device.
* Currently this filter applies only for eMMC device, not the external
* device connected via USB */
#define BLK_IO_SEL_MATCH_ROOT_DEVICE 0x0100
/* Select through partition name*/
#define BLK_IO_SEL_MATCH_PARTITION_LABEL 0x0200
/* Do case insensetive string comparisons */
#define BLK_IO_SEL_STRING_CASE_INSENSITIVE 0x0400
/* Partitioning scheme types for selecting the BlkIo handles */
#define PARTITIONED_TYPE_MBR 0x01
#define PARTITIONED_TYPE_GPT 0x02
#define MAX_HANDLE_INFO_LIST 128
#define BOOT_DEV_NAME_SIZE_MAX 10
/* Output data providing more information about the device handle */
typedef struct {
/* Handle that has BlkIO protocol installed, returned for all type of filters
*/
EFI_HANDLE *Handle;
/* Block IO protocol interface is returned for all type of filters */
EFI_BLOCK_IO_PROTOCOL *BlkIo;
/* This HDD dev path is returned only if Matching Partition type is requested
* It should be noted that the contents of this memory should NOT be changed
*/
const HARDDRIVE_DEVICE_PATH *PartitionInfo;
} HandleInfo;
/* Return True if integer overflow will occur */
#define CHECK_ADD64(a, b) ((MAX_UINT64 - b < a) ? TRUE : FALSE)
/* Any data specific to additional attributes can be added here. */
typedef struct {
EFI_GUID *RootDeviceType; /* GUID Selecting the root device type */
EFI_GUID *PartitionType; /* Partition Type to match */
CHAR8 *VolumeName; /* Mounted filesystem volume name to match */
CHAR16 *PartitionLabel; /* Partition label to match */
} PartiSelectFilter;
EFI_STATUS
EFIAPI
GetPartitionEntry (IN EFI_HANDLE Handle,
OUT EFI_PARTITION_ENTRY **PartEntry);
/**
Returns a list of BlkIo handles based on required criteria
SelectionAttrib : Bitmask representing the conditions that need
to be met for the handles returned. Based on the
selections filter members should have valid values.
FilterData : Instance of Partition Select Filter structure that
needs extended data for certain type flags. For example
Partition type and/or Volume name can be specified.
HandleInfoPtr : Pointer Handle info where the information can be returned
MaxBlkIopCnt : On input, max number of handles the buffer can hold,
On output, the number of handles returned.
@retval EFI_SUCCESS if the operation was successful
*/
EFI_STATUS
EFIAPI
GetBlkIOHandles (IN UINT32 SelectionAttrib,
IN PartiSelectFilter *FilterData,
OUT HandleInfo *HandleInfoPtr,
IN OUT UINT32 *MaxBlkIopCnt);
#endif

View File

@ -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__ */

View File

@ -0,0 +1,29 @@
/*
* SwitchSlotsApp Module
* Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/
*/
#ifndef __BSL_EFIUTILS_H__
#define __BSL_EFIUTILS_H__
#include <Uefi.h>
void WaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable);
void PrintAndWaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable, CHAR16 *Message);
#endif

View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of The Linux Foundation nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __BSL_PARTITION_TABLE_H__
#define __BSL_PARTITION_TABLE_H__
#include <Library/BootSlotLib/BlockIoUtils.h>
enum ReturnVal {
SUCCESS = 0,
FAILURE,
};
typedef enum {
PARTITION_ATTRIBUTES = 1,
PARTITION_GUID,
PARTITION_ALL,
} UPDATE_TYPE;
typedef enum {
PTN_ENTRIES_TO_MISC = 1,
PTN_ENTRIES_FROM_MISC,
} NANDAB_UPDATE_TYPE;
#define NANDAB_MAX_SLOTNAME_LEN 7
#define PARTITION_ATTRIBUTES_MASK 0x1
#define PARTITION_GUID_MASK 0x2
#define MAX_HANDLEINF_LST_SIZE 128
#define PARTITION_TYPE_MBR 0
#define PARTITION_TYPE_GPT 1
#define PARTITION_TYPE_GPT_BACKUP 2
#define GPT_PROTECTIVE 0xEE
#define MBR_PARTITION_RECORD 446
#define OS_TYPE 4
#define MBR_SIGNATURE 510
#define MBR_SIGNATURE_BYTE_0 0x55
#define MBR_SIGNATURE_BYTE_1 0xAA
#define MIBIB_MAGIC1 0xFE569FAC
#define MIBIB_MAGIC2 0xCD7F127A
/* GPT Signature should be 0x5452415020494645 */
#define GPT_SIGNATURE_1 0x54524150
#define GPT_SIGNATURE_2 0x20494645
#define GPT_HEADER_SIZE 92
#define GPT_LBA 1
#define GPT_PART_ENTRY_SIZE 128
#define MAX_GPT_NAME_SIZE 72
/* GPT Offsets */
#define HEADER_SIZE_OFFSET 12
#define HEADER_CRC_OFFSET 16
#define PRIMARY_HEADER_OFFSET 24
#define BACKUP_HEADER_OFFSET 32
#define FIRST_USABLE_LBA_OFFSET 40
#define LAST_USABLE_LBA_OFFSET 48
#define PARTITION_ENTRIES_OFFSET 72
#define PARTITION_COUNT_OFFSET 80
#define PENTRY_SIZE_OFFSET 84
#define PARTITION_CRC_OFFSET 88
#define PARTITION_ENTRY_LAST_LBA 40
#define PARTITION_TYPE_GUID_SIZE 4
#define UNIQUE_PARTITION_GUID_SIZE 16
#define PARTITION_ENTRY_SIZE 128
#define PART_ATT_READONLY_OFFSET 60
/*
The attributes like Priority, Active bit,
Max retry count, Success bit and Unabootable bits will be
stored in attributes filed of the each partition in partition
table in the respective position mentioned below.
*/
/* Partition Attribute fields*/
#define PART_ATT_PRIORITY_BIT 48
#define PART_ATT_ACTIVE_BIT 50
#define PART_ATT_MAX_RETRY_CNT_BIT 51
#define PART_ATT_SUCCESS_BIT 54
#define PART_ATT_UNBOOTABLE_BIT 55
#define PART_ATT_PRIORITY_VAL ((UINT64)0x3 << PART_ATT_PRIORITY_BIT)
#define PART_ATT_ACTIVE_VAL ((UINT64)0x1 << PART_ATT_ACTIVE_BIT)
#define PART_ATT_MAX_RETRY_COUNT_VAL ((UINT64)0x7 << PART_ATT_MAX_RETRY_CNT_BIT)
#define PART_ATT_SUCCESSFUL_VAL ((UINT64)0x1 << PART_ATT_SUCCESS_BIT)
#define PART_ATT_UNBOOTABLE_VAL ((UINT64)0x1 << PART_ATT_UNBOOTABLE_BIT)
#define MAX_PRIORITY 3
#define MAX_RETRY_COUNT 7
#define MAX_NUM_PARTITIONS 128
#define MIN_PARTITION_ARRAY_SIZE 0x4000
#define ATTRIBUTE_FLAG_OFFSET 48
#define INVALID_PTN -1
#define GPT_HDR_BLOCKS 0x1
#define MAX_PARTITION_ENTRIES_SZ (MAX_NUM_PARTITIONS * PARTITION_ENTRY_SIZE)
#define GUID_SIZE 16
#define PRIMARY_HDR_LBA 0x1
#define BOOT_PART_SIZE 32
/*Slot specific macros*/
#define MAX_SLOT_SUFFIX_SZ 3
#define MIN_SLOTS 1
#define MAX_SLOTS 2
#define MAX_LUNS 8
#define NO_LUN -1
#define GET_LWORD_FROM_BYTE(x) \
((UINT32) * (x) | ((UINT32) * (x + 1) << 8) | ((UINT32) * (x + 2) << 16) | \
((UINT32) * (x + 3) << 24))
#define GET_LLWORD_FROM_BYTE(x) \
((UINT64) * (x) | ((UINT64) * (x + 1) << 8) | ((UINT64) * (x + 2) << 16) | \
((UINT64) * (x + 3) << 24) | ((UINT64) * (x + 4) << 32) | \
((UINT64) * (x + 5) << 40) | ((UINT64) * (x + 6) << 48) | \
((UINT64) * (x + 7) << 56))
#define GET_LONG(x) \
((UINT32) * (x) | ((UINT32) * (x + 1) << 8) | ((UINT32) * (x + 2) << 16) | \
((UINT32) * (x + 3) << 24))
#define PUT_LONG(x, y) \
*(x) = y & 0xff; \
*(x + 1) = (y >> 8) & 0xff; \
*(x + 2) = (y >> 16) & 0xff; \
*(x + 3) = (y >> 24) & 0xff;
#define PUT_LONG_LONG(x, y) \
(*(x) = (y)&0xff); \
(*((x) + 1) = (((y) >> 8) & 0xff)); \
(*((x) + 2) = (((y) >> 16) & 0xff)); \
(*((x) + 3) = (((y) >> 24) & 0xff)); \
(*((x) + 4) = (((y) >> 32) & 0xff)); \
(*((x) + 5) = (((y) >> 40) & 0xff)); \
(*((x) + 6) = (((y) >> 48) & 0xff)); \
(*((x) + 7) = (((y) >> 56) & 0xff));
#define GUARD(code) \
do { \
Status = (code); \
if (Status != EFI_SUCCESS) { \
DEBUG ((EFI_D_ERROR, "Err: line:%d %a() status: %r\n", __LINE__, \
__FUNCTION__, Status)); \
return Status; \
} \
} while (0)
struct StoragePartInfo {
HandleInfo HandleInfoList[MAX_NUM_PARTITIONS];
UINT32 MaxHandles;
};
extern struct StoragePartInfo Ptable[MAX_LUNS];
typedef struct {
CHAR16 Suffix[MAX_SLOT_SUFFIX_SZ];
} Slot;
Slot GetCurrentSlotSuffix ();
UINT32 GetMaxLuns ();
VOID GetPartitionCount (UINT32 *Val);
VOID SetMultiSlotBootVal (BOOLEAN Val);
struct PartitionEntry {
EFI_PARTITION_ENTRY PartEntry;
UINT32 lun;
};
extern struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
struct BootPartsLinkedList {
CHAR16 PartName[BOOT_PART_SIZE];
struct BootPartsLinkedList *Next;
};
INT32 GetPartitionIndex (CHAR16 *PartitionName);
BOOLEAN PartitionHasMultiSlot (CONST CHAR16 *Pname);
EFI_STATUS EnumeratePartitions (VOID);
VOID UpdatePartitionEntries (VOID);
VOID UpdatePartitionAttributes (UINT32 UpdateType);
BOOLEAN IsSuffixEmpty (Slot *CheckSlot);
EFI_STATUS SetActiveSlot (Slot *NewSlot, BOOLEAN ResetSuccessBit, BOOLEAN SetSuccessBit);
BOOLEAN IsSlotBootable (Slot *CheckSlot);
EFI_STATUS ClearUnbootable (Slot *CheckSlot);
UINT64 GetPartitionSize (EFI_BLOCK_IO_PROTOCOL *BlockIo);
#endif

View File

@ -0,0 +1,55 @@
/* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BSL_BOARD_H__
#define __BSL_BOARD_H__
#include <Uefi.h>
#include <Library/PrintLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BootSlotLib/EFICardInfo.h>
#define HANDLE_MAX_INFO_LIST 128
typedef enum {
EMMC = 0,
UFS = 1,
UNKNOWN,
} MemCardType;
VOID
GetRootDeviceType (CHAR8 *StrDeviceType, UINT32 Len);
MemCardType
CheckRootDeviceType (VOID);
EFI_STATUS
UfsGetSetBootLun (UINT32 *UfsBootlun, BOOLEAN IsGet);
#endif

View File

@ -0,0 +1,361 @@
/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AutoGen.h"
#include <Library/BootSlotLib/BlockIoUtils.h>
#include <Library/BootSlotLib/EFIUtils.h>
#include <Protocol/PartitionInfo.h>
/* Volume Label size 11 chars, round off to 16 */
#define VOLUME_LABEL_SIZE 16
/* List of all the filters that need device path protocol in the handle to
* filter */
#define FILTERS_NEEDING_DEVICEPATH \
(BLK_IO_SEL_PARTITIONED_MBR | BLK_IO_SEL_PARTITIONED_GPT | \
BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID | BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY | \
BLK_IO_SEL_MATCH_ROOT_DEVICE)
/* Returns 0 if the volume label matches otherwise non zero */
STATIC UINTN
CompareVolumeLabel (IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* Fs,
IN CHAR8* ReqVolumeName)
{
INT32 CmpResult;
UINT32 j;
UINT16 VolumeLabel[VOLUME_LABEL_SIZE];
EFI_FILE_PROTOCOL *FsVolume = NULL;
EFI_STATUS Status;
UINTN Size;
EFI_FILE_SYSTEM_INFO *FsInfo;
// Get information about the volume
Status = Fs->OpenVolume (Fs, &FsVolume);
if (Status != EFI_SUCCESS) {
return 1;
}
/* Get the Volume name */
Size = 0;
FsInfo = NULL;
Status = FsVolume->GetInfo (FsVolume, &gEfiFileSystemInfoGuid, &Size, FsInfo);
if (Status == EFI_BUFFER_TOO_SMALL) {
FsInfo = AllocateZeroPool (Size);
Status = FsVolume->GetInfo (FsVolume,
&gEfiFileSystemInfoGuid, &Size, FsInfo);
if (Status != EFI_SUCCESS) {
FreePool (FsInfo);
return 1;
}
}
if (FsInfo == NULL) {
return 1;
}
/* Convert the passed in Volume name to Wide char and upper case */
for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && ReqVolumeName[j]; ++j) {
VolumeLabel[j] = ReqVolumeName[j];
if ((VolumeLabel[j] >= 'a') &&
(VolumeLabel[j] <= 'z')) {
VolumeLabel[j] -= ('a' - 'A');
}
}
/* Null termination */
VolumeLabel[j] = 0;
/* Change any lower chars in volume name to upper
* (ideally this is not needed) */
for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && FsInfo->VolumeLabel[j]; ++j) {
if ((FsInfo->VolumeLabel[j] >= 'a') &&
(FsInfo->VolumeLabel[j] <= 'z')) {
FsInfo->VolumeLabel[j] -= ('a' - 'A');
}
}
CmpResult = StrnCmp (FsInfo->VolumeLabel, VolumeLabel, VOLUME_LABEL_SIZE);
FreePool (FsInfo);
FsVolume->Close (FsVolume);
return CmpResult;
}
EFI_STATUS
EFIAPI
GetPartitionEntry (IN EFI_HANDLE Handle,
OUT EFI_PARTITION_ENTRY **PartEntry)
{
EFI_PARTITION_INFO_PROTOCOL *PartInfo;
EFI_STATUS Status = gBS->HandleProtocol (Handle, &gEfiPartitionInfoProtocolGuid, (VOID **)&PartInfo);
if (!EFI_ERROR(Status)) {
*PartEntry = &PartInfo->Info.Gpt;
}
return Status;
}
/**
Returns a list of BlkIo handles based on required criteria
SelectionAttrib : Bitmask representing the conditions that need
to be met for the handles returned. Based on the
selections filter members should have valid values.
FilterData : Instance of Partition Select Filter structure that
needs extended data for certain type flags. For example
Partition type and/or Volume name can be specified.
HandleInfoPtr : Pointer to array of HandleInfo structures in which the
output is returned.
MaxBlkIopCnt : On input, max number of handle structures the buffer can hold,
On output, the number of handle structures returned.
@retval EFI_SUCCESS if the operation was successful
*/
EFI_STATUS
EFIAPI
GetBlkIOHandles (IN UINT32 SelectionAttrib,
IN PartiSelectFilter *FilterData,
OUT HandleInfo *HandleInfoPtr,
IN OUT UINT32* MaxBlkIopCnt)
{
EFI_BLOCK_IO_PROTOCOL *BlkIo;
EFI_HANDLE *BlkIoHandles;
UINTN BlkIoHandleCount;
UINTN i;
UINTN DevicePathDepth;
HARDDRIVE_DEVICE_PATH *Partition, *PartitionOut;
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *DevPathInst;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
VENDOR_DEVICE_PATH *RootDevicePath;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
UINT32 BlkIoCnt = 0;
EFI_PARTITION_ENTRY *PartEntry;
if ((MaxBlkIopCnt == NULL) || (HandleInfoPtr == NULL))
return EFI_INVALID_PARAMETER;
/* Adjust some defaults first */
if ((SelectionAttrib & (BLK_IO_SEL_MEDIA_TYPE_REMOVABLE |
BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE)) == 0)
SelectionAttrib |=
(BLK_IO_SEL_MEDIA_TYPE_REMOVABLE | BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE);
if (((BLK_IO_SEL_PARTITIONED_GPT | BLK_IO_SEL_PARTITIONED_MBR) &
SelectionAttrib) == 0)
SelectionAttrib |=
(BLK_IO_SEL_PARTITIONED_GPT | BLK_IO_SEL_PARTITIONED_MBR);
/* If we need Filesystem handle then search based on that its narrower search
* than BlkIo */
if (SelectionAttrib & (BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM |
BLK_IO_SEL_SELECT_BY_VOLUME_NAME)) {
Status =
gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
NULL, &BlkIoHandleCount, &BlkIoHandles);
} else {
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid,
NULL, &BlkIoHandleCount, &BlkIoHandles);
}
if (Status != EFI_SUCCESS) {
DEBUG (
(EFI_D_ERROR, "Unable to get Filesystem Handle buffer %r\n", Status));
return Status;
}
/* Loop through to search for the ones we are interested in. */
for (i = 0; i < BlkIoHandleCount; i++) {
Status = gBS->HandleProtocol (BlkIoHandles[i], &gEfiBlockIoProtocolGuid,
(VOID **)&BlkIo);
/* Fv volumes will not support Blk I/O protocol */
if (Status == EFI_UNSUPPORTED) {
continue;
}
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "Unable to get Filesystem Handle %r\n", Status));
return Status;
}
/* Check if the media type criteria (for removable/not) satisfies */
if (BlkIo->Media->RemovableMedia) {
if ((SelectionAttrib & BLK_IO_SEL_MEDIA_TYPE_REMOVABLE) == 0)
continue;
} else {
if ((SelectionAttrib & BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE) == 0)
continue;
}
/* Clear the pointer, we can get it if the filter is set */
PartitionOut = NULL;
/* Check if partition related criteria satisfies */
if ((SelectionAttrib & FILTERS_NEEDING_DEVICEPATH) != 0) {
Status = gBS->HandleProtocol (
BlkIoHandles[i], &gEfiDevicePathProtocolGuid, (VOID **)&DevPathInst);
/* If we didn't get the DevicePath Protocol then this handle
* cannot be used */
if (EFI_ERROR (Status))
continue;
DevicePathDepth = 0;
/* Get the device path */
TempDevicePath = DevPathInst;
RootDevicePath = (VENDOR_DEVICE_PATH *)DevPathInst;
Partition = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
if ((SelectionAttrib & (BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY |
BLK_IO_SEL_MATCH_ROOT_DEVICE)) != 0) {
if (!FilterData) {
return EFI_INVALID_PARAMETER;
}
/* If this is not the root device that we are looking for, ignore this
* handle */
if (RootDevicePath->Header.Type != HARDWARE_DEVICE_PATH ||
RootDevicePath->Header.SubType != HW_VENDOR_DP ||
(RootDevicePath->Header.Length[0] |
(RootDevicePath->Header.Length[1] << 8)) !=
sizeof (VENDOR_DEVICE_PATH) ||
((FilterData->RootDeviceType != NULL) &&
(CompareGuid (FilterData->RootDeviceType,
&RootDevicePath->Guid) == FALSE)))
continue;
}
/* Locate the last Device Path Node */
while (!IsDevicePathEnd (TempDevicePath)) {
DevicePathDepth++;
Partition = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
TempDevicePath = NextDevicePathNode (TempDevicePath);
}
/* If we need the handle for root device only and if this is representing
* a sub partition in the root device then ignore this handle */
if (SelectionAttrib & BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY)
if (DevicePathDepth > 1)
continue;
/* Check if the last node is Harddrive Device path that contains the
* Partition information */
if (Partition->Header.Type == MEDIA_DEVICE_PATH &&
Partition->Header.SubType == MEDIA_HARDDRIVE_DP &&
(Partition->Header.Length[0] | (Partition->Header.Length[1] << 8)) ==
sizeof (*Partition)) {
PartitionOut = Partition;
if ((SelectionAttrib & BLK_IO_SEL_PARTITIONED_GPT) == 0)
if (Partition->MBRType == PARTITIONED_TYPE_GPT)
continue;
if ((SelectionAttrib & BLK_IO_SEL_PARTITIONED_MBR) == 0)
if (Partition->MBRType == PARTITIONED_TYPE_MBR)
continue;
/* PartitionDxe implementation should return partition type also */
if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0) {
VOID *Interface;
if (!FilterData ||
FilterData->PartitionType == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->HandleProtocol (BlkIoHandles[i],
FilterData->PartitionType,
(VOID**)&Interface);
if (EFI_ERROR (Status)) {
Status = GetPartitionEntry(BlkIoHandles[i], &PartEntry);
if (EFI_ERROR (Status)) {
continue;
}
if (CompareGuid (&PartEntry->PartitionTypeGUID, FilterData->PartitionType) == FALSE) {
continue;
}
}
}
}
/* If we wanted a particular partition and didn't get the HDD DP,
then this handle is probably not the interested ones */
else if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0)
continue;
}
/* Check if the Filesystem related criteria satisfies */
if ((SelectionAttrib & BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM) != 0) {
Status = gBS->HandleProtocol (BlkIoHandles[i],
&gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
if (EFI_ERROR (Status)) {
continue;
}
if ((SelectionAttrib & BLK_IO_SEL_SELECT_BY_VOLUME_NAME) != 0) {
if (!FilterData ||
FilterData->VolumeName == NULL) {
return EFI_INVALID_PARAMETER;
}
if (CompareVolumeLabel (Fs, FilterData->VolumeName) != 0) {
continue;
}
}
}
/* Check if the Partition name related criteria satisfies */
if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_LABEL) != 0) {
Status = GetPartitionEntry(BlkIoHandles[i], &PartEntry);
if (Status != EFI_SUCCESS)
continue;
if (StrnCmp (PartEntry->PartitionName, FilterData->PartitionLabel,
MAX (StrLen (PartEntry->PartitionName),
StrLen (FilterData->PartitionLabel))))
continue;
}
/* We came here means, this handle satisfies all the conditions needed,
* Add it into the list */
HandleInfoPtr[BlkIoCnt].Handle = BlkIoHandles[i];
HandleInfoPtr[BlkIoCnt].BlkIo = BlkIo;
HandleInfoPtr[BlkIoCnt].PartitionInfo = PartitionOut;
BlkIoCnt++;
if (BlkIoCnt >= *MaxBlkIopCnt)
break;
}
*MaxBlkIopCnt = BlkIoCnt;
/* Free the handle buffer */
if (BlkIoHandles != NULL) {
FreePool (BlkIoHandles);
BlkIoHandles = NULL;
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,68 @@
# /*
# * BootSlot Library
# * Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
# *
# * This program is free software: you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation, either version 3 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program. If not, see <https://www.gnu.org/licenses/
# */
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = BootSlotLib
FILE_GUID = 6071c048-1de6-4141-ba0a-4500e1096572
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = BootSlotLib
[Sources]
EFIUtils.c
StorageUtils.c
BlockIoUtils.c
PartitionTableUpdate.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
sdm845Pkg/sdm845Pkg.dec
[LibraryClasses]
UefiLib
BaseLib
DebugLib
DevicePathLib
[Guids]
gEfiFileSystemInfoGuid
gEfiEmmcUserPartitionGuid
gEfiUfsLU0Guid
gEfiUfsLU1Guid
gEfiUfsLU2Guid
gEfiUfsLU3Guid
gEfiUfsLU4Guid
gEfiUfsLU5Guid
gEfiUfsLU6Guid
gEfiUfsLU7Guid
[Protocols]
gEfiBlockIoProtocolGuid
gEfiDiskIoProtocolGuid
gEfiPartitionInfoProtocolGuid
gEfiDevicePathToTextProtocolGuid
gEfiDevicePathProtocolGuid
gEfiDevicePathFromTextProtocolGuid
gEfiSimpleFileSystemProtocolGuid
gEfiMemCardInfoProtocolGuid
[Depex]
TRUE

View File

@ -0,0 +1,32 @@
/*
* SwitchSlotsApp Module
* Copyright (C) 2021 Renard Gold <goldrenard@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/
*/
#include <Library/BootSlotLib/EFIUtils.h>
#include <Library/UefiLib.h>
void WaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable) {
UINTN index = 0;
EFI_INPUT_KEY Key;
mSystemTable->BootServices->WaitForEvent(1, &mSystemTable->ConIn->WaitForKey, &index);
mSystemTable->ConIn->ReadKeyStroke(mSystemTable->ConIn, &Key);
}
void PrintAndWaitAnyKey(EFI_SYSTEM_TABLE *mSystemTable, CHAR16 *Message) {
Print(Message);
WaitAnyKey(mSystemTable);
}

View File

@ -0,0 +1,926 @@
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of The Linux Foundation nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "AutoGen.h"
#include <Uefi.h>
#include <Uefi/UefiSpec.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/BootSlotLib.h>
struct StoragePartInfo Ptable[MAX_LUNS];
struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
STATIC UINT32 MaxLuns;
STATIC UINT32 PartitionCount;
STATIC struct PartitionEntry PtnEntriesBak[MAX_NUM_PARTITIONS];
STATIC struct BootPartsLinkedList *HeadNode;
STATIC EFI_STATUS
GetActiveSlot (Slot *ActiveSlot);
Slot GetCurrentSlotSuffix (VOID)
{
Slot CurrentSlot = {{0}};
BOOLEAN IsMultiSlot = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
if (IsMultiSlot == FALSE) {
return CurrentSlot;
}
GetActiveSlot (&CurrentSlot);
return CurrentSlot;
}
VOID
GetPartitionCount (UINT32 *Val)
{
*Val = PartitionCount;
return;
}
VOID UpdatePartitionEntries (VOID)
{
UINT32 i;
UINT32 j;
UINT32 Index = 0;
EFI_STATUS Status;
EFI_PARTITION_ENTRY *PartEntry;
PartitionCount = 0;
/*Nullify the PtnEntries array before using it*/
gBS->SetMem ((VOID *)PtnEntries,
(sizeof (PtnEntries[0]) * MAX_NUM_PARTITIONS), 0);
for (i = 0; i < MaxLuns; i++) {
for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS);
j++, Index++) {
Status = GetPartitionEntry(Ptable[i].HandleInfoList[j].Handle, &PartEntry);
PartitionCount++;
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_VERBOSE, "Selected Lun : %d, handle: %d does not have "
"partition record, ignore\n",
i, j));
PtnEntries[Index].lun = i;
continue;
}
gBS->CopyMem ((&PtnEntries[Index]), PartEntry, sizeof (PartEntry[0]));
PtnEntries[Index].lun = i;
}
}
/* Back up the ptn entries */
gBS->CopyMem (PtnEntriesBak, PtnEntries, sizeof (PtnEntries));
}
INT32
GetPartitionIndex (CHAR16 *Pname)
{
INT32 i;
for (i = 0; i < PartitionCount; i++) {
if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname,
ARRAY_SIZE (PtnEntries[i].PartEntry.PartitionName))) {
return i;
}
}
return INVALID_PTN;
}
STATIC EFI_STATUS
GetStorageHandle (INT32 Lun, HandleInfo *BlockIoHandle, UINT32 *MaxHandles)
{
EFI_STATUS Status = EFI_INVALID_PARAMETER;
UINT32 Attribs = 0;
PartiSelectFilter HandleFilter;
// UFS LUN GUIDs
EFI_GUID LunGuids[] = {
gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid,
gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid,
};
Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY;
HandleFilter.PartitionType = NULL;
HandleFilter.VolumeName = NULL;
if (Lun == NO_LUN) {
HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
Status =
GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Emmc\n"));
return Status;
}
} else {
HandleFilter.RootDeviceType = &LunGuids[Lun];
Status =
GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun));
return Status;
}
}
return Status;
}
STATIC BOOLEAN IsUpdatePartitionAttributes ()
{
if (CompareMem (PtnEntries, PtnEntriesBak, sizeof (PtnEntries))) {
return TRUE;
}
return FALSE;
}
UINT64 GetPartitionSize (EFI_BLOCK_IO_PROTOCOL *BlockIo)
{
UINT64 PartitionSize;
if (!BlockIo) {
DEBUG ((EFI_D_ERROR, "Invalid parameter, pleae check BlockIo info!!!\n"));
return 0;
}
if (CHECK_ADD64 (BlockIo->Media->LastBlock, 1)) {
DEBUG ((EFI_D_ERROR, "Integer overflow while adding LastBlock and 1\n"));
return 0;
}
if ((MAX_UINT64 / (BlockIo->Media->LastBlock + 1)) <
(UINT64)BlockIo->Media->BlockSize) {
DEBUG ((EFI_D_ERROR,
"Integer overflow while multiplying LastBlock and BlockSize\n"));
return 0;
}
PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
return PartitionSize;
}
VOID UpdatePartitionAttributes (UINT32 UpdateType)
{
UINT32 BlkSz;
UINT8 *GptHdr = NULL;
UINT8 *GptHdrPtr = NULL;
UINTN MaxGptPartEntrySzBytes;
UINT32 Offset;
UINT32 MaxPtnCount = 0;
UINT32 PtnEntrySz = 0;
UINT32 i = 0;
UINT8 *PtnEntriesPtr;
UINT8 *Ptn_Entries;
UINT32 CrcVal = 0;
UINT32 Iter;
UINT32 HdrSz = GPT_HEADER_SIZE;
UINT64 DeviceDensity;
UINT64 CardSizeSec;
EFI_STATUS Status;
INT32 Lun;
EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
UINT32 PartEntriesblocks = 0;
BOOLEAN SkipUpdation;
UINT64 Attr;
struct PartitionEntry *InMemPtnEnt;
/* The PtnEntries is the same as PtnEntriesBak by default
* It needs to update attributes or GUID when PtnEntries is changed
*/
if (!IsUpdatePartitionAttributes ()) {
return;
}
GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
for (Lun = 0; Lun < MaxLuns; Lun++) {
if (!AsciiStrnCmp (BootDeviceType, "EMMC", AsciiStrLen ("EMMC"))) {
Status = GetStorageHandle (NO_LUN, BlockIoHandle, &MaxHandles);
} else if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
Status = GetStorageHandle (Lun, BlockIoHandle, &MaxHandles);
} else {
DEBUG ((EFI_D_ERROR, "Unsupported boot device type\n"));
return;
}
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR,
"Failed to get BlkIo for device. MaxHandles:%d - %r\n",
MaxHandles, Status));
return;
}
if (MaxHandles != 1) {
DEBUG ((EFI_D_VERBOSE,
"Failed to get the BlockIo for device. MaxHandle:%d, %r\n",
MaxHandles, Status));
continue;
}
BlockIo = BlockIoHandle[0].BlkIo;
DeviceDensity = GetPartitionSize (BlockIo);
if (!DeviceDensity) {
return;
}
BlkSz = BlockIo->Media->BlockSize;
PartEntriesblocks = MAX_PARTITION_ENTRIES_SZ / BlkSz;
MaxGptPartEntrySzBytes = (GPT_HDR_BLOCKS + PartEntriesblocks) * BlkSz;
CardSizeSec = (DeviceDensity) / BlkSz;
Offset = PRIMARY_HDR_LBA;
GptHdr = AllocateZeroPool (MaxGptPartEntrySzBytes);
if (!GptHdr) {
DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n"));
return;
}
GptHdrPtr = GptHdr;
/* This loop iterates twice to update both primary and backup Gpt*/
for (Iter = 0; Iter < 2;
Iter++, (Offset = CardSizeSec - MaxGptPartEntrySzBytes / BlkSz)) {
SkipUpdation = TRUE;
Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
MaxGptPartEntrySzBytes, GptHdr);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Unable to read the media \n"));
goto Exit;
}
if (Iter == 0x1) {
/* This is the back up GPT */
Ptn_Entries = GptHdr;
GptHdr = GptHdr + ((PartEntriesblocks)*BlkSz);
} else
/* otherwise we are at the primary gpt */
Ptn_Entries = GptHdr + BlkSz;
PtnEntriesPtr = Ptn_Entries;
for (i = 0; i < PartitionCount; i++) {
InMemPtnEnt = (struct PartitionEntry *)PtnEntriesPtr;
/*If GUID is not present, then it is BlkIo Handle of the Lun. Skip*/
if (!(PtnEntries[i].PartEntry.PartitionTypeGUID.Data1)) {
DEBUG ((EFI_D_VERBOSE, " Skipping Lun:%d, i=%d\n", Lun, i));
continue;
}
if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
/* Partition table is populated with entries from lun 0 to max lun.
* break out of the loop once we see the partition lun is > current
* lun */
if (PtnEntries[i].lun > Lun)
break;
/* Find the entry where the partition table for 'lun' starts and then
* update the attributes */
if (PtnEntries[i].lun != Lun)
continue;
}
Attr = GET_LLWORD_FROM_BYTE (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET]);
if (UpdateType & PARTITION_GUID_MASK) {
if (CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID,
&PtnEntries[i].PartEntry.PartitionTypeGUID,
sizeof (EFI_GUID))) {
/* Update the partition GUID values */
gBS->CopyMem ((VOID *)PtnEntriesPtr,
(VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID,
GUID_SIZE);
/* Update the PtnEntriesBak for next comparison */
gBS->CopyMem (
(VOID *)&PtnEntriesBak[i].PartEntry.PartitionTypeGUID,
(VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID,
GUID_SIZE);
SkipUpdation = FALSE;
}
}
if (UpdateType & PARTITION_ATTRIBUTES_MASK) {
/* If GUID is not present, then it is back up GPT, update it
* If GUID is present, and the GUID is matched, update it
*/
if (!(InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) ||
!CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID,
&PtnEntries[i].PartEntry.PartitionTypeGUID,
sizeof (EFI_GUID))) {
if (Attr != PtnEntries[i].PartEntry.Attributes) {
/* Update the partition attributes */
PUT_LONG_LONG (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET],
PtnEntries[i].PartEntry.Attributes);
/* Update the PtnEntriesBak for next comparison */
PtnEntriesBak[i].PartEntry.Attributes =
PtnEntries[i].PartEntry.Attributes;
SkipUpdation = FALSE;
}
} else {
if (InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) {
DEBUG ((EFI_D_ERROR,
"Error in GPT header, GUID is not match!\n"));
continue;
}
}
}
/* point to the next partition entry */
PtnEntriesPtr += PARTITION_ENTRY_SIZE;
}
if (SkipUpdation)
continue;
MaxPtnCount = GET_LWORD_FROM_BYTE (&GptHdr[PARTITION_COUNT_OFFSET]);
PtnEntrySz = GET_LWORD_FROM_BYTE (&GptHdr[PENTRY_SIZE_OFFSET]);
if (((UINT64) (MaxPtnCount)*PtnEntrySz) > MAX_PARTITION_ENTRIES_SZ) {
DEBUG ((EFI_D_ERROR,
"Invalid GPT header fields MaxPtnCount = %x, PtnEntrySz = %x\n",
MaxPtnCount, PtnEntrySz));
goto Exit;
}
Status = gBS->CalculateCrc32 (Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)),
&CrcVal);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n",
Status));
goto Exit;
}
PUT_LONG (&GptHdr[PARTITION_CRC_OFFSET], CrcVal);
/*Write CRC to 0 before we calculate the crc of the GPT header*/
CrcVal = 0;
PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal);
Status = gBS->CalculateCrc32 (GptHdr, HdrSz, &CrcVal);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n",
Status));
goto Exit;
}
PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal);
if (Iter == 0x1)
/* Write the backup GPT header, which is at an offset of CardSizeSec -
* MaxGptPartEntrySzBytes/BlkSz in blocks*/
Status =
BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
MaxGptPartEntrySzBytes, (VOID *)Ptn_Entries);
else
/* Write the primary GPT header, which is at an offset of BlkSz */
Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset,
MaxGptPartEntrySzBytes, (VOID *)GptHdr);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
goto Exit;
}
}
FreePool (GptHdrPtr);
GptHdrPtr = NULL;
}
Exit:
if (GptHdrPtr) {
FreePool (GptHdrPtr);
GptHdrPtr = NULL;
}
}
STATIC VOID
MarkPtnActive (CHAR16 *ActiveSlot)
{
UINT32 i;
for (i = 0; i < PartitionCount; i++) {
/* Mark all the slots with current ActiveSlot as active */
if (StrStr (PtnEntries[i].PartEntry.PartitionName, ActiveSlot))
PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL;
else
PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL;
}
/* Update the partition table */
UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
}
STATIC VOID
SwapPtnGuid (EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2)
{
EFI_GUID Temp;
if (p1 == NULL || p2 == NULL)
return;
gBS->CopyMem ((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID,
sizeof (EFI_GUID));
gBS->CopyMem ((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID,
sizeof (EFI_GUID));
gBS->CopyMem ((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp,
sizeof (EFI_GUID));
}
STATIC EFI_STATUS GetMultiSlotPartsList (VOID)
{
UINT32 i = 0;
UINT32 j = 0;
UINT32 Len = 0;
UINT32 PtnLen = 0;
CHAR16 *SearchString = NULL;
struct BootPartsLinkedList *TempNode = NULL;
for (i = 0; i < PartitionCount; i++) {
SearchString = PtnEntries[i].PartEntry.PartitionName;
if (!SearchString[0])
continue;
for (j = i + 1; j < PartitionCount; j++) {
if (!PtnEntries[j].PartEntry.PartitionName[0])
continue;
Len = StrLen (SearchString);
PtnLen = StrLen (PtnEntries[j].PartEntry.PartitionName);
/*Need to compare till "boot_"a hence skip last Char from StrLen value*/
if ((PtnLen == Len) &&
!StrnCmp (PtnEntries[j].PartEntry.PartitionName,
SearchString, Len - 1) &&
(StrStr (SearchString, (CONST CHAR16 *)L"_a") ||
StrStr (SearchString, (CONST CHAR16 *)L"_b"))) {
TempNode = AllocateZeroPool (sizeof (struct BootPartsLinkedList));
if (TempNode) {
/*Skip _a/_b from partition name*/
StrnCpyS (TempNode->PartName, sizeof (TempNode->PartName),
SearchString, Len - 2);
TempNode->Next = HeadNode;
HeadNode = TempNode;
} else {
DEBUG ((EFI_D_ERROR,
"Unable to Allocate Memory for MultiSlot Partition list\n"));
return EFI_OUT_OF_RESOURCES;
}
break;
}
}
}
return EFI_SUCCESS;
}
STATIC VOID
SwitchPtnSlots (CONST CHAR16 *SetActive)
{
UINT32 i;
struct PartitionEntry *PtnCurrent = NULL;
struct PartitionEntry *PtnNew = NULL;
CHAR16 CurSlot[BOOT_PART_SIZE];
CHAR16 NewSlot[BOOT_PART_SIZE];
CHAR16 SetInactive[MAX_SLOT_SUFFIX_SZ];
UINT32 UfsBootLun = 0;
BOOLEAN UfsGet = TRUE;
BOOLEAN UfsSet = FALSE;
struct BootPartsLinkedList *TempNode = NULL;
EFI_STATUS Status;
CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
/* Create the partition name string for active and non active slots*/
if (!StrnCmp (SetActive, (CONST CHAR16 *)L"_a",
StrLen ((CONST CHAR16 *)L"_a")))
StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_b",
StrLen ((CONST CHAR16 *)L"_b"));
else
StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_a",
StrLen ((CONST CHAR16 *)L"_a"));
if (!HeadNode) {
Status = GetMultiSlotPartsList ();
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_INFO, "Unable to get GetMultiSlotPartsList\n"));
return;
}
}
for (TempNode = HeadNode; TempNode; TempNode = TempNode->Next) {
gBS->SetMem (CurSlot, BOOT_PART_SIZE, 0);
gBS->SetMem (NewSlot, BOOT_PART_SIZE, 0);
StrnCpyS (CurSlot, BOOT_PART_SIZE, TempNode->PartName,
StrLen (TempNode->PartName));
StrnCatS (CurSlot, BOOT_PART_SIZE, SetInactive, StrLen (SetInactive));
StrnCpyS (NewSlot, BOOT_PART_SIZE, TempNode->PartName,
StrLen (TempNode->PartName));
StrnCatS (NewSlot, BOOT_PART_SIZE, SetActive, StrLen (SetActive));
/* Find the pointer to partition table entry for active and non-active
* slots*/
for (i = 0; i < PartitionCount; i++) {
if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, CurSlot,
StrLen (CurSlot))) {
PtnCurrent = &PtnEntries[i];
} else if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, NewSlot,
StrLen (NewSlot))) {
PtnNew = &PtnEntries[i];
}
}
/* Swap the guids for the slots */
SwapPtnGuid (&PtnCurrent->PartEntry, &PtnNew->PartEntry);
PtnCurrent = PtnNew = NULL;
}
GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
UfsGetSetBootLun (&UfsBootLun, UfsGet);
// Special case for XBL is to change the bootlun instead of swapping the
// guid
if (UfsBootLun == 0x1 &&
!StrnCmp (SetActive, (CONST CHAR16 *)L"_b",
StrLen ((CONST CHAR16 *)L"_b"))) {
DEBUG ((EFI_D_INFO, "Switching the boot lun from 1 to 2\n"));
UfsBootLun = 0x2;
} else if (UfsBootLun == 0x2 &&
!StrnCmp (SetActive, (CONST CHAR16 *)L"_a",
StrLen ((CONST CHAR16 *)L"_a"))) {
DEBUG ((EFI_D_INFO, "Switching the boot lun from 2 to 1\n"));
UfsBootLun = 0x1;
}
UfsGetSetBootLun (&UfsBootLun, UfsSet);
}
UpdatePartitionAttributes (PARTITION_GUID);
}
EFI_STATUS
EnumeratePartitions (VOID)
{
EFI_STATUS Status;
PartiSelectFilter HandleFilter;
UINT32 Attribs = 0;
UINT32 i;
// UFS LUN GUIDs
EFI_GUID LunGuids[] = {
gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid,
gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid,
};
gBS->SetMem ((VOID *)Ptable, (sizeof (struct StoragePartInfo) * MAX_LUNS), 0);
/* By default look for emmc partitions if not found look for UFS */
Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
Ptable[0].MaxHandles = ARRAY_SIZE (Ptable[0].HandleInfoList);
HandleFilter.PartitionType = NULL;
HandleFilter.VolumeName = NULL;
HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
Status =
GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0],
&Ptable[0].MaxHandles);
if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
MaxLuns = 1;
}
/* If the media is not emmc then look for UFS */
else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) {
/* By default max 8 luns are supported but HW could be configured to use
* only few of them or all of them
* Based on the information read update the MaxLuns to reflect the max
* supported luns */
for (i = 0; i < MAX_LUNS; i++) {
Ptable[i].MaxHandles = ARRAY_SIZE (Ptable[i].HandleInfoList);
HandleFilter.PartitionType = NULL;
HandleFilter.VolumeName = NULL;
HandleFilter.RootDeviceType = &LunGuids[i];
Status =
GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0],
&Ptable[i].MaxHandles);
/* If we fail to get block for a lun that means the lun is not configured
* and unsed, ignore the error
* and continue with the next Lun */
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR,
"Error getting block IO handle for %d lun, Lun may be unused\n",
i));
continue;
}
}
MaxLuns = i;
} else {
DEBUG ((EFI_D_ERROR, "Error populating block IO handles\n"));
return EFI_NOT_FOUND;
}
return Status;
}
/*Function to provide has-slot info
*Pname: the partition name
*return: 1 or 0.
*/
BOOLEAN
PartitionHasMultiSlot (CONST CHAR16 *Pname)
{
UINT32 i;
UINT32 SlotCount = 0;
UINT32 Len = StrLen (Pname);
for (i = 0; i < PartitionCount; i++) {
if (!(StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname, Len))) {
if (PtnEntries[i].PartEntry.PartitionName[Len] == L'_' &&
(PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'a' ||
PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'b'))
if (++SlotCount > MIN_SLOTS) {
return TRUE;
}
}
}
return FALSE;
}
STATIC struct PartitionEntry *
GetBootPartitionEntry (Slot *BootSlot)
{
INT32 Index = INVALID_PTN;
if (StrnCmp ((CONST CHAR16 *)L"_a", BootSlot->Suffix,
StrLen (BootSlot->Suffix)) == 0) {
Index = GetPartitionIndex ((CHAR16 *)L"boot_a");
} else if (StrnCmp ((CONST CHAR16 *)L"_b", BootSlot->Suffix,
StrLen (BootSlot->Suffix)) == 0) {
Index = GetPartitionIndex ((CHAR16 *)L"boot_b");
} else {
DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition "
"entry for slot %s\n",
BootSlot->Suffix));
return NULL;
}
if (Index == INVALID_PTN) {
DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition entry "
"for slot %s, invalid index\n",
BootSlot->Suffix));
return NULL;
}
return &PtnEntries[Index];
}
BOOLEAN IsSlotBootable (Slot *BootSlot)
{
struct PartitionEntry *BootPartition = NULL;
BootPartition = GetBootPartitionEntry (BootSlot);
if (BootPartition == NULL) {
DEBUG ((EFI_D_ERROR, "IsCurrentSlotBootable: No boot partition "
"entry for slot %s\n",
BootSlot->Suffix));
return FALSE;
}
DEBUG ((EFI_D_VERBOSE, "Slot suffix %s Part Attr 0x%lx\n", BootSlot->Suffix,
BootPartition->PartEntry.Attributes));
if (!(BootPartition->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) &&
BootPartition->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) {
DEBUG ((EFI_D_VERBOSE, "Slot %s is bootable\n", BootSlot->Suffix));
return TRUE;
}
DEBUG ((EFI_D_VERBOSE, "Slot %s is unbootable \n", BootSlot->Suffix));
return FALSE;
}
EFI_STATUS ClearUnbootable (Slot *BootSlot)
{
struct PartitionEntry *BootEntry = NULL;
BootEntry = GetBootPartitionEntry (BootSlot);
if (BootEntry == NULL) {
DEBUG ((EFI_D_ERROR,
"ClearUnbootable: No boot partition entry for slot %s\n",
BootSlot->Suffix));
return EFI_NOT_FOUND;
}
BootEntry->PartEntry.Attributes &= ~PART_ATT_UNBOOTABLE_VAL;
BootEntry->PartEntry.Attributes |= PART_ATT_MAX_RETRY_COUNT_VAL;
UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
return EFI_SUCCESS;
}
BOOLEAN
IsSuffixEmpty (Slot *CheckSlot)
{
if (CheckSlot == NULL) {
return TRUE;
}
if (StrLen (CheckSlot->Suffix) == 0) {
return TRUE;
}
return FALSE;
}
STATIC EFI_STATUS
GetActiveSlot (Slot *ActiveSlot)
{
EFI_STATUS Status = EFI_SUCCESS;
Slot Slots[] = {{L"_a"}, {L"_b"}};
UINT64 Priority = 0;
if (ActiveSlot == NULL) {
DEBUG ((EFI_D_ERROR, "GetActiveSlot: bad parameter\n"));
return EFI_INVALID_PARAMETER;
}
for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) {
struct PartitionEntry *BootPartition =
GetBootPartitionEntry (&Slots[SlotIndex]);
UINT64 BootPriority = 0;
if (BootPartition == NULL) {
DEBUG ((EFI_D_ERROR, "GetActiveSlot: No boot partition "
"entry for slot %s\n",
Slots[SlotIndex].Suffix));
return EFI_NOT_FOUND;
}
BootPriority =
(BootPartition->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
PART_ATT_PRIORITY_BIT;
if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) &&
(BootPriority > Priority)) {
GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),
Slots[SlotIndex].Suffix,
StrLen (Slots[SlotIndex].Suffix)));
Priority = BootPriority;
}
}
DEBUG ((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n",
ActiveSlot->Suffix, Priority));
if (IsSuffixEmpty (ActiveSlot) == TRUE) {
/* Check for first boot and set default slot */
/* For First boot all A/B attributes for the slot would be 0 */
UINT64 BootPriority = 0;
UINT64 RetryCount = 0;
struct PartitionEntry *SlotA = GetBootPartitionEntry (&Slots[0]);
if (SlotA == NULL) {
DEBUG ((EFI_D_ERROR, "GetActiveSlot: First Boot: No boot partition "
"entry for slot %s\n",
Slots[0].Suffix));
return EFI_NOT_FOUND;
}
BootPriority = (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
PART_ATT_PRIORITY_BIT;
RetryCount = (SlotA->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>
PART_ATT_MAX_RETRY_CNT_BIT;
if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 &&
(SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 &&
(SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 &&
BootPriority == 0) {
DEBUG ((EFI_D_INFO, "GetActiveSlot: First boot: set "
"default slot _a\n"));
SlotA->PartEntry.Attributes &=
(~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
SlotA->PartEntry.Attributes |=
(PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
PART_ATT_MAX_RETRY_COUNT_VAL);
GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),
Slots[0].Suffix, StrLen (Slots[0].Suffix)));
UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
return EFI_SUCCESS;
}
DEBUG ((EFI_D_ERROR, "GetActiveSlot: No active slot found\n"));
DEBUG ((EFI_D_ERROR, "GetActiveSlot: Slot attr: Priority %ld, Retry "
"%ld, Active %ld, Success %ld, unboot %ld\n",
BootPriority, RetryCount,
(SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >>
PART_ATT_ACTIVE_BIT,
(SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL),
(SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL)));
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
EFI_STATUS
SetActiveSlot (Slot *NewSlot, BOOLEAN ResetSuccessBit, BOOLEAN SetSuccessBit)
{
EFI_STATUS Status = EFI_SUCCESS;
Slot CurrentSlot = {{0}};
Slot *AlternateSlot = NULL;
Slot Slots[] = {{L"_a"}, {L"_b"}};
BOOLEAN UfsGet = TRUE;
BOOLEAN UfsSet = FALSE;
UINT32 UfsBootLun = 0;
CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
struct PartitionEntry *BootEntry = NULL;
if (NewSlot == NULL) {
DEBUG ((EFI_D_ERROR, "SetActiveSlot: input parameter invalid\n"));
return EFI_INVALID_PARAMETER;
}
GUARD (GetActiveSlot (&CurrentSlot));
if (StrnCmp (NewSlot->Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == 0) {
AlternateSlot = &Slots[1];
} else {
AlternateSlot = &Slots[0];
}
BootEntry = GetBootPartitionEntry (NewSlot);
if (BootEntry == NULL) {
DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n",
NewSlot->Suffix));
return EFI_NOT_FOUND;
}
BootEntry->PartEntry.Attributes |=
(PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
PART_ATT_MAX_RETRY_COUNT_VAL);
BootEntry->PartEntry.Attributes &= (~PART_ATT_UNBOOTABLE_VAL);
if (ResetSuccessBit &&
(BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL)) {
BootEntry->PartEntry.Attributes &= (~PART_ATT_SUCCESSFUL_VAL);
}
if (SetSuccessBit &&
((BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0)) {
BootEntry->PartEntry.Attributes |= PART_ATT_SUCCESSFUL_VAL;
}
/* Reduce the priority and clear the active flag for alternate slot*/
BootEntry = GetBootPartitionEntry (AlternateSlot);
if (BootEntry == NULL) {
DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n",
AlternateSlot->Suffix));
return EFI_NOT_FOUND;
}
BootEntry->PartEntry.Attributes &=
(~PART_ATT_PRIORITY_VAL & ~PART_ATT_ACTIVE_VAL);
BootEntry->PartEntry.Attributes |=
(((UINT64)MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT);
UpdatePartitionAttributes (PARTITION_ATTRIBUTES);
if (StrnCmp (CurrentSlot.Suffix, NewSlot->Suffix,
StrLen (CurrentSlot.Suffix)) == 0) {
DEBUG ((EFI_D_INFO, "SetActiveSlot: %s already active slot\n",
NewSlot->Suffix));
/* Check if BootLun is matching with Slot */
GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) {
UfsGetSetBootLun (&UfsBootLun, UfsGet);
if (UfsBootLun == 0x1 &&
!StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_b",
StrLen ((CONST CHAR16 *)L"_b"))) {
DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 1 to 2\n"));
DEBUG ((EFI_D_INFO, "Reboot Required\n"));
UfsBootLun = 0x2;
UfsGetSetBootLun (&UfsBootLun, UfsSet);
} else if (UfsBootLun == 0x2 &&
!StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_a",
StrLen ((CONST CHAR16 *)L"_a"))) {
DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 2 to 1\n"));
DEBUG ((EFI_D_INFO, "Reboot Required\n"));
UfsBootLun = 0x1;
UfsGetSetBootLun (&UfsBootLun, UfsSet);
}
}
} else {
DEBUG ((EFI_D_INFO, "Alternate slot %s, New slot %s\n",
AlternateSlot->Suffix, NewSlot->Suffix));
SwitchPtnSlots (NewSlot->Suffix);
MarkPtnActive (NewSlot->Suffix);
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,201 @@
/* Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AutoGen.h"
#include <Library/BootSlotLib/StorageUtils.h>
#include <Library/BootSlotLib/BlockIoUtils.h>
STATIC CONST CHAR8 *DeviceType[] = {
[EMMC] = "EMMC", [UFS] = "UFS", [UNKNOWN] = "Unknown",
};
/**
Device Handler Info
@param[out] HndlInfo : Pointer to array of HandleInfo structures
in which the output is returned.
@param[in, out] MaxHandles : On input, max number of handle structures
the buffer can hold, On output, the number
of handle structures returned.
@param[in] Type : Device Type : UNKNOWN, UFS, EMMC, NAND
@retval EFI_STATUS : Return Success on getting Handler Info
**/
STATIC EFI_STATUS
GetDeviceHandleInfo (VOID *HndlInfo, UINT32 MaxHandles, MemCardType Type)
{
EFI_STATUS Status = EFI_INVALID_PARAMETER;
UINT32 Attribs = 0;
PartiSelectFilter HandleFilter;
HandleInfo *HandleInfoList = HndlInfo;
Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
HandleFilter.PartitionType = NULL;
HandleFilter.VolumeName = NULL;
switch (Type) {
case UFS:
HandleFilter.RootDeviceType = &gEfiUfsLU0Guid;
break;
case EMMC:
HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
break;
case UNKNOWN:
DEBUG ((EFI_D_ERROR, "Device type unknown\n"));
return Status;
}
Status =
GetBlkIOHandles (Attribs, &HandleFilter, HandleInfoList, &MaxHandles);
if (EFI_ERROR (Status) ||
MaxHandles == 0) {
DEBUG ((EFI_D_ERROR, "Get BlkIohandles failed\n"));
return Status;
}
return Status;
}
/**
Return a device type
@retval Device type : UNKNOWN | UFS | EMMC | NAND
**/
STATIC UINT32
GetCompatibleRootDeviceType (VOID)
{
EFI_STATUS Status = EFI_INVALID_PARAMETER;
HandleInfo HandleInfoList[HANDLE_MAX_INFO_LIST];
UINT32 MaxHandles = ARRAY_SIZE (HandleInfoList);
UINT32 Index;
for (Index = 0; Index < UNKNOWN; Index++) {
Status = GetDeviceHandleInfo (HandleInfoList, MaxHandles, Index);
if (Status == EFI_SUCCESS) {
return Index;
}
}
return Index;
}
/**
Return a device type
@retval Device type : UNKNOWN | UFS | EMMC, default is UNKNOWN
**/
MemCardType
CheckRootDeviceType (VOID)
{
EFI_STATUS Status = EFI_INVALID_PARAMETER;
STATIC MemCardType Type = UNKNOWN;
MEM_CARD_INFO CardInfoData;
EFI_MEM_CARDINFO_PROTOCOL *CardInfo;
if (Type == UNKNOWN) {
Status = gBS->LocateProtocol (&gEfiMemCardInfoProtocolGuid, NULL,
(VOID **)&CardInfo);
if (!EFI_ERROR (Status)) {
Status = CardInfo->GetCardInfo (CardInfo, &CardInfoData);
if (!EFI_ERROR (Status)) {
if (!AsciiStrnCmp ((CHAR8 *)CardInfoData.card_type, "UFS",
AsciiStrLen ("UFS"))) {
Type = UFS;
} else if (!AsciiStrnCmp ((CHAR8 *)CardInfoData.card_type, "EMMC",
AsciiStrLen ("EMMC"))) {
Type = EMMC;
} else {
Type = GetCompatibleRootDeviceType ();
}
}
}
}
return Type;
}
/**
Get device type
@param[out] StrDeviceType : Pointer to array of device type string.
@param[in] Len : The size of the device type string
**/
VOID
GetRootDeviceType (CHAR8 *StrDeviceType, UINT32 Len)
{
UINT32 Type;
Type = CheckRootDeviceType ();
AsciiSPrint (StrDeviceType, Len, "%a", DeviceType[Type]);
}
EFI_STATUS
UfsGetSetBootLun (UINT32 *UfsBootlun, BOOLEAN IsGet)
{
EFI_STATUS Status = EFI_INVALID_PARAMETER;
EFI_MEM_CARDINFO_PROTOCOL *CardInfo;
HandleInfo HandleInfoList[MAX_HANDLE_INFO_LIST];
UINT32 Attribs = 0;
UINT32 MaxHandles;
PartiSelectFilter HandleFilter;
Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
MaxHandles = ARRAY_SIZE (HandleInfoList);
HandleFilter.PartitionType = NULL;
HandleFilter.VolumeName = NULL;
HandleFilter.RootDeviceType = &gEfiUfsLU0Guid;
Status =
GetBlkIOHandles (Attribs, &HandleFilter, HandleInfoList, &MaxHandles);
if (EFI_ERROR (Status))
return EFI_NOT_FOUND;
Status =
gBS->HandleProtocol (HandleInfoList[0].Handle,
&gEfiMemCardInfoProtocolGuid, (VOID **)&CardInfo);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "Error locating MemCardInfoProtocol:%x\n", Status));
return Status;
}
if (CardInfo->Revision < EFI_MEM_CARD_INFO_PROTOCOL_REVISION) {
DEBUG ((EFI_D_ERROR, "This API not supported in Revision =%u\n",
CardInfo->Revision));
return EFI_NOT_FOUND;
}
if (IsGet == TRUE) {
if (CardInfo->GetBootLU (CardInfo, UfsBootlun) == EFI_SUCCESS)
DEBUG ((EFI_D_VERBOSE, "Get BootLun =%u\n", *UfsBootlun));
} else {
if (CardInfo->SetBootLU (CardInfo, *UfsBootlun) == EFI_SUCCESS)
DEBUG ((EFI_D_VERBOSE, "SetBootLun =%u\n", *UfsBootlun));
}
return Status;
}

View File

@ -754,6 +754,15 @@ PlatformBootManagerAfterConsole (
PlatformRegisterFvBootOption (
&gUsbfnMsdAppFileGuid, L"Mass Storage", LOAD_OPTION_ACTIVE
);
#ifdef AB_SLOTS_SUPPORT
//
// Register Switch Slots App
//
PlatformRegisterFvBootOption (
&gSwitchSlotsAppFileGuid, L"Reboot to other slot", LOAD_OPTION_ACTIVE
);
#endif
}
/**

View File

@ -78,6 +78,7 @@
gEfiTtyTermGuid
gUefiShellFileGuid
gUsbfnMsdAppFileGuid
gSwitchSlotsAppFileGuid
[Protocols]
gEdkiiNonDiscoverableDeviceProtocolGuid

View File

@ -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

View File

@ -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