| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software and associated documentation |
| * files (the "Software"), to deal in the Software without |
| * restriction, including without limitation the rights to use, copy, |
| * modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| |
| /* Copyright (c) 2018, 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 "../OEMPublicKey.h" |
| #include "avb_sysdeps.h" |
| #include "libavb.h" |
| #include <platform.h> |
| #include <err.h> |
| #include <ab_partition_parser.h> |
| #include <partition_parser.h> |
| |
| struct partition_entry *PtnEntries; |
| |
| bool IsCurrentSlotSuccessful() |
| { |
| struct ab_slot_info slot_info[AB_SUPPORTED_SLOTS]; |
| int slot_idx =INVALID; |
| |
| slot_idx = partition_find_active_slot(); |
| if(slot_idx == INVALID) |
| { |
| dprintf(CRITICAL, |
| "IsCurrentSlotSuccessful: no active slots found!\n"); |
| return FALSE; |
| } |
| partition_fill_slot_meta(slot_info); |
| if(!strncmp(slot_info[slot_idx].slot_is_succesful_rsp,"yes",strlen("yes"))) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| static struct partition_entry *Getpartition_entry(const char *Partition) |
| { |
| int32_t Index = partition_get_index(Partition); |
| struct partition_entry *partition_entries = |
| partition_get_partition_entries(); |
| if (partition_entries == NULL) { |
| dprintf(CRITICAL, "Getpartition_entry: No partition entry found\n"); |
| return NULL; |
| } |
| |
| PtnEntries = partition_entries; |
| |
| if (Index == INVALID_PTN) { |
| dprintf(CRITICAL, "Getpartition_entry: No partition entry for " |
| "%s, invalid index\n", Partition); |
| return NULL; |
| } |
| return &PtnEntries[Index]; |
| } |
| |
| int get_unique_guid(const char *Partition, char *unique_guid) |
| { |
| struct partition_entry *gp = Getpartition_entry(Partition); |
| if(gp == NULL) |
| { |
| dprintf(CRITICAL, "Partition entry not found\n"); |
| return -1; |
| |
| } |
| if (!unique_guid) |
| return -1; |
| |
| memcpy(unique_guid, gp->unique_partition_guid, UNIQUE_PARTITION_GUID_SIZE); |
| |
| return 0; |
| } |
| |
| static struct partition_entry *GetBootpartition_entry(Slot *BootSlot) |
| { |
| int32_t Index = INVALID_PTN; |
| struct partition_entry *partition_entries = |
| partition_get_partition_entries(); |
| if( BootSlot == NULL) |
| { |
| dprintf(INFO, "No bootable slot found \n"); |
| return NULL; |
| |
| } |
| if( partition_entries == NULL) |
| { |
| dprintf(INFO, "No partition entry found \n"); |
| return NULL; |
| |
| } |
| PtnEntries = partition_entries; |
| |
| if (strncmp("_a", (const char *)BootSlot->Suffix, strlen((const char *)BootSlot->Suffix)) == 0) { |
| Index = partition_get_index("boot_a"); |
| } else if (strncmp("_b", (const char *)BootSlot->Suffix, strlen((const char *)BootSlot->Suffix)) == 0) { |
| Index = partition_get_index("boot_b"); |
| } else { |
| dprintf(CRITICAL, "GetBootpartition_entry: No boot partition " |
| "entry for slot %s\n", (char *)BootSlot->Suffix); |
| return NULL; |
| } |
| |
| if (Index == INVALID_PTN) { |
| dprintf(CRITICAL, |
| "GetBootpartition_entry: No boot partition entry " |
| "for slot %s, invalid index\n", (char *)BootSlot->Suffix); |
| return NULL; |
| } |
| return &PtnEntries[Index]; |
| } |
| |
| AvbIOResult AvbReadFromPartition(AvbOps *Ops, const char *Partition, int64_t ReadOffset, |
| size_t NumBytes, void *Buffer, size_t *OutNumRead) |
| { |
| AvbIOResult Result = AVB_IO_RESULT_OK; |
| EFI_STATUS Status = EFI_SUCCESS; |
| VOID *Page = NULL; |
| UINT32 Offset = 0; |
| UINTN ptn = 0; |
| UINT32 PageSize = 0; |
| UINT32 StartBlock = 0; |
| UINT32 LastBlock = 0; |
| UINT32 FullBlock = 0; |
| UINTN StartPageReadSize = 0; |
| int index = INVALID_PTN; |
| |
| if (Partition == NULL || Buffer == NULL || OutNumRead == NULL || NumBytes <= 0) { |
| dprintf(CRITICAL, "bad input paramaters\n"); |
| Result = AVB_IO_RESULT_ERROR_IO; |
| goto out; |
| } |
| *OutNumRead = 0; |
| |
| if (!strncmp(Partition,"boot",strlen("boot"))) { |
| /* API returns previously loaded Boot Image buffer address and size */ |
| get_boot_image_info(Buffer, OutNumRead, "boot"); |
| return AVB_IO_RESULT_OK; |
| } |
| |
| index = partition_get_index(Partition); |
| ptn = partition_get_offset(index); |
| |
| if (ReadOffset < 0) { |
| if ((-ReadOffset) > ptn) { |
| dprintf(CRITICAL, |
| "Negative Offset outside range.\n"); |
| Result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| goto out; |
| } |
| Offset = ptn - (-ReadOffset); |
| dprintf(DEBUG, |
| "negative Offset (%lld) converted to (%u) \n", ReadOffset, Offset); |
| } else { |
| // check int64_t to UINT32 converstion? |
| Offset = ReadOffset; |
| } |
| |
| if (Offset > ptn) { |
| dprintf(CRITICAL, "Offset outside range.\n"); |
| Result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| goto out; |
| } |
| |
| if (NumBytes > ptn - Offset) { |
| NumBytes = ptn - Offset; |
| } |
| |
| dprintf(CRITICAL, |
| "read from %s, 0x%x bytes at Offset 0x%x, partition size %lu\n", |
| Partition, NumBytes, Offset, ptn); |
| |
| /* |NumBytes| and or |Offset| can be unaligned to block size/page size. |
| */ |
| //PageSize = mmc_get_device_blocksize(); |
| PageSize = get_page_size(); |
| Page = avb_malloc(PageSize); |
| if (Page == NULL) { |
| dprintf(CRITICAL, "Allocate for partial read failed!"); |
| Result = AVB_IO_RESULT_ERROR_OOM; |
| goto out; |
| } |
| |
| StartBlock = Offset / PageSize; |
| LastBlock = (NumBytes + Offset) / PageSize; |
| FullBlock = StartBlock; |
| StartPageReadSize = 0; |
| |
| if (Offset % PageSize != 0) { |
| /* Offset not aligned to PageSize*/ |
| UINT32 StartPageReadOffset = Offset - (StartBlock * PageSize); |
| |
| if (StartBlock == LastBlock) { |
| /* Offset & Offset + NumBytes are in same block */ |
| StartPageReadSize = NumBytes; |
| } else { |
| StartPageReadSize = PageSize - StartPageReadOffset; |
| FullBlock++; |
| } |
| |
| dprintf(DEBUG, |
| "StartBlock 0x%x, ReadOffset 0x%x, read_size 0x%lx\n", |
| StartBlock, StartPageReadOffset, StartPageReadSize); |
| if (StartPageReadSize <= 0 || StartPageReadOffset >= PageSize || |
| StartPageReadSize > PageSize - StartPageReadOffset || |
| StartPageReadSize > NumBytes) { |
| dprintf(CRITICAL, |
| "StartBlock 0x%x, ReadOffset 0x%x, read_size " |
| "0x%lx outside range.\n", |
| StartBlock, StartPageReadOffset, StartPageReadSize); |
| Result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| goto out; |
| } |
| |
| Status = mmc_read(ptn, Page, PageSize); |
| if (Status == EFI_SUCCESS) { |
| avb_memcpy(Buffer, Page + StartPageReadOffset, StartPageReadSize); |
| *OutNumRead += StartPageReadSize; |
| } else { |
| *OutNumRead = 0; |
| dprintf(CRITICAL, "ReadBlocks failed %d\n", Status); |
| goto out; |
| } |
| } |
| |
| if (*OutNumRead < NumBytes && (NumBytes + Offset) % PageSize != 0) { |
| /* NumBytes + Offset not aligned to PageSize*/ |
| /* Offset for last block is always zero, start at Page boundary |
| */ |
| UINT32 LastPageReadOffset = 0; |
| UINTN ReadOffset2 = (LastBlock * PageSize); |
| UINTN LastPageReadSize = (Offset + NumBytes) - ReadOffset2; |
| |
| dprintf(DEBUG, |
| "LastBlock 0x%x, ReadOffset 0x%x, read_size 0x%lx\n", |
| LastBlock, LastPageReadOffset, LastPageReadSize); |
| |
| if (LastPageReadSize <= 0 || LastPageReadSize >= PageSize || |
| LastPageReadSize > (NumBytes - *OutNumRead)) { |
| dprintf(CRITICAL, |
| "LastBlock 0x%x, ReadOffset 0x%x, read_size " |
| "0x%lx outside range.\n", |
| LastBlock, LastPageReadOffset, LastPageReadSize); |
| Result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| goto out; |
| } |
| |
| Status = mmc_read(ptn + ReadOffset2, Page, PageSize); |
| if (Status == EFI_SUCCESS) { |
| avb_memcpy(Buffer + (NumBytes - LastPageReadSize), Page, |
| LastPageReadSize); |
| *OutNumRead += LastPageReadSize; |
| } else { |
| *OutNumRead = 0; |
| dprintf(CRITICAL, "ReadBlocks failed %d\n", Status); |
| goto out; |
| } |
| } |
| |
| if (*OutNumRead < NumBytes) { |
| /* full block reads */ |
| UINTN FillPageReadSize = NumBytes - *OutNumRead; |
| |
| if ((FillPageReadSize % PageSize) != 0 || |
| (NumBytes - StartPageReadSize) < FillPageReadSize) { |
| dprintf(CRITICAL, |
| "FullBlock 0x%x, ReadOffset 0x%x, read_size " |
| "0x%lx outside range.\n", |
| FullBlock, 0, FillPageReadSize); |
| Result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; |
| goto out; |
| } |
| dprintf(SPEW, |
| "FullBlock 0x%x, ReadOffset 0x%x, read_size " |
| "0x%lx outside range. StartPageReadSize %#lx PageSize %d ptn %#lx Buffer %p\n", |
| FullBlock, 0, FillPageReadSize, StartPageReadSize, PageSize, ptn, Buffer); |
| Status = mmc_read(ptn + FullBlock * PageSize, Buffer + StartPageReadSize, |
| FillPageReadSize); |
| if (Status == EFI_SUCCESS) { |
| *OutNumRead += FillPageReadSize; |
| } else { |
| *OutNumRead = 0; |
| dprintf(CRITICAL, "ReadBlocks failed %d\n", Status); |
| goto out; |
| } |
| } |
| out: |
| if (Page != NULL) { |
| avb_free(Page); |
| } |
| |
| return Result; |
| } |
| |
| AvbIOResult AvbWriteToPartition(AvbOps *Ops, const char *Partition, int64_t Offset, |
| size_t NumBytes, const void *Buffer) |
| { |
| /* unsupported api */ |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| AvbIOResult |
| AvbValidateVbmetaPublicKey(AvbOps *Ops, const uint8_t *PublicKeyData, |
| size_t PublicKeyLength, const uint8_t *PublicKeyMetadata, |
| size_t PublicKeyMetadataLength, bool *OutIsTrusted) |
| { |
| UINT8 *UserKeyBuffer = NULL; |
| UINT32 UserKeyLength = 0; |
| EFI_STATUS Status = EFI_SUCCESS; |
| AvbOpsUserData *UserData = NULL; |
| |
| dprintf(DEBUG, "ValidateVbmetaPublicKey PublicKeyLength %d, " |
| "PublicKeyMetadataLength %d\n", |
| PublicKeyLength, PublicKeyMetadataLength); |
| |
| if (Ops == NULL || OutIsTrusted == NULL || PublicKeyData == NULL) { |
| dprintf(CRITICAL, "Invalid parameters\n"); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| Status = get_userkey(&UserKeyBuffer, &UserKeyLength); |
| if (Status != EFI_SUCCESS) { |
| dprintf(CRITICAL, "get_userkey failed\n"); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| UserData = (AvbOpsUserData *)Ops->user_data; |
| UserData->IsUserKey = FALSE; |
| |
| if (PublicKeyLength == UserKeyLength && |
| memcmp(PublicKeyData, UserKeyBuffer, PublicKeyLength) == 0) { |
| *OutIsTrusted = true; |
| UserData->IsUserKey = TRUE; |
| } else if (PublicKeyLength == ARRAY_SIZE(OEMPublicKey) && |
| memcmp(PublicKeyData, OEMPublicKey, PublicKeyLength) == 0) { |
| *OutIsTrusted = true; |
| } else { |
| *OutIsTrusted = false; |
| memset(UserData->PublicKey, 0, ARRAY_SIZE(UserData->PublicKey)); |
| UserData->PublicKeyLen = 0; |
| } |
| |
| if (*OutIsTrusted == true) { |
| if (PublicKeyLength > ARRAY_SIZE(UserData->PublicKey)) { |
| dprintf(CRITICAL, "ValidateVbmetaPublicKey: " |
| "public key length too large %d\n", |
| PublicKeyLength); |
| return AVB_IO_RESULT_ERROR_OOM; |
| } |
| memcpy(UserData->PublicKey, PublicKeyData, PublicKeyLength); |
| UserData->PublicKeyLen = PublicKeyLength; |
| } |
| dprintf(DEBUG, |
| "ValidateVbmetaPublicKey OutIsTrusted %d, UserKey %d\n", |
| *OutIsTrusted, UserData->IsUserKey); |
| return AVB_IO_RESULT_OK; |
| } |
| |
| |
| AvbIOResult AvbReadRollbackIndex(AvbOps *Ops, size_t RollbackIndexLocation, |
| uint64_t *OutRollbackIndex) |
| { |
| |
| EFI_STATUS Status = read_rollback_index(RollbackIndexLocation, OutRollbackIndex); |
| |
| if (Status != EFI_SUCCESS) { |
| dprintf(CRITICAL, "ReadRollbackIndex failed! %d\n", Status); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| dprintf(DEBUG, |
| "ReadRollbackIndex Location %zu, RollbackIndex %llu\n", |
| RollbackIndexLocation, *OutRollbackIndex); |
| return AVB_IO_RESULT_OK; |
| } |
| |
| AvbIOResult |
| AvbWriteRollbackIndex(AvbOps *Ops, size_t RollbackIndexLocation, uint64_t RollbackIndex) |
| { |
| EFI_STATUS Status = EFI_SUCCESS; |
| BOOLEAN UpdateRollbackIndex = FALSE; |
| AvbOpsUserData *UserData = NULL; |
| |
| dprintf(DEBUG, |
| "WriteRollbackIndex Location %zu, RollbackIndex %llu\n", |
| RollbackIndexLocation, RollbackIndex); |
| |
| UserData = (AvbOpsUserData *)Ops->user_data; |
| if(UserData->IsMultiSlot) { |
| /* Update rollback if the current slot is successful */ |
| if (IsCurrentSlotSuccessful()) { |
| UpdateRollbackIndex = TRUE; |
| } else { |
| UpdateRollbackIndex = FALSE; |
| dprintf(DEBUG, "Not updating rollback index as current " |
| "slot is unbootable\n"); |
| } |
| } else { |
| /* When Multislot is disabled, always update*/ |
| UpdateRollbackIndex = TRUE; |
| } |
| |
| if(UpdateRollbackIndex == TRUE) { |
| dprintf(INFO, |
| "Updating rollback index %llu, for location %zu\n", |
| RollbackIndex, RollbackIndexLocation); |
| Status = write_rollback_index(RollbackIndexLocation, RollbackIndex); |
| if (Status != EFI_SUCCESS) { |
| dprintf(CRITICAL, "ReadRollbackIndex failed! %d\n", Status); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| } |
| return AVB_IO_RESULT_OK; |
| } |
| |
| AvbIOResult AvbReadIsDeviceUnlocked(AvbOps *Ops, bool *OutIsUnlocked) |
| { |
| if (OutIsUnlocked == NULL) { |
| dprintf(CRITICAL, "bad input paramaters\n"); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| *OutIsUnlocked = !is_device_locked(); |
| return AVB_IO_RESULT_OK; |
| } |
| |
| static VOID GuidToHex(CHAR8 *Buf, EFI_GUID *Guid) |
| { |
| CHAR8 HexDigits[17] = "0123456789abcdef"; |
| |
| Buf[0] = HexDigits[(Guid->Data1 >> 28) & 0x0f]; |
| Buf[1] = HexDigits[(Guid->Data1 >> 24) & 0x0f]; |
| Buf[2] = HexDigits[(Guid->Data1 >> 20) & 0x0f]; |
| Buf[3] = HexDigits[(Guid->Data1 >> 16) & 0x0f]; |
| Buf[4] = HexDigits[(Guid->Data1 >> 12) & 0x0f]; |
| Buf[5] = HexDigits[(Guid->Data1 >> 8) & 0x0f]; |
| Buf[6] = HexDigits[(Guid->Data1 >> 4) & 0x0f]; |
| Buf[7] = HexDigits[(Guid->Data1 >> 0) & 0x0f]; |
| Buf[8] = '-'; |
| Buf[9] = HexDigits[(Guid->Data2 >> 12) & 0x0f]; |
| Buf[10] = HexDigits[(Guid->Data2 >> 8) & 0x0f]; |
| Buf[11] = HexDigits[(Guid->Data2 >> 4) & 0x0f]; |
| Buf[12] = HexDigits[(Guid->Data2 >> 0) & 0x0f]; |
| Buf[13] = '-'; |
| Buf[14] = HexDigits[(Guid->Data3 >> 12) & 0x0f]; |
| Buf[15] = HexDigits[(Guid->Data3 >> 8) & 0x0f]; |
| Buf[16] = HexDigits[(Guid->Data3 >> 4) & 0x0f]; |
| Buf[17] = HexDigits[(Guid->Data3 >> 0) & 0x0f]; |
| Buf[18] = '-'; |
| Buf[19] = HexDigits[(Guid->Data4[0] >> 4) & 0x0f]; |
| Buf[20] = HexDigits[(Guid->Data4[0] >> 0) & 0x0f]; |
| Buf[21] = HexDigits[(Guid->Data4[1] >> 4) & 0x0f]; |
| Buf[22] = HexDigits[(Guid->Data4[1] >> 0) & 0x0f]; |
| Buf[23] = '-'; |
| Buf[24] = HexDigits[(Guid->Data4[2] >> 4) & 0x0f]; |
| Buf[25] = HexDigits[(Guid->Data4[2] >> 0) & 0x0f]; |
| Buf[26] = HexDigits[(Guid->Data4[3] >> 4) & 0x0f]; |
| Buf[27] = HexDigits[(Guid->Data4[3] >> 0) & 0x0f]; |
| Buf[28] = HexDigits[(Guid->Data4[4] >> 4) & 0x0f]; |
| Buf[29] = HexDigits[(Guid->Data4[4] >> 0) & 0x0f]; |
| Buf[30] = HexDigits[(Guid->Data4[5] >> 4) & 0x0f]; |
| Buf[31] = HexDigits[(Guid->Data4[5] >> 0) & 0x0f]; |
| Buf[32] = HexDigits[(Guid->Data4[6] >> 4) & 0x0f]; |
| Buf[33] = HexDigits[(Guid->Data4[6] >> 0) & 0x0f]; |
| Buf[34] = HexDigits[(Guid->Data4[7] >> 4) & 0x0f]; |
| Buf[35] = HexDigits[(Guid->Data4[7] >> 0) & 0x0f]; |
| Buf[36] = '\0'; |
| } |
| |
| AvbIOResult AvbGetUniqueGuidForPartition(AvbOps *Ops, const char *PartitionName, |
| char *GuidBuf, size_t GuidBufSize) |
| { |
| EFI_STATUS Status = EFI_SUCCESS; |
| char unique_partition_guid[UNIQUE_PARTITION_GUID_SIZE]; |
| CHAR16 UnicodePartition[MAX_GPT_NAME_SIZE] = {0}; |
| |
| Status = get_unique_guid(PartitionName, unique_partition_guid); |
| if (Status) { |
| dprintf(CRITICAL, |
| "get_unique_guid: No partition entry for %s\n", |
| PartitionName); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| if ((strlen(PartitionName) + 1) > ARRAY_SIZE(UnicodePartition)) { |
| dprintf(CRITICAL, "AvbGetUniqueGuidForPartition: Partition " |
| "%s, name too large\n", |
| PartitionName); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| GuidToHex(GuidBuf, (EFI_GUID *)unique_partition_guid); |
| dprintf(DEBUG, "%s uuid: %s\n", PartitionName, GuidBuf); |
| |
| return AVB_IO_RESULT_OK; |
| } |
| |
| AvbIOResult AvbGetSizeOfPartition(AvbOps *Ops, const char *Partition, uint64_t *OutSizeNumBytes) |
| { |
| AvbIOResult Result = AVB_IO_RESULT_OK; |
| int index; |
| |
| if (Ops == NULL || Partition == NULL || OutSizeNumBytes == NULL) { |
| dprintf(CRITICAL, |
| "AvbGetSizeOfPartition invalid parameter pointers\n"); |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| |
| index = partition_get_index(Partition); |
| *OutSizeNumBytes = (uint64_t)partition_get_size(index); |
| if (*OutSizeNumBytes == 0) |
| return AVB_IO_RESULT_ERROR_IO; |
| |
| return Result; |
| } |
| |
| AvbOps *AvbOpsNew(VOID *UserData) |
| { |
| AvbOps *Ops = avb_calloc(sizeof(AvbOps)); |
| if (Ops == NULL) { |
| dprintf(CRITICAL, "Error allocating memory for AvbOps.\n"); |
| goto out; |
| } |
| |
| Ops->user_data = UserData; |
| Ops->read_from_partition = AvbReadFromPartition; |
| Ops->write_to_partition = AvbWriteToPartition; |
| Ops->validate_vbmeta_public_key = AvbValidateVbmetaPublicKey; |
| Ops->read_rollback_index = AvbReadRollbackIndex; |
| Ops->write_rollback_index = AvbWriteRollbackIndex; |
| Ops->read_is_device_unlocked = AvbReadIsDeviceUnlocked; |
| Ops->get_unique_guid_for_partition = AvbGetUniqueGuidForPartition; |
| Ops->get_size_of_partition = AvbGetSizeOfPartition; |
| |
| out: |
| return Ops; |
| } |
| |
| VOID AvbOpsFree(AvbOps *Ops) |
| { |
| if (Ops != NULL) { |
| avb_free(Ops); |
| } |
| } |