1201b66b7SHaojian Zhuang /* 28aabea33SPaul Beesley * Copyright (c) 2016-2019, 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> 1309d40e0eSAntonio Nino Diaz #include <drivers/io/io_storage.h> 14*3cb10655SSughosh Ganu #include <drivers/partition/efi.h> 1509d40e0eSAntonio Nino Diaz #include <drivers/partition/partition.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/partition/gpt.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/partition/mbr.h> 1809d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 1909d40e0eSAntonio Nino Diaz 20f8631f51SHaojian Zhuang static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; 2198228529SFlorian La Roche static partition_entry_list_t list; 22201b66b7SHaojian Zhuang 23201b66b7SHaojian Zhuang #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 24201b66b7SHaojian Zhuang static void dump_entries(int num) 25201b66b7SHaojian Zhuang { 26201b66b7SHaojian Zhuang char name[EFI_NAMELEN]; 27201b66b7SHaojian Zhuang int i, j, len; 28201b66b7SHaojian Zhuang 29201b66b7SHaojian Zhuang VERBOSE("Partition table with %d entries:\n", num); 30201b66b7SHaojian Zhuang for (i = 0; i < num; i++) { 3139b6cc66SAntonio Nino Diaz len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 32201b66b7SHaojian Zhuang for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 33201b66b7SHaojian Zhuang name[len + j] = ' '; 34201b66b7SHaojian Zhuang } 35201b66b7SHaojian Zhuang name[EFI_NAMELEN - 1] = '\0'; 364ef449c1SManish Pandey VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start, 37201b66b7SHaojian Zhuang list.list[i].start + list.list[i].length - 4); 38201b66b7SHaojian Zhuang } 39201b66b7SHaojian Zhuang } 40201b66b7SHaojian Zhuang #else 41201b66b7SHaojian Zhuang #define dump_entries(num) ((void)num) 42201b66b7SHaojian Zhuang #endif 43201b66b7SHaojian Zhuang 44201b66b7SHaojian Zhuang /* 45201b66b7SHaojian Zhuang * Load the first sector that carries MBR header. 46201b66b7SHaojian Zhuang * The MBR boot signature should be always valid whether it's MBR or GPT. 47201b66b7SHaojian Zhuang */ 48201b66b7SHaojian Zhuang static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 49201b66b7SHaojian Zhuang { 50201b66b7SHaojian Zhuang size_t bytes_read; 51201b66b7SHaojian Zhuang uintptr_t offset; 52201b66b7SHaojian Zhuang int result; 53201b66b7SHaojian Zhuang 54201b66b7SHaojian Zhuang assert(mbr_entry != NULL); 55201b66b7SHaojian Zhuang /* MBR partition table is in LBA0. */ 56201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 57201b66b7SHaojian Zhuang if (result != 0) { 58201b66b7SHaojian Zhuang WARN("Failed to seek (%i)\n", result); 59201b66b7SHaojian Zhuang return result; 60201b66b7SHaojian Zhuang } 61201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)&mbr_sector, 62f8631f51SHaojian Zhuang PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 63201b66b7SHaojian Zhuang if (result != 0) { 64201b66b7SHaojian Zhuang WARN("Failed to read data (%i)\n", result); 65201b66b7SHaojian Zhuang return result; 66201b66b7SHaojian Zhuang } 67201b66b7SHaojian Zhuang 68201b66b7SHaojian Zhuang /* Check MBR boot signature. */ 69f8631f51SHaojian Zhuang if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 70f8631f51SHaojian Zhuang (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 71201b66b7SHaojian Zhuang return -ENOENT; 72201b66b7SHaojian Zhuang } 73201b66b7SHaojian Zhuang offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; 74201b66b7SHaojian Zhuang memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 75201b66b7SHaojian Zhuang return 0; 76201b66b7SHaojian Zhuang } 77201b66b7SHaojian Zhuang 78201b66b7SHaojian Zhuang /* 79201b66b7SHaojian Zhuang * Load GPT header and check the GPT signature. 808aabea33SPaul Beesley * If partition numbers could be found, check & update it. 81201b66b7SHaojian Zhuang */ 82201b66b7SHaojian Zhuang static int load_gpt_header(uintptr_t image_handle) 83201b66b7SHaojian Zhuang { 84201b66b7SHaojian Zhuang gpt_header_t header; 85201b66b7SHaojian Zhuang size_t bytes_read; 86201b66b7SHaojian Zhuang int result; 87201b66b7SHaojian Zhuang 88201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); 89201b66b7SHaojian Zhuang if (result != 0) { 90201b66b7SHaojian Zhuang return result; 91201b66b7SHaojian Zhuang } 92201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)&header, 93201b66b7SHaojian Zhuang sizeof(gpt_header_t), &bytes_read); 94201b66b7SHaojian Zhuang if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 95201b66b7SHaojian Zhuang return result; 96201b66b7SHaojian Zhuang } 97201b66b7SHaojian Zhuang if (memcmp(header.signature, GPT_SIGNATURE, 98201b66b7SHaojian Zhuang sizeof(header.signature)) != 0) { 99201b66b7SHaojian Zhuang return -EINVAL; 100201b66b7SHaojian Zhuang } 101201b66b7SHaojian Zhuang 102201b66b7SHaojian Zhuang /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 103201b66b7SHaojian Zhuang list.entry_count = header.list_num; 104201b66b7SHaojian Zhuang if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 105201b66b7SHaojian Zhuang list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 106201b66b7SHaojian Zhuang } 107201b66b7SHaojian Zhuang return 0; 108201b66b7SHaojian Zhuang } 109201b66b7SHaojian Zhuang 11030f833caSLoh Tien Hock static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, 11130f833caSLoh Tien Hock int part_number) 11230f833caSLoh Tien Hock { 11330f833caSLoh Tien Hock size_t bytes_read; 11430f833caSLoh Tien Hock uintptr_t offset; 11530f833caSLoh Tien Hock int result; 11630f833caSLoh Tien Hock 11730f833caSLoh Tien Hock assert(mbr_entry != NULL); 11830f833caSLoh Tien Hock /* MBR partition table is in LBA0. */ 11930f833caSLoh Tien Hock result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 12030f833caSLoh Tien Hock if (result != 0) { 12130f833caSLoh Tien Hock WARN("Failed to seek (%i)\n", result); 12230f833caSLoh Tien Hock return result; 12330f833caSLoh Tien Hock } 12430f833caSLoh Tien Hock result = io_read(image_handle, (uintptr_t)&mbr_sector, 125f8631f51SHaojian Zhuang PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 12630f833caSLoh Tien Hock if (result != 0) { 12730f833caSLoh Tien Hock WARN("Failed to read data (%i)\n", result); 12830f833caSLoh Tien Hock return result; 12930f833caSLoh Tien Hock } 13030f833caSLoh Tien Hock 13130f833caSLoh Tien Hock /* Check MBR boot signature. */ 132f8631f51SHaojian Zhuang if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 133f8631f51SHaojian Zhuang (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 13430f833caSLoh Tien Hock return -ENOENT; 13530f833caSLoh Tien Hock } 13630f833caSLoh Tien Hock offset = (uintptr_t)&mbr_sector + 13730f833caSLoh Tien Hock MBR_PRIMARY_ENTRY_OFFSET + 13830f833caSLoh Tien Hock MBR_PRIMARY_ENTRY_SIZE * part_number; 13930f833caSLoh Tien Hock memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 14030f833caSLoh Tien Hock 14130f833caSLoh Tien Hock return 0; 14230f833caSLoh Tien Hock } 14330f833caSLoh Tien Hock 14430f833caSLoh Tien Hock static int load_mbr_entries(uintptr_t image_handle) 14530f833caSLoh Tien Hock { 14630f833caSLoh Tien Hock mbr_entry_t mbr_entry; 14730f833caSLoh Tien Hock int i; 14830f833caSLoh Tien Hock 14930f833caSLoh Tien Hock list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; 15030f833caSLoh Tien Hock 15130f833caSLoh Tien Hock for (i = 0; i < list.entry_count; i++) { 15230f833caSLoh Tien Hock load_mbr_entry(image_handle, &mbr_entry, i); 15330f833caSLoh Tien Hock list.list[i].start = mbr_entry.first_lba * 512; 15430f833caSLoh Tien Hock list.list[i].length = mbr_entry.sector_nums * 512; 15530f833caSLoh Tien Hock list.list[i].name[0] = mbr_entry.type; 15630f833caSLoh Tien Hock } 15730f833caSLoh Tien Hock 15830f833caSLoh Tien Hock return 0; 15930f833caSLoh Tien Hock } 16030f833caSLoh Tien Hock 161201b66b7SHaojian Zhuang static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 162201b66b7SHaojian Zhuang { 163201b66b7SHaojian Zhuang size_t bytes_read; 164201b66b7SHaojian Zhuang int result; 165201b66b7SHaojian Zhuang 166201b66b7SHaojian Zhuang assert(entry != NULL); 167201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 168201b66b7SHaojian Zhuang &bytes_read); 169201b66b7SHaojian Zhuang if (sizeof(gpt_entry_t) != bytes_read) 170201b66b7SHaojian Zhuang return -EINVAL; 171201b66b7SHaojian Zhuang return result; 172201b66b7SHaojian Zhuang } 173201b66b7SHaojian Zhuang 174201b66b7SHaojian Zhuang static int verify_partition_gpt(uintptr_t image_handle) 175201b66b7SHaojian Zhuang { 176201b66b7SHaojian Zhuang gpt_entry_t entry; 177201b66b7SHaojian Zhuang int result, i; 178201b66b7SHaojian Zhuang 179201b66b7SHaojian Zhuang for (i = 0; i < list.entry_count; i++) { 180201b66b7SHaojian Zhuang result = load_gpt_entry(image_handle, &entry); 181201b66b7SHaojian Zhuang assert(result == 0); 182201b66b7SHaojian Zhuang result = parse_gpt_entry(&entry, &list.list[i]); 183201b66b7SHaojian Zhuang if (result != 0) { 184201b66b7SHaojian Zhuang break; 185201b66b7SHaojian Zhuang } 186201b66b7SHaojian Zhuang } 187201b66b7SHaojian Zhuang if (i == 0) { 188201b66b7SHaojian Zhuang return -EINVAL; 189201b66b7SHaojian Zhuang } 190201b66b7SHaojian Zhuang /* 191201b66b7SHaojian Zhuang * Only records the valid partition number that is loaded from 192201b66b7SHaojian Zhuang * partition table. 193201b66b7SHaojian Zhuang */ 194201b66b7SHaojian Zhuang list.entry_count = i; 195201b66b7SHaojian Zhuang dump_entries(list.entry_count); 196201b66b7SHaojian Zhuang 197201b66b7SHaojian Zhuang return 0; 198201b66b7SHaojian Zhuang } 199201b66b7SHaojian Zhuang 200201b66b7SHaojian Zhuang int load_partition_table(unsigned int image_id) 201201b66b7SHaojian Zhuang { 202201b66b7SHaojian Zhuang uintptr_t dev_handle, image_handle, image_spec = 0; 203201b66b7SHaojian Zhuang mbr_entry_t mbr_entry; 204201b66b7SHaojian Zhuang int result; 205201b66b7SHaojian Zhuang 206201b66b7SHaojian Zhuang result = plat_get_image_source(image_id, &dev_handle, &image_spec); 207201b66b7SHaojian Zhuang if (result != 0) { 208201b66b7SHaojian Zhuang WARN("Failed to obtain reference to image id=%u (%i)\n", 209201b66b7SHaojian Zhuang image_id, result); 210201b66b7SHaojian Zhuang return result; 211201b66b7SHaojian Zhuang } 212201b66b7SHaojian Zhuang 213201b66b7SHaojian Zhuang result = io_open(dev_handle, image_spec, &image_handle); 214201b66b7SHaojian Zhuang if (result != 0) { 215201b66b7SHaojian Zhuang WARN("Failed to access image id=%u (%i)\n", image_id, result); 216201b66b7SHaojian Zhuang return result; 217201b66b7SHaojian Zhuang } 218201b66b7SHaojian Zhuang 219201b66b7SHaojian Zhuang result = load_mbr_header(image_handle, &mbr_entry); 220201b66b7SHaojian Zhuang if (result != 0) { 221201b66b7SHaojian Zhuang WARN("Failed to access image id=%u (%i)\n", image_id, result); 222201b66b7SHaojian Zhuang return result; 223201b66b7SHaojian Zhuang } 224201b66b7SHaojian Zhuang if (mbr_entry.type == PARTITION_TYPE_GPT) { 225201b66b7SHaojian Zhuang result = load_gpt_header(image_handle); 226201b66b7SHaojian Zhuang assert(result == 0); 227201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); 228201b66b7SHaojian Zhuang assert(result == 0); 229201b66b7SHaojian Zhuang result = verify_partition_gpt(image_handle); 230201b66b7SHaojian Zhuang } else { 23130f833caSLoh Tien Hock result = load_mbr_entries(image_handle); 232201b66b7SHaojian Zhuang } 23330f833caSLoh Tien Hock 234201b66b7SHaojian Zhuang io_close(image_handle); 235201b66b7SHaojian Zhuang return result; 236201b66b7SHaojian Zhuang } 237201b66b7SHaojian Zhuang 238201b66b7SHaojian Zhuang const partition_entry_t *get_partition_entry(const char *name) 239201b66b7SHaojian Zhuang { 240201b66b7SHaojian Zhuang int i; 241201b66b7SHaojian Zhuang 242201b66b7SHaojian Zhuang for (i = 0; i < list.entry_count; i++) { 243201b66b7SHaojian Zhuang if (strcmp(name, list.list[i].name) == 0) { 244201b66b7SHaojian Zhuang return &list.list[i]; 245201b66b7SHaojian Zhuang } 246201b66b7SHaojian Zhuang } 247201b66b7SHaojian Zhuang return NULL; 248201b66b7SHaojian Zhuang } 249201b66b7SHaojian Zhuang 250*3cb10655SSughosh Ganu const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid) 251*3cb10655SSughosh Ganu { 252*3cb10655SSughosh Ganu int i; 253*3cb10655SSughosh Ganu 254*3cb10655SSughosh Ganu for (i = 0; i < list.entry_count; i++) { 255*3cb10655SSughosh Ganu if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) { 256*3cb10655SSughosh Ganu return &list.list[i]; 257*3cb10655SSughosh Ganu } 258*3cb10655SSughosh Ganu } 259*3cb10655SSughosh Ganu 260*3cb10655SSughosh Ganu return NULL; 261*3cb10655SSughosh Ganu } 262*3cb10655SSughosh Ganu 263201b66b7SHaojian Zhuang const partition_entry_list_t *get_partition_entry_list(void) 264201b66b7SHaojian Zhuang { 265201b66b7SHaojian Zhuang return &list; 266201b66b7SHaojian Zhuang } 267201b66b7SHaojian Zhuang 268201b66b7SHaojian Zhuang void partition_init(unsigned int image_id) 269201b66b7SHaojian Zhuang { 270201b66b7SHaojian Zhuang load_partition_table(image_id); 271201b66b7SHaojian Zhuang } 272