Better Slot Handling + Slot Switch from EDK2
This commit is contained in:
parent
713bb23f06
commit
7597ee34c5
82
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c
Normal file
82
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.c
Normal 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;
|
||||
}
|
37
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
Normal file
37
sdm845Pkg/Application/SwitchSlotsApp/SwitchSlotsApp.inf
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
75
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c
Normal file
75
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.c
Normal 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;
|
||||
}
|
40
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
Normal file
40
sdm845Pkg/Drivers/BootSlotDxe/BootSlotDxe.inf
Normal 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
|
26
sdm845Pkg/Include/Library/BootSlotLib.h
Normal file
26
sdm845Pkg/Include/Library/BootSlotLib.h
Normal 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
|
130
sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h
Normal file
130
sdm845Pkg/Include/Library/BootSlotLib/BlockIoUtils.h
Normal 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
|
168
sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h
Normal file
168
sdm845Pkg/Include/Library/BootSlotLib/EFICardInfo.h
Normal 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__ */
|
29
sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h
Normal file
29
sdm845Pkg/Include/Library/BootSlotLib/EFIUtils.h
Normal 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
|
209
sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h
Normal file
209
sdm845Pkg/Include/Library/BootSlotLib/PartitionTableUpdate.h
Normal 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
|
55
sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h
Normal file
55
sdm845Pkg/Include/Library/BootSlotLib/StorageUtils.h
Normal 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
|
361
sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c
Normal file
361
sdm845Pkg/Library/BootSlotLib/BlockIoUtils.c
Normal 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;
|
||||
}
|
68
sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf
Normal file
68
sdm845Pkg/Library/BootSlotLib/BootSlotLib.inf
Normal 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
|
32
sdm845Pkg/Library/BootSlotLib/EFIUtils.c
Normal file
32
sdm845Pkg/Library/BootSlotLib/EFIUtils.c
Normal 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);
|
||||
}
|
926
sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c
Normal file
926
sdm845Pkg/Library/BootSlotLib/PartitionTableUpdate.c
Normal 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;
|
||||
}
|
201
sdm845Pkg/Library/BootSlotLib/StorageUtils.c
Normal file
201
sdm845Pkg/Library/BootSlotLib/StorageUtils.c
Normal 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;
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,6 +78,7 @@
|
||||
gEfiTtyTermGuid
|
||||
gUefiShellFileGuid
|
||||
gUsbfnMsdAppFileGuid
|
||||
gSwitchSlotsAppFileGuid
|
||||
|
||||
[Protocols]
|
||||
gEdkiiNonDiscoverableDeviceProtocolGuid
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user