1 /* 2 * Copyright (c) 2016-2023, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <inttypes.h> 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <common/debug.h> 13 #include <common/tf_crc32.h> 14 #include <drivers/io/io_storage.h> 15 #include <drivers/partition/efi.h> 16 #include <drivers/partition/partition.h> 17 #include <drivers/partition/gpt.h> 18 #include <drivers/partition/mbr.h> 19 #include <plat/common/platform.h> 20 21 static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; 22 static partition_entry_list_t list; 23 24 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 25 static void dump_entries(int num) 26 { 27 char name[EFI_NAMELEN]; 28 int i, j, len; 29 30 VERBOSE("Partition table with %d entries:\n", num); 31 for (i = 0; i < num; i++) { 32 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 33 for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 34 name[len + j] = ' '; 35 } 36 name[EFI_NAMELEN - 1] = '\0'; 37 VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start, 38 list.list[i].start + list.list[i].length - 4); 39 } 40 } 41 #else 42 #define dump_entries(num) ((void)num) 43 #endif 44 45 /* 46 * Load the first sector that carries MBR header. 47 * The MBR boot signature should be always valid whether it's MBR or GPT. 48 */ 49 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 50 { 51 size_t bytes_read; 52 int result; 53 mbr_entry_t *tmp; 54 55 assert(mbr_entry != NULL); 56 /* MBR partition table is in LBA0. */ 57 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 58 if (result != 0) { 59 VERBOSE("Failed to seek (%i)\n", result); 60 return result; 61 } 62 result = io_read(image_handle, (uintptr_t)&mbr_sector, 63 PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 64 if ((result != 0) || (bytes_read != PLAT_PARTITION_BLOCK_SIZE)) { 65 VERBOSE("Failed to read data (%i)\n", result); 66 return result; 67 } 68 69 /* Check MBR boot signature. */ 70 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 71 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 72 VERBOSE("MBR boot signature failure\n"); 73 return -ENOENT; 74 } 75 76 tmp = (mbr_entry_t *)(&mbr_sector[MBR_PRIMARY_ENTRY_OFFSET]); 77 78 if (tmp->first_lba != 1) { 79 VERBOSE("MBR header may have an invalid first LBA\n"); 80 return -EINVAL; 81 } 82 83 if ((tmp->sector_nums == 0) || (tmp->sector_nums == UINT32_MAX)) { 84 VERBOSE("MBR header entry has an invalid number of sectors\n"); 85 return -EINVAL; 86 } 87 88 memcpy(mbr_entry, tmp, sizeof(mbr_entry_t)); 89 return 0; 90 } 91 92 /* 93 * Load GPT header and check the GPT signature and header CRC. 94 * If partition numbers could be found, check & update it. 95 */ 96 static int load_gpt_header(uintptr_t image_handle, size_t header_offset, 97 unsigned long long *part_lba) 98 { 99 gpt_header_t header; 100 size_t bytes_read; 101 int result; 102 uint32_t header_crc, calc_crc; 103 104 result = io_seek(image_handle, IO_SEEK_SET, header_offset); 105 if (result != 0) { 106 VERBOSE("Failed to seek into the GPT image at offset (%zu)\n", 107 header_offset); 108 return result; 109 } 110 result = io_read(image_handle, (uintptr_t)&header, 111 sizeof(gpt_header_t), &bytes_read); 112 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 113 VERBOSE("GPT header read error(%i) or read mismatch occurred," 114 "expected(%zu) and actual(%zu)\n", result, 115 sizeof(gpt_header_t), bytes_read); 116 return result; 117 } 118 if (memcmp(header.signature, GPT_SIGNATURE, 119 sizeof(header.signature)) != 0) { 120 VERBOSE("GPT header signature failure\n"); 121 return -EINVAL; 122 } 123 124 /* 125 * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is 126 * computed by setting this field to 0, and computing the 127 * 32-bit CRC for HeaderSize bytes. 128 */ 129 header_crc = header.header_crc; 130 header.header_crc = 0U; 131 132 calc_crc = tf_crc32(0U, (uint8_t *)&header, sizeof(gpt_header_t)); 133 if (header_crc != calc_crc) { 134 ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n", 135 header_crc, calc_crc); 136 return -EINVAL; 137 } 138 139 header.header_crc = header_crc; 140 141 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 142 list.entry_count = header.list_num; 143 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 144 list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 145 } 146 147 *part_lba = header.part_lba; 148 return 0; 149 } 150 151 /* 152 * Load a single MBR entry based on details from MBR header. 153 */ 154 static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, 155 int part_number) 156 { 157 size_t bytes_read; 158 uintptr_t offset; 159 int result; 160 161 assert(mbr_entry != NULL); 162 /* MBR partition table is in LBA0. */ 163 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 164 if (result != 0) { 165 VERBOSE("Failed to seek (%i)\n", result); 166 return result; 167 } 168 result = io_read(image_handle, (uintptr_t)&mbr_sector, 169 PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 170 if (result != 0) { 171 VERBOSE("Failed to read data (%i)\n", result); 172 return result; 173 } 174 175 /* Check MBR boot signature. */ 176 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 177 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 178 VERBOSE("MBR Entry boot signature failure\n"); 179 return -ENOENT; 180 } 181 offset = (uintptr_t)&mbr_sector + 182 MBR_PRIMARY_ENTRY_OFFSET + 183 MBR_PRIMARY_ENTRY_SIZE * part_number; 184 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 185 186 return 0; 187 } 188 189 /* 190 * Load MBR entries based on max number of partition entries. 191 */ 192 static int load_mbr_entries(uintptr_t image_handle) 193 { 194 mbr_entry_t mbr_entry; 195 int i; 196 197 list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; 198 199 for (i = 0; i < list.entry_count; i++) { 200 load_mbr_entry(image_handle, &mbr_entry, i); 201 list.list[i].start = mbr_entry.first_lba * 512; 202 list.list[i].length = mbr_entry.sector_nums * 512; 203 list.list[i].name[0] = mbr_entry.type; 204 } 205 206 return 0; 207 } 208 209 /* 210 * Try to read and load a single GPT entry. 211 */ 212 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 213 { 214 size_t bytes_read = 0U; 215 int result; 216 217 assert(entry != NULL); 218 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 219 &bytes_read); 220 if ((result != 0) || (sizeof(gpt_entry_t) != bytes_read)) { 221 VERBOSE("GPT Entry read error(%i) or read mismatch occurred," 222 "expected(%zu) and actual(%zu)\n", result, 223 sizeof(gpt_entry_t), bytes_read); 224 return -EINVAL; 225 } 226 227 return result; 228 } 229 230 /* 231 * Retrieve each entry in the partition table, parse the data from each 232 * entry and store them in the list of partition table entries. 233 */ 234 static int load_partition_gpt(uintptr_t image_handle, 235 unsigned long long part_lba) 236 { 237 const signed long long gpt_entry_offset = LBA(part_lba); 238 gpt_entry_t entry; 239 int result, i; 240 241 result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset); 242 if (result != 0) { 243 VERBOSE("Failed to seek (%i), Failed loading GPT partition" 244 "table entries\n", result); 245 return result; 246 } 247 248 for (i = 0; i < list.entry_count; i++) { 249 result = load_gpt_entry(image_handle, &entry); 250 if (result != 0) { 251 VERBOSE("Failed to load gpt entry data(%i) error is (%i)\n", 252 i, result); 253 return result; 254 } 255 256 result = parse_gpt_entry(&entry, &list.list[i]); 257 if (result != 0) { 258 break; 259 } 260 } 261 if (i == 0) { 262 VERBOSE("No Valid GPT Entries found\n"); 263 return -EINVAL; 264 } 265 /* 266 * Only records the valid partition number that is loaded from 267 * partition table. 268 */ 269 list.entry_count = i; 270 dump_entries(list.entry_count); 271 272 return 0; 273 } 274 275 /* 276 * Try retrieving and parsing the backup-GPT header and backup GPT entries. 277 * Last 33 blocks contains the backup-GPT entries and header. 278 */ 279 static int load_backup_gpt(unsigned int image_id, unsigned int sector_nums) 280 { 281 int result; 282 unsigned long long part_lba = 0; 283 size_t gpt_header_offset; 284 uintptr_t dev_handle, image_spec, image_handle; 285 io_block_spec_t *block_spec; 286 int part_num_entries; 287 288 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 289 if (result != 0) { 290 VERBOSE("Failed to obtain reference to image id=%u (%i)\n", 291 image_id, result); 292 return result; 293 } 294 295 block_spec = (io_block_spec_t *)image_spec; 296 /* 297 * We need to read 32 blocks of GPT entries and one block of GPT header 298 * try mapping only last 33 last blocks from the image to read the 299 * Backup-GPT header and its entries. 300 */ 301 part_num_entries = (PLAT_PARTITION_MAX_ENTRIES / 4); 302 /* Move the offset base to LBA-33 */ 303 block_spec->offset += LBA(sector_nums - part_num_entries); 304 /* 305 * Set length as LBA-33, 32 blocks of backup-GPT entries and one 306 * block of backup-GPT header. 307 */ 308 block_spec->length = LBA(part_num_entries + 1); 309 310 result = io_open(dev_handle, image_spec, &image_handle); 311 if (result != 0) { 312 VERBOSE("Failed to access image id (%i)\n", result); 313 return result; 314 } 315 316 INFO("Trying to retrieve back-up GPT header\n"); 317 /* Last block is backup-GPT header, after the end of GPT entries */ 318 gpt_header_offset = LBA(part_num_entries); 319 result = load_gpt_header(image_handle, gpt_header_offset, &part_lba); 320 if ((result != 0) || (part_lba == 0)) { 321 ERROR("Failed to retrieve Backup GPT header," 322 "Partition maybe corrupted\n"); 323 goto out; 324 } 325 326 /* 327 * Note we mapped last 33 blocks(LBA-33), first block here starts with 328 * entries while last block was header. 329 */ 330 result = load_partition_gpt(image_handle, 0); 331 332 out: 333 io_close(image_handle); 334 return result; 335 } 336 337 /* 338 * Load a GPT partition, Try retrieving and parsing the primary GPT header, 339 * if its corrupted try loading backup GPT header and then retrieve list 340 * of partition table entries found from the GPT. 341 */ 342 static int load_primary_gpt(uintptr_t image_handle, unsigned int first_lba) 343 { 344 int result; 345 unsigned long long part_lba; 346 size_t gpt_header_offset; 347 348 /* Try to load Primary GPT header from LBA1 */ 349 gpt_header_offset = LBA(first_lba); 350 result = load_gpt_header(image_handle, gpt_header_offset, &part_lba); 351 if ((result != 0) || (part_lba == 0)) { 352 VERBOSE("Failed to retrieve Primary GPT header," 353 "trying to retrieve back-up GPT header\n"); 354 return result; 355 } 356 357 return load_partition_gpt(image_handle, part_lba); 358 } 359 360 /* 361 * Load the partition table info based on the image id provided. 362 */ 363 int load_partition_table(unsigned int image_id) 364 { 365 uintptr_t dev_handle, image_handle, image_spec = 0; 366 mbr_entry_t mbr_entry; 367 int result; 368 369 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 370 if (result != 0) { 371 VERBOSE("Failed to obtain reference to image id=%u (%i)\n", 372 image_id, result); 373 return result; 374 } 375 376 result = io_open(dev_handle, image_spec, &image_handle); 377 if (result != 0) { 378 VERBOSE("Failed to access image id=%u (%i)\n", image_id, result); 379 return result; 380 } 381 382 result = load_mbr_header(image_handle, &mbr_entry); 383 if (result != 0) { 384 VERBOSE("Failed to access image id=%u (%i)\n", image_id, result); 385 goto out; 386 } 387 if (mbr_entry.type == PARTITION_TYPE_GPT) { 388 result = load_primary_gpt(image_handle, mbr_entry.first_lba); 389 if (result != 0) { 390 io_close(image_handle); 391 return load_backup_gpt(BKUP_GPT_IMAGE_ID, 392 mbr_entry.sector_nums); 393 } 394 } else { 395 result = load_mbr_entries(image_handle); 396 } 397 398 out: 399 io_close(image_handle); 400 return result; 401 } 402 403 /* 404 * Try retrieving a partition table entry based on the name of the partition. 405 */ 406 const partition_entry_t *get_partition_entry(const char *name) 407 { 408 int i; 409 410 for (i = 0; i < list.entry_count; i++) { 411 if (strcmp(name, list.list[i].name) == 0) { 412 return &list.list[i]; 413 } 414 } 415 return NULL; 416 } 417 418 /* 419 * Try retrieving a partition table entry based on the GUID. 420 */ 421 const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid) 422 { 423 int i; 424 425 for (i = 0; i < list.entry_count; i++) { 426 if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) { 427 return &list.list[i]; 428 } 429 } 430 431 return NULL; 432 } 433 434 /* 435 * Try retrieving a partition table entry based on the UUID. 436 */ 437 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid) 438 { 439 int i; 440 441 for (i = 0; i < list.entry_count; i++) { 442 if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) { 443 return &list.list[i]; 444 } 445 } 446 447 return NULL; 448 } 449 450 /* 451 * Return entry to the list of partition table entries. 452 */ 453 const partition_entry_list_t *get_partition_entry_list(void) 454 { 455 return &list; 456 } 457 458 /* 459 * Try loading partition table info for the given image ID. 460 */ 461 void partition_init(unsigned int image_id) 462 { 463 int ret; 464 465 ret = load_partition_table(image_id); 466 if (ret != 0) { 467 ERROR("Failed to parse partition with image id = %u\n", 468 image_id); 469 } 470 } 471 472 /* 473 * Load a GPT based image. 474 */ 475 int gpt_partition_init(void) 476 { 477 return load_partition_table(GPT_IMAGE_ID); 478 } 479