1201b66b7SHaojian Zhuang /* 217a261deSlaurenw-arm * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved. 3201b66b7SHaojian Zhuang * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5201b66b7SHaojian Zhuang */ 6201b66b7SHaojian Zhuang 7201b66b7SHaojian Zhuang #include <assert.h> 84ef449c1SManish Pandey #include <inttypes.h> 939b6cc66SAntonio Nino Diaz #include <stdio.h> 10201b66b7SHaojian Zhuang #include <string.h> 11201b66b7SHaojian Zhuang 1209d40e0eSAntonio Nino Diaz #include <common/debug.h> 13a283d19fSRohit Ner #include <common/tf_crc32.h> 1409d40e0eSAntonio Nino Diaz #include <drivers/io/io_storage.h> 153cb10655SSughosh Ganu #include <drivers/partition/efi.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/partition/partition.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/partition/gpt.h> 1809d40e0eSAntonio Nino Diaz #include <drivers/partition/mbr.h> 1909d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 2009d40e0eSAntonio Nino Diaz 21f8631f51SHaojian Zhuang static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; 2298228529SFlorian La Roche static partition_entry_list_t list; 23201b66b7SHaojian Zhuang 24201b66b7SHaojian Zhuang #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 25201b66b7SHaojian Zhuang static void dump_entries(int num) 26201b66b7SHaojian Zhuang { 27201b66b7SHaojian Zhuang char name[EFI_NAMELEN]; 28201b66b7SHaojian Zhuang int i, j, len; 29201b66b7SHaojian Zhuang 30201b66b7SHaojian Zhuang VERBOSE("Partition table with %d entries:\n", num); 31201b66b7SHaojian Zhuang for (i = 0; i < num; i++) { 3239b6cc66SAntonio Nino Diaz len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 33201b66b7SHaojian Zhuang for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 34201b66b7SHaojian Zhuang name[len + j] = ' '; 35201b66b7SHaojian Zhuang } 36201b66b7SHaojian Zhuang name[EFI_NAMELEN - 1] = '\0'; 374ef449c1SManish Pandey VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start, 38201b66b7SHaojian Zhuang list.list[i].start + list.list[i].length - 4); 39201b66b7SHaojian Zhuang } 40201b66b7SHaojian Zhuang } 41201b66b7SHaojian Zhuang #else 42201b66b7SHaojian Zhuang #define dump_entries(num) ((void)num) 43201b66b7SHaojian Zhuang #endif 44201b66b7SHaojian Zhuang 45201b66b7SHaojian Zhuang /* 46201b66b7SHaojian Zhuang * Load the first sector that carries MBR header. 47201b66b7SHaojian Zhuang * The MBR boot signature should be always valid whether it's MBR or GPT. 48201b66b7SHaojian Zhuang */ 49201b66b7SHaojian Zhuang static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 50201b66b7SHaojian Zhuang { 51201b66b7SHaojian Zhuang size_t bytes_read; 52201b66b7SHaojian Zhuang int result; 53fce8a70eSGovindraj Raja mbr_entry_t *tmp; 54201b66b7SHaojian Zhuang 55201b66b7SHaojian Zhuang assert(mbr_entry != NULL); 56201b66b7SHaojian Zhuang /* MBR partition table is in LBA0. */ 57201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 58201b66b7SHaojian Zhuang if (result != 0) { 590f23e7ebSGovindraj Raja VERBOSE("Failed to seek (%i)\n", result); 60201b66b7SHaojian Zhuang return result; 61201b66b7SHaojian Zhuang } 62201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)&mbr_sector, 63f8631f51SHaojian Zhuang PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 64fce8a70eSGovindraj Raja if ((result != 0) || (bytes_read != PLAT_PARTITION_BLOCK_SIZE)) { 650f23e7ebSGovindraj Raja VERBOSE("Failed to read data (%i)\n", result); 66201b66b7SHaojian Zhuang return result; 67201b66b7SHaojian Zhuang } 68201b66b7SHaojian Zhuang 69201b66b7SHaojian Zhuang /* Check MBR boot signature. */ 70f8631f51SHaojian Zhuang if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 71f8631f51SHaojian Zhuang (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 720f23e7ebSGovindraj Raja VERBOSE("MBR boot signature failure\n"); 73201b66b7SHaojian Zhuang return -ENOENT; 74201b66b7SHaojian Zhuang } 75fce8a70eSGovindraj Raja 76fce8a70eSGovindraj Raja tmp = (mbr_entry_t *)(&mbr_sector[MBR_PRIMARY_ENTRY_OFFSET]); 77fce8a70eSGovindraj Raja 78fce8a70eSGovindraj Raja if (tmp->first_lba != 1) { 790f23e7ebSGovindraj Raja VERBOSE("MBR header may have an invalid first LBA\n"); 80fce8a70eSGovindraj Raja return -EINVAL; 81fce8a70eSGovindraj Raja } 82fce8a70eSGovindraj Raja 83fce8a70eSGovindraj Raja if ((tmp->sector_nums == 0) || (tmp->sector_nums == UINT32_MAX)) { 840f23e7ebSGovindraj Raja VERBOSE("MBR header entry has an invalid number of sectors\n"); 85fce8a70eSGovindraj Raja return -EINVAL; 86fce8a70eSGovindraj Raja } 87fce8a70eSGovindraj Raja 88fce8a70eSGovindraj Raja memcpy(mbr_entry, tmp, sizeof(mbr_entry_t)); 89201b66b7SHaojian Zhuang return 0; 90201b66b7SHaojian Zhuang } 91201b66b7SHaojian Zhuang 92201b66b7SHaojian Zhuang /* 93a283d19fSRohit Ner * Load GPT header and check the GPT signature and header CRC. 948aabea33SPaul Beesley * If partition numbers could be found, check & update it. 95201b66b7SHaojian Zhuang */ 96fce8a70eSGovindraj Raja static int load_gpt_header(uintptr_t image_handle, size_t header_offset, 9717a261deSlaurenw-arm gpt_header_t *header) 98201b66b7SHaojian Zhuang { 99201b66b7SHaojian Zhuang size_t bytes_read; 100201b66b7SHaojian Zhuang int result; 101a283d19fSRohit Ner uint32_t header_crc, calc_crc; 102201b66b7SHaojian Zhuang 103fce8a70eSGovindraj Raja result = io_seek(image_handle, IO_SEEK_SET, header_offset); 104201b66b7SHaojian Zhuang if (result != 0) { 1050f23e7ebSGovindraj Raja VERBOSE("Failed to seek into the GPT image at offset (%zu)\n", 106ad2dd658SGovindraj Raja header_offset); 107201b66b7SHaojian Zhuang return result; 108201b66b7SHaojian Zhuang } 10917a261deSlaurenw-arm result = io_read(image_handle, (uintptr_t)header, 110201b66b7SHaojian Zhuang sizeof(gpt_header_t), &bytes_read); 111201b66b7SHaojian Zhuang if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 1120f23e7ebSGovindraj Raja VERBOSE("GPT header read error(%i) or read mismatch occurred," 113ad2dd658SGovindraj Raja "expected(%zu) and actual(%zu)\n", result, 114ad2dd658SGovindraj Raja sizeof(gpt_header_t), bytes_read); 115201b66b7SHaojian Zhuang return result; 116201b66b7SHaojian Zhuang } 11717a261deSlaurenw-arm if (memcmp(header->signature, GPT_SIGNATURE, 11817a261deSlaurenw-arm sizeof(header->signature)) != 0) { 1190f23e7ebSGovindraj Raja VERBOSE("GPT header signature failure\n"); 120201b66b7SHaojian Zhuang return -EINVAL; 121201b66b7SHaojian Zhuang } 122201b66b7SHaojian Zhuang 123a283d19fSRohit Ner /* 124a283d19fSRohit Ner * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is 125a283d19fSRohit Ner * computed by setting this field to 0, and computing the 126a283d19fSRohit Ner * 32-bit CRC for HeaderSize bytes. 127a283d19fSRohit Ner */ 12817a261deSlaurenw-arm header_crc = header->header_crc; 12917a261deSlaurenw-arm header->header_crc = 0U; 130a283d19fSRohit Ner 13117a261deSlaurenw-arm calc_crc = tf_crc32(0U, (uint8_t *)header, sizeof(gpt_header_t)); 132a283d19fSRohit Ner if (header_crc != calc_crc) { 133a283d19fSRohit Ner ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n", 134a283d19fSRohit Ner header_crc, calc_crc); 135a283d19fSRohit Ner return -EINVAL; 136a283d19fSRohit Ner } 137a283d19fSRohit Ner 13817a261deSlaurenw-arm header->header_crc = header_crc; 139a283d19fSRohit Ner 140201b66b7SHaojian Zhuang /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 14117a261deSlaurenw-arm list.entry_count = header->list_num; 142201b66b7SHaojian Zhuang if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 143201b66b7SHaojian Zhuang list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 144201b66b7SHaojian Zhuang } 145fce8a70eSGovindraj Raja 146201b66b7SHaojian Zhuang return 0; 147201b66b7SHaojian Zhuang } 148201b66b7SHaojian Zhuang 149ad2dd658SGovindraj Raja /* 150ad2dd658SGovindraj Raja * Load a single MBR entry based on details from MBR header. 151ad2dd658SGovindraj Raja */ 15230f833caSLoh Tien Hock static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, 15330f833caSLoh Tien Hock int part_number) 15430f833caSLoh Tien Hock { 15530f833caSLoh Tien Hock size_t bytes_read; 15630f833caSLoh Tien Hock uintptr_t offset; 15730f833caSLoh Tien Hock int result; 15830f833caSLoh Tien Hock 15930f833caSLoh Tien Hock assert(mbr_entry != NULL); 16030f833caSLoh Tien Hock /* MBR partition table is in LBA0. */ 16130f833caSLoh Tien Hock result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 16230f833caSLoh Tien Hock if (result != 0) { 1630f23e7ebSGovindraj Raja VERBOSE("Failed to seek (%i)\n", result); 16430f833caSLoh Tien Hock return result; 16530f833caSLoh Tien Hock } 16630f833caSLoh Tien Hock result = io_read(image_handle, (uintptr_t)&mbr_sector, 167f8631f51SHaojian Zhuang PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 16830f833caSLoh Tien Hock if (result != 0) { 1690f23e7ebSGovindraj Raja VERBOSE("Failed to read data (%i)\n", result); 17030f833caSLoh Tien Hock return result; 17130f833caSLoh Tien Hock } 17230f833caSLoh Tien Hock 17330f833caSLoh Tien Hock /* Check MBR boot signature. */ 174f8631f51SHaojian Zhuang if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 175f8631f51SHaojian Zhuang (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 1760f23e7ebSGovindraj Raja VERBOSE("MBR Entry boot signature failure\n"); 17730f833caSLoh Tien Hock return -ENOENT; 17830f833caSLoh Tien Hock } 17930f833caSLoh Tien Hock offset = (uintptr_t)&mbr_sector + 18030f833caSLoh Tien Hock MBR_PRIMARY_ENTRY_OFFSET + 18130f833caSLoh Tien Hock MBR_PRIMARY_ENTRY_SIZE * part_number; 18230f833caSLoh Tien Hock memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 18330f833caSLoh Tien Hock 18430f833caSLoh Tien Hock return 0; 18530f833caSLoh Tien Hock } 18630f833caSLoh Tien Hock 187ad2dd658SGovindraj Raja /* 188ad2dd658SGovindraj Raja * Load MBR entries based on max number of partition entries. 189ad2dd658SGovindraj Raja */ 19030f833caSLoh Tien Hock static int load_mbr_entries(uintptr_t image_handle) 19130f833caSLoh Tien Hock { 19230f833caSLoh Tien Hock mbr_entry_t mbr_entry; 193*ce574314Slaurenw-arm unsigned int i; 19430f833caSLoh Tien Hock 19530f833caSLoh Tien Hock list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; 19630f833caSLoh Tien Hock 197*ce574314Slaurenw-arm for (i = 0U; i < list.entry_count; i++) { 19830f833caSLoh Tien Hock load_mbr_entry(image_handle, &mbr_entry, i); 19930f833caSLoh Tien Hock list.list[i].start = mbr_entry.first_lba * 512; 20030f833caSLoh Tien Hock list.list[i].length = mbr_entry.sector_nums * 512; 20130f833caSLoh Tien Hock list.list[i].name[0] = mbr_entry.type; 20230f833caSLoh Tien Hock } 20330f833caSLoh Tien Hock 20430f833caSLoh Tien Hock return 0; 20530f833caSLoh Tien Hock } 20630f833caSLoh Tien Hock 207ad2dd658SGovindraj Raja /* 208ad2dd658SGovindraj Raja * Try to read and load a single GPT entry. 209ad2dd658SGovindraj Raja */ 210201b66b7SHaojian Zhuang static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 211201b66b7SHaojian Zhuang { 212ad2dd658SGovindraj Raja size_t bytes_read = 0U; 213201b66b7SHaojian Zhuang int result; 214201b66b7SHaojian Zhuang 215201b66b7SHaojian Zhuang assert(entry != NULL); 216201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 217201b66b7SHaojian Zhuang &bytes_read); 218ad2dd658SGovindraj Raja if ((result != 0) || (sizeof(gpt_entry_t) != bytes_read)) { 2190f23e7ebSGovindraj Raja VERBOSE("GPT Entry read error(%i) or read mismatch occurred," 220ad2dd658SGovindraj Raja "expected(%zu) and actual(%zu)\n", result, 221ad2dd658SGovindraj Raja sizeof(gpt_entry_t), bytes_read); 222201b66b7SHaojian Zhuang return -EINVAL; 223ad2dd658SGovindraj Raja } 224ad2dd658SGovindraj Raja 225201b66b7SHaojian Zhuang return result; 226201b66b7SHaojian Zhuang } 227201b66b7SHaojian Zhuang 228ad2dd658SGovindraj Raja /* 229ad2dd658SGovindraj Raja * Retrieve each entry in the partition table, parse the data from each 230ad2dd658SGovindraj Raja * entry and store them in the list of partition table entries. 231ad2dd658SGovindraj Raja */ 23217a261deSlaurenw-arm static int load_partition_gpt(uintptr_t image_handle, gpt_header_t header) 233201b66b7SHaojian Zhuang { 23417a261deSlaurenw-arm const signed long long gpt_entry_offset = LBA(header.part_lba); 235201b66b7SHaojian Zhuang gpt_entry_t entry; 2367a9e9f6eSlaurenw-arm int result; 2377a9e9f6eSlaurenw-arm unsigned int i; 2387a9e9f6eSlaurenw-arm uint32_t calc_crc = 0U; 239201b66b7SHaojian Zhuang 240ad2dd658SGovindraj Raja result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset); 241ad2dd658SGovindraj Raja if (result != 0) { 2420f23e7ebSGovindraj Raja VERBOSE("Failed to seek (%i), Failed loading GPT partition" 243ad2dd658SGovindraj Raja "table entries\n", result); 244ad2dd658SGovindraj Raja return result; 245ad2dd658SGovindraj Raja } 246ad2dd658SGovindraj Raja 247*ce574314Slaurenw-arm for (i = 0U; i < list.entry_count; i++) { 248201b66b7SHaojian Zhuang result = load_gpt_entry(image_handle, &entry); 249ad2dd658SGovindraj Raja if (result != 0) { 2507a9e9f6eSlaurenw-arm VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n", 251ad2dd658SGovindraj Raja i, result); 252ad2dd658SGovindraj Raja return result; 253ad2dd658SGovindraj Raja } 254ad2dd658SGovindraj Raja 255201b66b7SHaojian Zhuang result = parse_gpt_entry(&entry, &list.list[i]); 256201b66b7SHaojian Zhuang if (result != 0) { 2577a9e9f6eSlaurenw-arm result = io_seek(image_handle, IO_SEEK_SET, 2587a9e9f6eSlaurenw-arm (gpt_entry_offset + (i * sizeof(gpt_entry_t)))); 2597a9e9f6eSlaurenw-arm if (result != 0) { 2607a9e9f6eSlaurenw-arm VERBOSE("Failed to seek (%i)\n", result); 2617a9e9f6eSlaurenw-arm return result; 2627a9e9f6eSlaurenw-arm } 263201b66b7SHaojian Zhuang break; 264201b66b7SHaojian Zhuang } 2657a9e9f6eSlaurenw-arm 2667a9e9f6eSlaurenw-arm /* 2677a9e9f6eSlaurenw-arm * Calculate CRC of Partition entry array to compare with CRC 2687a9e9f6eSlaurenw-arm * value in header 2697a9e9f6eSlaurenw-arm */ 2707a9e9f6eSlaurenw-arm calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t)); 271201b66b7SHaojian Zhuang } 272201b66b7SHaojian Zhuang if (i == 0) { 2730f23e7ebSGovindraj Raja VERBOSE("No Valid GPT Entries found\n"); 274201b66b7SHaojian Zhuang return -EINVAL; 275201b66b7SHaojian Zhuang } 2767a9e9f6eSlaurenw-arm 277201b66b7SHaojian Zhuang /* 278201b66b7SHaojian Zhuang * Only records the valid partition number that is loaded from 279201b66b7SHaojian Zhuang * partition table. 280201b66b7SHaojian Zhuang */ 281201b66b7SHaojian Zhuang list.entry_count = i; 282201b66b7SHaojian Zhuang dump_entries(list.entry_count); 283201b66b7SHaojian Zhuang 2847a9e9f6eSlaurenw-arm /* 2857a9e9f6eSlaurenw-arm * If there are less valid entries than the possible number of entries 2867a9e9f6eSlaurenw-arm * from the header, continue to load the partition entry table to 2877a9e9f6eSlaurenw-arm * calculate the full CRC in order to check against the partition CRC 2887a9e9f6eSlaurenw-arm * from the header for validation. 2897a9e9f6eSlaurenw-arm */ 2907a9e9f6eSlaurenw-arm for (; i < header.list_num; i++) { 2917a9e9f6eSlaurenw-arm result = load_gpt_entry(image_handle, &entry); 2927a9e9f6eSlaurenw-arm if (result != 0) { 2937a9e9f6eSlaurenw-arm VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n", 2947a9e9f6eSlaurenw-arm i, result); 2957a9e9f6eSlaurenw-arm return result; 2967a9e9f6eSlaurenw-arm } 2977a9e9f6eSlaurenw-arm 2987a9e9f6eSlaurenw-arm calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t)); 2997a9e9f6eSlaurenw-arm } 3007a9e9f6eSlaurenw-arm 3017a9e9f6eSlaurenw-arm if (header.part_crc != calc_crc) { 3027a9e9f6eSlaurenw-arm ERROR("Invalid GPT Partition Array Entry CRC: Expected 0x%x" 3037a9e9f6eSlaurenw-arm " but got 0x%x.\n", header.part_crc, calc_crc); 3047a9e9f6eSlaurenw-arm return -EINVAL; 3057a9e9f6eSlaurenw-arm } 3067a9e9f6eSlaurenw-arm 307201b66b7SHaojian Zhuang return 0; 308201b66b7SHaojian Zhuang } 309201b66b7SHaojian Zhuang 310ad2dd658SGovindraj Raja /* 311ad2dd658SGovindraj Raja * Try retrieving and parsing the backup-GPT header and backup GPT entries. 312ad2dd658SGovindraj Raja * Last 33 blocks contains the backup-GPT entries and header. 313ad2dd658SGovindraj Raja */ 314ad2dd658SGovindraj Raja static int load_backup_gpt(unsigned int image_id, unsigned int sector_nums) 315ad2dd658SGovindraj Raja { 316ad2dd658SGovindraj Raja int result; 31717a261deSlaurenw-arm gpt_header_t header; 318ad2dd658SGovindraj Raja size_t gpt_header_offset; 319ad2dd658SGovindraj Raja uintptr_t dev_handle, image_spec, image_handle; 320ad2dd658SGovindraj Raja io_block_spec_t *block_spec; 321ad2dd658SGovindraj Raja int part_num_entries; 322ad2dd658SGovindraj Raja 323ad2dd658SGovindraj Raja result = plat_get_image_source(image_id, &dev_handle, &image_spec); 324ad2dd658SGovindraj Raja if (result != 0) { 3250f23e7ebSGovindraj Raja VERBOSE("Failed to obtain reference to image id=%u (%i)\n", 326ad2dd658SGovindraj Raja image_id, result); 327ad2dd658SGovindraj Raja return result; 328ad2dd658SGovindraj Raja } 329ad2dd658SGovindraj Raja 330ad2dd658SGovindraj Raja block_spec = (io_block_spec_t *)image_spec; 331ad2dd658SGovindraj Raja /* 332ad2dd658SGovindraj Raja * We need to read 32 blocks of GPT entries and one block of GPT header 333ad2dd658SGovindraj Raja * try mapping only last 33 last blocks from the image to read the 334ad2dd658SGovindraj Raja * Backup-GPT header and its entries. 335ad2dd658SGovindraj Raja */ 336ad2dd658SGovindraj Raja part_num_entries = (PLAT_PARTITION_MAX_ENTRIES / 4); 337ad2dd658SGovindraj Raja /* Move the offset base to LBA-33 */ 338ad2dd658SGovindraj Raja block_spec->offset += LBA(sector_nums - part_num_entries); 339ad2dd658SGovindraj Raja /* 340ad2dd658SGovindraj Raja * Set length as LBA-33, 32 blocks of backup-GPT entries and one 341ad2dd658SGovindraj Raja * block of backup-GPT header. 342ad2dd658SGovindraj Raja */ 343ad2dd658SGovindraj Raja block_spec->length = LBA(part_num_entries + 1); 344ad2dd658SGovindraj Raja 345ad2dd658SGovindraj Raja result = io_open(dev_handle, image_spec, &image_handle); 346ad2dd658SGovindraj Raja if (result != 0) { 3470f23e7ebSGovindraj Raja VERBOSE("Failed to access image id (%i)\n", result); 348ad2dd658SGovindraj Raja return result; 349ad2dd658SGovindraj Raja } 350ad2dd658SGovindraj Raja 351ad2dd658SGovindraj Raja INFO("Trying to retrieve back-up GPT header\n"); 352ad2dd658SGovindraj Raja /* Last block is backup-GPT header, after the end of GPT entries */ 353ad2dd658SGovindraj Raja gpt_header_offset = LBA(part_num_entries); 35417a261deSlaurenw-arm result = load_gpt_header(image_handle, gpt_header_offset, &header); 35517a261deSlaurenw-arm if ((result != 0) || (header.part_lba == 0)) { 356ad2dd658SGovindraj Raja ERROR("Failed to retrieve Backup GPT header," 357ad2dd658SGovindraj Raja "Partition maybe corrupted\n"); 358ad2dd658SGovindraj Raja goto out; 359ad2dd658SGovindraj Raja } 360ad2dd658SGovindraj Raja 361ad2dd658SGovindraj Raja /* 362ad2dd658SGovindraj Raja * Note we mapped last 33 blocks(LBA-33), first block here starts with 363ad2dd658SGovindraj Raja * entries while last block was header. 364ad2dd658SGovindraj Raja */ 36517a261deSlaurenw-arm header.part_lba = 0; 36617a261deSlaurenw-arm result = load_partition_gpt(image_handle, header); 367ad2dd658SGovindraj Raja 368ad2dd658SGovindraj Raja out: 369ad2dd658SGovindraj Raja io_close(image_handle); 370ad2dd658SGovindraj Raja return result; 371ad2dd658SGovindraj Raja } 372ad2dd658SGovindraj Raja 373ad2dd658SGovindraj Raja /* 374ad2dd658SGovindraj Raja * Load a GPT partition, Try retrieving and parsing the primary GPT header, 375ad2dd658SGovindraj Raja * if its corrupted try loading backup GPT header and then retrieve list 376ad2dd658SGovindraj Raja * of partition table entries found from the GPT. 377ad2dd658SGovindraj Raja */ 378ad2dd658SGovindraj Raja static int load_primary_gpt(uintptr_t image_handle, unsigned int first_lba) 379ad2dd658SGovindraj Raja { 380ad2dd658SGovindraj Raja int result; 381ad2dd658SGovindraj Raja size_t gpt_header_offset; 38217a261deSlaurenw-arm gpt_header_t header; 383ad2dd658SGovindraj Raja 384ad2dd658SGovindraj Raja /* Try to load Primary GPT header from LBA1 */ 385ad2dd658SGovindraj Raja gpt_header_offset = LBA(first_lba); 38617a261deSlaurenw-arm result = load_gpt_header(image_handle, gpt_header_offset, &header); 38717a261deSlaurenw-arm if ((result != 0) || (header.part_lba == 0)) { 3880f23e7ebSGovindraj Raja VERBOSE("Failed to retrieve Primary GPT header," 389ad2dd658SGovindraj Raja "trying to retrieve back-up GPT header\n"); 390ad2dd658SGovindraj Raja return result; 391ad2dd658SGovindraj Raja } 392ad2dd658SGovindraj Raja 39317a261deSlaurenw-arm return load_partition_gpt(image_handle, header); 394ad2dd658SGovindraj Raja } 395ad2dd658SGovindraj Raja 396ad2dd658SGovindraj Raja /* 397ad2dd658SGovindraj Raja * Load the partition table info based on the image id provided. 398ad2dd658SGovindraj Raja */ 399201b66b7SHaojian Zhuang int load_partition_table(unsigned int image_id) 400201b66b7SHaojian Zhuang { 401201b66b7SHaojian Zhuang uintptr_t dev_handle, image_handle, image_spec = 0; 402201b66b7SHaojian Zhuang mbr_entry_t mbr_entry; 403201b66b7SHaojian Zhuang int result; 404201b66b7SHaojian Zhuang 405201b66b7SHaojian Zhuang result = plat_get_image_source(image_id, &dev_handle, &image_spec); 406201b66b7SHaojian Zhuang if (result != 0) { 4070f23e7ebSGovindraj Raja VERBOSE("Failed to obtain reference to image id=%u (%i)\n", 408201b66b7SHaojian Zhuang image_id, result); 409201b66b7SHaojian Zhuang return result; 410201b66b7SHaojian Zhuang } 411201b66b7SHaojian Zhuang 412201b66b7SHaojian Zhuang result = io_open(dev_handle, image_spec, &image_handle); 413201b66b7SHaojian Zhuang if (result != 0) { 4140f23e7ebSGovindraj Raja VERBOSE("Failed to access image id=%u (%i)\n", image_id, result); 415201b66b7SHaojian Zhuang return result; 416201b66b7SHaojian Zhuang } 417201b66b7SHaojian Zhuang 418201b66b7SHaojian Zhuang result = load_mbr_header(image_handle, &mbr_entry); 419201b66b7SHaojian Zhuang if (result != 0) { 4200f23e7ebSGovindraj Raja VERBOSE("Failed to access image id=%u (%i)\n", image_id, result); 421ad2dd658SGovindraj Raja goto out; 422201b66b7SHaojian Zhuang } 423201b66b7SHaojian Zhuang if (mbr_entry.type == PARTITION_TYPE_GPT) { 424ad2dd658SGovindraj Raja result = load_primary_gpt(image_handle, mbr_entry.first_lba); 425fce8a70eSGovindraj Raja if (result != 0) { 426ad2dd658SGovindraj Raja io_close(image_handle); 427ad2dd658SGovindraj Raja return load_backup_gpt(BKUP_GPT_IMAGE_ID, 428ad2dd658SGovindraj Raja mbr_entry.sector_nums); 429fce8a70eSGovindraj Raja } 430201b66b7SHaojian Zhuang } else { 43130f833caSLoh Tien Hock result = load_mbr_entries(image_handle); 432201b66b7SHaojian Zhuang } 43330f833caSLoh Tien Hock 434ad2dd658SGovindraj Raja out: 435201b66b7SHaojian Zhuang io_close(image_handle); 436201b66b7SHaojian Zhuang return result; 437201b66b7SHaojian Zhuang } 438201b66b7SHaojian Zhuang 439ad2dd658SGovindraj Raja /* 440ad2dd658SGovindraj Raja * Try retrieving a partition table entry based on the name of the partition. 441ad2dd658SGovindraj Raja */ 442201b66b7SHaojian Zhuang const partition_entry_t *get_partition_entry(const char *name) 443201b66b7SHaojian Zhuang { 444*ce574314Slaurenw-arm unsigned int i; 445201b66b7SHaojian Zhuang 446*ce574314Slaurenw-arm for (i = 0U; i < list.entry_count; i++) { 447201b66b7SHaojian Zhuang if (strcmp(name, list.list[i].name) == 0) { 448201b66b7SHaojian Zhuang return &list.list[i]; 449201b66b7SHaojian Zhuang } 450201b66b7SHaojian Zhuang } 451201b66b7SHaojian Zhuang return NULL; 452201b66b7SHaojian Zhuang } 453201b66b7SHaojian Zhuang 454ad2dd658SGovindraj Raja /* 45537e81a60SSughosh Ganu * Try retrieving a partition table entry based on the partition type GUID. 456ad2dd658SGovindraj Raja */ 45737e81a60SSughosh Ganu const partition_entry_t *get_partition_entry_by_type( 45837e81a60SSughosh Ganu const struct efi_guid *type_guid) 459564f5d47SLionel Debieve { 460*ce574314Slaurenw-arm unsigned int i; 461564f5d47SLionel Debieve 462*ce574314Slaurenw-arm for (i = 0U; i < list.entry_count; i++) { 46337e81a60SSughosh Ganu if (guidcmp(type_guid, &list.list[i].type_guid) == 0) { 464564f5d47SLionel Debieve return &list.list[i]; 465564f5d47SLionel Debieve } 466564f5d47SLionel Debieve } 467564f5d47SLionel Debieve 468564f5d47SLionel Debieve return NULL; 469564f5d47SLionel Debieve } 470564f5d47SLionel Debieve 471ad2dd658SGovindraj Raja /* 47237e81a60SSughosh Ganu * Try retrieving a partition table entry based on the unique partition GUID. 473ad2dd658SGovindraj Raja */ 47437e81a60SSughosh Ganu const partition_entry_t *get_partition_entry_by_guid( 47537e81a60SSughosh Ganu const struct efi_guid *part_guid) 4763cb10655SSughosh Ganu { 477*ce574314Slaurenw-arm unsigned int i; 4783cb10655SSughosh Ganu 479*ce574314Slaurenw-arm for (i = 0U; i < list.entry_count; i++) { 48037e81a60SSughosh Ganu if (guidcmp(part_guid, &list.list[i].part_guid) == 0) { 4813cb10655SSughosh Ganu return &list.list[i]; 4823cb10655SSughosh Ganu } 4833cb10655SSughosh Ganu } 4843cb10655SSughosh Ganu 4853cb10655SSughosh Ganu return NULL; 4863cb10655SSughosh Ganu } 4873cb10655SSughosh Ganu 488ad2dd658SGovindraj Raja /* 489ad2dd658SGovindraj Raja * Return entry to the list of partition table entries. 490ad2dd658SGovindraj Raja */ 491201b66b7SHaojian Zhuang const partition_entry_list_t *get_partition_entry_list(void) 492201b66b7SHaojian Zhuang { 493201b66b7SHaojian Zhuang return &list; 494201b66b7SHaojian Zhuang } 495201b66b7SHaojian Zhuang 496ad2dd658SGovindraj Raja /* 497ad2dd658SGovindraj Raja * Try loading partition table info for the given image ID. 498ad2dd658SGovindraj Raja */ 499201b66b7SHaojian Zhuang void partition_init(unsigned int image_id) 500201b66b7SHaojian Zhuang { 501f08460dcSGovindraj Raja int ret; 502f08460dcSGovindraj Raja 503f08460dcSGovindraj Raja ret = load_partition_table(image_id); 504f08460dcSGovindraj Raja if (ret != 0) { 505f08460dcSGovindraj Raja ERROR("Failed to parse partition with image id = %u\n", 506f08460dcSGovindraj Raja image_id); 507f08460dcSGovindraj Raja } 508f08460dcSGovindraj Raja } 509f08460dcSGovindraj Raja 510f08460dcSGovindraj Raja /* 511f08460dcSGovindraj Raja * Load a GPT based image. 512f08460dcSGovindraj Raja */ 513f08460dcSGovindraj Raja int gpt_partition_init(void) 514f08460dcSGovindraj Raja { 515f08460dcSGovindraj Raja return load_partition_table(GPT_IMAGE_ID); 516201b66b7SHaojian Zhuang } 517