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