diff options
author | Vijay Kumar Pendoti <vpendo@codeaurora.org> | 2016-09-07 20:32:01 +0530 |
---|---|---|
committer | Vijay Kumar Pendoti <vpendo@codeaurora.org> | 2016-09-07 21:54:24 +0530 |
commit | c34f2b0eca8cba42b7998e4a17ffca013c1a6e03 (patch) | |
tree | 9b5fb211f8907568bd30a0d260ca26189413ef04 /QcomModulePkg/Library | |
parent | a49a5d7efe1af813e28884ac1aa0df8e299e33ad (diff) |
QcomModulePkg: Move the location of files
Move the location of PartitionTableUpdate.c and
PartitionTableUpdate.h files to Boot Library,so
that they can be used in all applications.
CRs-Fixed: 1058053
Change-Id: I3ad63278beb88f24ec739ab7c5a64af4e2f2e111
Diffstat (limited to 'QcomModulePkg/Library')
-rw-r--r-- | QcomModulePkg/Library/BootLib/BootLib.inf | 1 | ||||
-rw-r--r-- | QcomModulePkg/Library/BootLib/PartitionTableUpdate.c | 491 |
2 files changed, 492 insertions, 0 deletions
diff --git a/QcomModulePkg/Library/BootLib/BootLib.inf b/QcomModulePkg/Library/BootLib/BootLib.inf index 4f7d748788..1feca8e23d 100644 --- a/QcomModulePkg/Library/BootLib/BootLib.inf +++ b/QcomModulePkg/Library/BootLib/BootLib.inf @@ -56,6 +56,7 @@ UnlockMenu.c FastbootMenu.c VerifiedBootMenu.c + PartitionTableUpdate.c [Packages] ArmPkg/ArmPkg.dec diff --git a/QcomModulePkg/Library/BootLib/PartitionTableUpdate.c b/QcomModulePkg/Library/BootLib/PartitionTableUpdate.c new file mode 100644 index 0000000000..e8dd958059 --- /dev/null +++ b/QcomModulePkg/Library/BootLib/PartitionTableUpdate.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2015-2016, 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 <Uefi/UefiSpec.h> +#include "PartitionTableUpdate.h" + +STATIC BOOLEAN FlashingGpt; +STATIC BOOLEAN ParseSecondaryGpt; + +STATIC INTN PartitionVerifyMbrSignature(UINT32 Sz, UINT8 *Gpt) +{ + if ((MBR_SIGNATURE + 1) > Sz) + { + DEBUG((EFI_D_ERROR, "Gpt Image size is invalid\n")); + return FAILURE; + } + + /* Check for the signature */ + if ((Gpt[MBR_SIGNATURE] != MBR_SIGNATURE_BYTE_0) || + (Gpt[MBR_SIGNATURE + 1] != MBR_SIGNATURE_BYTE_1)) + { + DEBUG((EFI_D_ERROR, "MBR signature do not match\n")); + return FAILURE; + } + return SUCCESS; +} + +STATIC INTN MbrGetPartitionType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype) +{ + UINT32 PtypeOffset = MBR_PARTITION_RECORD + OS_TYPE; + + if (Sz < (PtypeOffset + sizeof(*Ptype))) + { + DEBUG((EFI_D_ERROR, "Input gpt image does not have gpt partition record data\n")); + return FAILURE; + } + + *Ptype = Gpt[PtypeOffset]; + + return SUCCESS; +} + +STATIC INTN PartitionGetType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype) +{ + INTN Ret; + + Ret = PartitionVerifyMbrSignature(Sz, Gpt); + if (!Ret) + { + /* MBR signature match, this coulb be MBR, MBR + EBR or GPT */ + Ret = MbrGetPartitionType(Sz, Gpt, Ptype); + if (!Ret) + { + if (*Ptype == GPT_PROTECTIVE) + *Ptype = PARTITION_TYPE_GPT; + else + *Ptype = PARTITION_TYPE_MBR; + } + } + else + { + /* This could be GPT back up */ + *Ptype = PARTITION_TYPE_GPT_BACKUP; + Ret = SUCCESS; + } + + return Ret; +} + +STATIC INTN ParseGptHeader(struct GptHeaderData *GptHeader, UINT8 *GptBuffer, UINTN DeviceDensity, UINT32 BlkSz) +{ + UINT32 CrcOrig; + UINT32 CrcVal; + UINT32 CurrentLba; + EFI_STATUS Status; + + if (((UINT32 *) GptBuffer)[0] != GPT_SIGNATURE_2 || ((UINT32 *) GptBuffer)[1] != GPT_SIGNATURE_1) + { + DEBUG((EFI_D_ERROR, "Gpt signature is not correct\n")); + return FAILURE; + } + + GptHeader->HeaderSz = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_SIZE_OFFSET]); + /* Validate the header size */ + if (GptHeader->HeaderSz < GPT_HEADER_SIZE) + { + DEBUG((EFI_D_ERROR, "GPT Header size is too small: %u\n", GptHeader->HeaderSz)); + return FAILURE; + } + + if (GptHeader->HeaderSz > BlkSz) + { + DEBUG((EFI_D_ERROR, "GPT Header is too large: %u\n", GptHeader->HeaderSz)); + return FAILURE; + } + + CrcOrig = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_CRC_OFFSET]); + /* CRC value is computed by setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes */ + CrcVal = 0; + PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal); + + Status = gBS->CalculateCrc32(GptBuffer, GptHeader->HeaderSz, &CrcVal); + if (Status != EFI_SUCCESS) + { + DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status)); + return FAILURE; + } + + if (CrcVal != CrcOrig) + { + DEBUG((EFI_D_ERROR, "Header CRC mismatch CrcVal = %u and CrcOrig = %u\n", CrcVal, CrcOrig)); + return FAILURE; + } + else + PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal); + + CurrentLba = GET_LLWORD_FROM_BYTE(&GptBuffer[PRIMARY_HEADER_OFFSET]); + GptHeader->FirstUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[FIRST_USABLE_LBA_OFFSET]); + GptHeader->MaxPtCnt = GET_LWORD_FROM_BYTE(&GptBuffer[PARTITION_COUNT_OFFSET]); + GptHeader->PartEntrySz = GET_LWORD_FROM_BYTE(&GptBuffer[PENTRY_SIZE_OFFSET]); + GptHeader->LastUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[LAST_USABLE_LBA_OFFSET]); + if (!ParseSecondaryGpt) + { + if (CurrentLba != GPT_LBA) + { + DEBUG((EFI_D_ERROR, "GPT first usable LBA mismatch\n")); + return FAILURE; + } + } + + /* Check for first lba should be within valid range */ + if (GptHeader->FirstUsableLba > (DeviceDensity / BlkSz)) + { + DEBUG((EFI_D_ERROR, "FirstUsableLba: %u out of Device capacity\n", GptHeader->FirstUsableLba)); + return FAILURE; + } + + /* Check for Last lba should be within valid range */ + if (GptHeader->LastUsableLba > (DeviceDensity / BlkSz)) + { + DEBUG((EFI_D_ERROR, "LastUsableLba: %u out of device capacity\n", GptHeader->LastUsableLba)); + return FAILURE; + } + + if (GptHeader->PartEntrySz != GPT_PART_ENTRY_SIZE) + { + DEBUG((EFI_D_ERROR, "Invalid partition entry size: %u\n", GptHeader->PartEntrySz)); + return FAILURE; + } + + if (GptHeader->MaxPtCnt > (MIN_PARTITION_ARRAY_SIZE / (GptHeader->PartEntrySz))) + { + DEBUG((EFI_D_ERROR, "Invalid Max Partition Count: %u\n", GptHeader->MaxPtCnt)); + return FAILURE; + } + + /* Todo: Check CRC during reading partition table*/ + if (!FlashingGpt) + { + } + + return SUCCESS; +} + +STATIC UINTN GetStorageHandle(INTN Lun, HandleInfo *BlockIoHandle, UINTN *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; + + if (Lun == NO_LUN) + { + HandleFilter.PartitionType = 0; + HandleFilter.VolumeName = 0; + 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 FAILURE; + } + } + else + { + HandleFilter.PartitionType = 0; + HandleFilter.VolumeName = 0; + 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 FAILURE; + } + } + + return SUCCESS; +} + +STATIC INTN PatchGpt ( + UINT8 *Gpt, UINTN DeviceDensity, UINT32 PartEntryArrSz, + struct GptHeaderData *GptHeader, UINT32 BlkSz) +{ + UINT8 *PrimaryGptHeader; + UINT8 *SecondaryGptHeader; + UINTN NumSectors; + UINT32 Offset; + UINT32 TotalPart = 0; + UINT32 LastPartOffset; + UINT8 *PartitionEntryArrStart; + UINT32 CrcVal; + EFI_STATUS Status; + + NumSectors = DeviceDensity / BlkSz; + + /* Update the primary and backup GPT header offset with the sector location */ + PrimaryGptHeader = (Gpt + BlkSz); + /* Patch primary GPT */ + PUT_LONG_LONG(PrimaryGptHeader + BACKUP_HEADER_OFFSET, (UINTN) (NumSectors - 1)); + PUT_LONG_LONG(PrimaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34)); + + /* Patch Backup GPT */ + Offset = (2 * PartEntryArrSz); + SecondaryGptHeader = Offset + BlkSz + PrimaryGptHeader; + PUT_LONG_LONG(SecondaryGptHeader + PRIMARY_HEADER_OFFSET, (UINTN)1); + PUT_LONG_LONG(SecondaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34)); + PUT_LONG_LONG(SecondaryGptHeader + PARTITION_ENTRIES_OFFSET, (UINTN) (NumSectors - 33)); + + /* Patch the last partition */ + while (*(PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE) != 0) + TotalPart++; + + LastPartOffset = (TotalPart - 1) * PARTITION_ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA; + + PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset, (UINTN) (NumSectors - 34)); + PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset + PartEntryArrSz, (UINTN) (NumSectors - 34)); + + /* Update CRC of the partition entry array for both headers */ + PartitionEntryArrStart = PrimaryGptHeader + BlkSz; + Status = gBS->CalculateCrc32(PartitionEntryArrStart, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error calculating CRC for primary partition entry\n")); + return FAILURE; + } + PUT_LONG(PrimaryGptHeader + PARTITION_CRC_OFFSET, CrcVal); + + Status = gBS->CalculateCrc32(PartitionEntryArrStart + PartEntryArrSz, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary partition entry\n")); + return FAILURE; + } + PUT_LONG(SecondaryGptHeader + PARTITION_CRC_OFFSET, CrcVal); + + /* Clear Header CRC field values & recalculate */ + PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, 0); + Status = gBS->CalculateCrc32(PrimaryGptHeader, GPT_HEADER_SIZE, &CrcVal); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error calculating CRC for primary gpt header\n")); + return FAILURE; + } + PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, CrcVal); + PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, 0); + Status = gBS->CalculateCrc32(SecondaryGptHeader, GPT_HEADER_SIZE, &CrcVal); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary gpt header\n")); + return FAILURE; + } + PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, CrcVal); + + return SUCCESS; +} + +STATIC INTN WriteGpt(INTN Lun, UINT32 Sz, UINT8 *Gpt) +{ + INTN Ret = 1; + struct GptHeaderData GptHeader; + UINTN BackupHeaderLba; + UINT32 MaxPtCnt = 0; + UINT8 *PartEntryArrSt; + UINT32 Offset; + UINT32 PartEntryArrSz; + UINTN DeviceDensity; + UINT32 BlkSz; + UINT8 *PrimaryGptHdr = NULL; + UINT8 *SecondaryGptHdr = NULL; + EFI_STATUS Status; + UINTN BackUpGptLba; + UINTN PartitionEntryLba; + EFI_ERASE_BLOCK_PROTOCOL *EraseProt = NULL; + UINTN TokenIndex; + EFI_ERASE_BLOCK_TOKEN EraseToken; + EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL; + HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE]; + UINTN MaxHandles = MAX_HANDLEINF_LST_SIZE; + + Ret = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles); + if (Ret || (MaxHandles != 1)) + { + DEBUG((EFI_D_ERROR, "Failed to get the BlockIo for the device\n")); + return Ret; + } + + BlockIo = BlockIoHandle[0].BlkIo; + DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize; + BlkSz = BlockIo->Media->BlockSize; + + /* Verity that passed block has valid GPT primary header */ + PrimaryGptHdr = (Gpt + BlkSz); + Ret = ParseGptHeader(&GptHeader, PrimaryGptHdr, DeviceDensity, BlkSz); + if (Ret) + { + DEBUG((EFI_D_ERROR, "GPT: Error processing primary GPT header\n")); + return Ret; + } + + /* Check if a valid back up GPT is present */ + PartEntryArrSz = GptHeader.PartEntrySz * GptHeader.MaxPtCnt; + if (PartEntryArrSz < MIN_PARTITION_ARRAY_SIZE) + PartEntryArrSz = MIN_PARTITION_ARRAY_SIZE; + + /* Back up partition is stored in the reverse order with back GPT, followed by + * part entries, find the offset to back up GPT */ + Offset = (2 * PartEntryArrSz); + SecondaryGptHdr = Offset + BlkSz + PrimaryGptHdr; + ParseSecondaryGpt = TRUE; + + Ret = ParseGptHeader(&GptHeader, SecondaryGptHdr, DeviceDensity, BlkSz); + if (Ret) + { + DEBUG((EFI_D_ERROR, "GPT: Error processing backup GPT header\n")); + return Ret; + } + + Ret = PatchGpt(Gpt, DeviceDensity, PartEntryArrSz, &GptHeader, BlkSz); + if (Ret) + { + DEBUG((EFI_D_ERROR, "Failed to patch GPT\n")); + return Ret; + } + /* Erase the entire card */ + Status = gBS->HandleProtocol(BlockIoHandle[0].Handle, &gEfiEraseBlockProtocolGuid, (VOID **) &EraseProt); + if (Status != EFI_SUCCESS) + { + DEBUG((EFI_D_ERROR, "Unable to locate Erase block protocol handle: %r\n", Status)); + return Status; + } + Status = EraseProt->EraseBlocks(BlockIo, BlockIo->Media->MediaId, 0, &EraseToken, DeviceDensity); + if (Status != EFI_SUCCESS) + { + DEBUG((EFI_D_ERROR, "Unable to Erase Block: %r\n", Status)); + return Status; + } + else + { + /* handle the event */ + if (EraseToken.Event != NULL) + { + DEBUG((EFI_D_INFO, "Waiting for the Erase even to signal the completion\n")); + gBS->WaitForEvent(1, &EraseToken.Event, &TokenIndex); + } + } + + /* write the protective MBR */ + Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 0, BlkSz, (VOID *)Gpt); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error writing protective MBR: %x\n", Status)); + return FAILURE; + } + + /* Write the primary GPT header, which is at an offset of BlkSz */ + Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 1, BlkSz, (VOID *)PrimaryGptHdr); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status)); + return FAILURE; + } + + /* Write the back up GPT header */ + BackUpGptLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[BACKUP_HEADER_OFFSET]); + Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, BackUpGptLba, BlkSz, (VOID *)SecondaryGptHdr); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error writing secondary GPT header: %x\n", Status)); + return FAILURE; + } + + /* write Partition Entries for primary partition table*/ + PartEntryArrSt = PrimaryGptHdr + BlkSz; + PartitionEntryLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[PARTITION_ENTRIES_OFFSET]); + Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error writing partition entries array for Primary Table: %x\n", Status)); + return FAILURE; + } + + /* write Partition Entries for secondary partition table*/ + PartEntryArrSt = PrimaryGptHdr + BlkSz + PartEntryArrSz; + PartitionEntryLba = GET_LLWORD_FROM_BYTE(&SecondaryGptHdr[PARTITION_ENTRIES_OFFSET]); + Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt); + if (EFI_ERROR(Status)) + { + DEBUG((EFI_D_ERROR, "Error writing partition entries array for Secondary Table: %x\n", Status)); + return FAILURE; + } + FlashingGpt = 0; + SetMem((VOID *)PrimaryGptHdr, Sz, 0x0); + + DEBUG((EFI_D_ERROR, "Updated Partition Table Successfully\n")); + return SUCCESS; +} + +EFI_STATUS UpdatePartitionTable(UINT8 *GptImage, UINT32 Sz, INTN Lun, struct StoragePartInfo *Ptable) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Ptype; + INTN Ret; + + /* Check if the partition type is GPT */ + Ret = PartitionGetType(Sz, GptImage, &Ptype); + if (Ret != 0) + { + DEBUG((EFI_D_ERROR, "Failed to get partition type from input gpt image\n")); + return EFI_NOT_FOUND; + } + + switch (Ptype) + { + case PARTITION_TYPE_GPT: + DEBUG((EFI_D_INFO, "Updating GPT partition\n")); + FlashingGpt = TRUE; + Ret = WriteGpt(Lun, Sz, GptImage); + if (Ret != 0) + { + DEBUG((EFI_D_ERROR, "Failed to write Gpt partition: %x\n", Ret)); + return EFI_VOLUME_CORRUPTED; + } + break; + default: + DEBUG((EFI_D_ERROR, "Invalid Partition type: %x\n",Ptype)); + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} |