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 WARN("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 WARN("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 return -ENOENT; 73 } 74 75 tmp = (mbr_entry_t *)(&mbr_sector[MBR_PRIMARY_ENTRY_OFFSET]); 76 77 if (tmp->first_lba != 1) { 78 WARN("MBR header may have an invalid first LBA\n"); 79 return -EINVAL; 80 } 81 82 if ((tmp->sector_nums == 0) || (tmp->sector_nums == UINT32_MAX)) { 83 WARN("MBR header entry has an invalid number of sectors\n"); 84 return -EINVAL; 85 } 86 87 memcpy(mbr_entry, tmp, sizeof(mbr_entry_t)); 88 return 0; 89 } 90 91 /* 92 * Load GPT header and check the GPT signature and header CRC. 93 * If partition numbers could be found, check & update it. 94 */ 95 static int load_gpt_header(uintptr_t image_handle, size_t header_offset, 96 unsigned long long *part_lba) 97 { 98 gpt_header_t header; 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 return result; 106 } 107 result = io_read(image_handle, (uintptr_t)&header, 108 sizeof(gpt_header_t), &bytes_read); 109 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 110 return result; 111 } 112 if (memcmp(header.signature, GPT_SIGNATURE, 113 sizeof(header.signature)) != 0) { 114 return -EINVAL; 115 } 116 117 /* 118 * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is 119 * computed by setting this field to 0, and computing the 120 * 32-bit CRC for HeaderSize bytes. 121 */ 122 header_crc = header.header_crc; 123 header.header_crc = 0U; 124 125 calc_crc = tf_crc32(0U, (uint8_t *)&header, sizeof(gpt_header_t)); 126 if (header_crc != calc_crc) { 127 ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n", 128 header_crc, calc_crc); 129 return -EINVAL; 130 } 131 132 header.header_crc = header_crc; 133 134 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 135 list.entry_count = header.list_num; 136 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 137 list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 138 } 139 140 *part_lba = header.part_lba; 141 return 0; 142 } 143 144 static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, 145 int part_number) 146 { 147 size_t bytes_read; 148 uintptr_t offset; 149 int result; 150 151 assert(mbr_entry != NULL); 152 /* MBR partition table is in LBA0. */ 153 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 154 if (result != 0) { 155 WARN("Failed to seek (%i)\n", result); 156 return result; 157 } 158 result = io_read(image_handle, (uintptr_t)&mbr_sector, 159 PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 160 if (result != 0) { 161 WARN("Failed to read data (%i)\n", result); 162 return result; 163 } 164 165 /* Check MBR boot signature. */ 166 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 167 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 168 return -ENOENT; 169 } 170 offset = (uintptr_t)&mbr_sector + 171 MBR_PRIMARY_ENTRY_OFFSET + 172 MBR_PRIMARY_ENTRY_SIZE * part_number; 173 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 174 175 return 0; 176 } 177 178 static int load_mbr_entries(uintptr_t image_handle) 179 { 180 mbr_entry_t mbr_entry; 181 int i; 182 183 list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; 184 185 for (i = 0; i < list.entry_count; i++) { 186 load_mbr_entry(image_handle, &mbr_entry, i); 187 list.list[i].start = mbr_entry.first_lba * 512; 188 list.list[i].length = mbr_entry.sector_nums * 512; 189 list.list[i].name[0] = mbr_entry.type; 190 } 191 192 return 0; 193 } 194 195 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 196 { 197 size_t bytes_read; 198 int result; 199 200 assert(entry != NULL); 201 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 202 &bytes_read); 203 if (sizeof(gpt_entry_t) != bytes_read) 204 return -EINVAL; 205 return result; 206 } 207 208 static int verify_partition_gpt(uintptr_t image_handle) 209 { 210 gpt_entry_t entry; 211 int result, i; 212 213 for (i = 0; i < list.entry_count; i++) { 214 result = load_gpt_entry(image_handle, &entry); 215 assert(result == 0); 216 result = parse_gpt_entry(&entry, &list.list[i]); 217 if (result != 0) { 218 break; 219 } 220 } 221 if (i == 0) { 222 return -EINVAL; 223 } 224 /* 225 * Only records the valid partition number that is loaded from 226 * partition table. 227 */ 228 list.entry_count = i; 229 dump_entries(list.entry_count); 230 231 return 0; 232 } 233 234 int load_partition_table(unsigned int image_id) 235 { 236 uintptr_t dev_handle, image_handle, image_spec = 0; 237 mbr_entry_t mbr_entry; 238 int result; 239 size_t gpt_header_offset; 240 unsigned long long part_lba = 0, gpt_entry_offset = 0; 241 242 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 243 if (result != 0) { 244 WARN("Failed to obtain reference to image id=%u (%i)\n", 245 image_id, result); 246 return result; 247 } 248 249 result = io_open(dev_handle, image_spec, &image_handle); 250 if (result != 0) { 251 WARN("Failed to access image id=%u (%i)\n", image_id, result); 252 return result; 253 } 254 255 result = load_mbr_header(image_handle, &mbr_entry); 256 if (result != 0) { 257 WARN("Failed to access image id=%u (%i)\n", image_id, result); 258 return result; 259 } 260 if (mbr_entry.type == PARTITION_TYPE_GPT) { 261 /* Try to load GPT header from LBA-1 */ 262 gpt_header_offset = mbr_entry.first_lba * PLAT_PARTITION_BLOCK_SIZE; 263 result = load_gpt_header(image_handle, gpt_header_offset, &part_lba); 264 if (result != 0 || part_lba == 0) { 265 WARN("Failed to retrieve Primary GPT header\n"); 266 return result; 267 } 268 269 gpt_entry_offset = part_lba * PLAT_PARTITION_BLOCK_SIZE; 270 result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset); 271 if (result != 0) { 272 WARN("Failed to seek (%i)," 273 "Failed loading GPT partition table entries\n", 274 result); 275 return result; 276 } 277 result = verify_partition_gpt(image_handle); 278 } else { 279 result = load_mbr_entries(image_handle); 280 } 281 282 io_close(image_handle); 283 return result; 284 } 285 286 const partition_entry_t *get_partition_entry(const char *name) 287 { 288 int i; 289 290 for (i = 0; i < list.entry_count; i++) { 291 if (strcmp(name, list.list[i].name) == 0) { 292 return &list.list[i]; 293 } 294 } 295 return NULL; 296 } 297 298 const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid) 299 { 300 int i; 301 302 for (i = 0; i < list.entry_count; i++) { 303 if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) { 304 return &list.list[i]; 305 } 306 } 307 308 return NULL; 309 } 310 311 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid) 312 { 313 int i; 314 315 for (i = 0; i < list.entry_count; i++) { 316 if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) { 317 return &list.list[i]; 318 } 319 } 320 321 return NULL; 322 } 323 324 const partition_entry_list_t *get_partition_entry_list(void) 325 { 326 return &list; 327 } 328 329 void partition_init(unsigned int image_id) 330 { 331 load_partition_table(image_id); 332 } 333