1 /* 2 * Copyright (c) 2016-2019, 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 <drivers/io/io_storage.h> 14 #include <drivers/partition/efi.h> 15 #include <drivers/partition/partition.h> 16 #include <drivers/partition/gpt.h> 17 #include <drivers/partition/mbr.h> 18 #include <plat/common/platform.h> 19 20 static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; 21 static partition_entry_list_t list; 22 23 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 24 static void dump_entries(int num) 25 { 26 char name[EFI_NAMELEN]; 27 int i, j, len; 28 29 VERBOSE("Partition table with %d entries:\n", num); 30 for (i = 0; i < num; i++) { 31 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 32 for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 33 name[len + j] = ' '; 34 } 35 name[EFI_NAMELEN - 1] = '\0'; 36 VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start, 37 list.list[i].start + list.list[i].length - 4); 38 } 39 } 40 #else 41 #define dump_entries(num) ((void)num) 42 #endif 43 44 /* 45 * Load the first sector that carries MBR header. 46 * The MBR boot signature should be always valid whether it's MBR or GPT. 47 */ 48 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 49 { 50 size_t bytes_read; 51 uintptr_t offset; 52 int result; 53 54 assert(mbr_entry != NULL); 55 /* MBR partition table is in LBA0. */ 56 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 57 if (result != 0) { 58 WARN("Failed to seek (%i)\n", result); 59 return result; 60 } 61 result = io_read(image_handle, (uintptr_t)&mbr_sector, 62 PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 63 if (result != 0) { 64 WARN("Failed to read data (%i)\n", result); 65 return result; 66 } 67 68 /* Check MBR boot signature. */ 69 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 70 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 71 return -ENOENT; 72 } 73 offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; 74 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 75 return 0; 76 } 77 78 /* 79 * Load GPT header and check the GPT signature. 80 * If partition numbers could be found, check & update it. 81 */ 82 static int load_gpt_header(uintptr_t image_handle) 83 { 84 gpt_header_t header; 85 size_t bytes_read; 86 int result; 87 88 result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); 89 if (result != 0) { 90 return result; 91 } 92 result = io_read(image_handle, (uintptr_t)&header, 93 sizeof(gpt_header_t), &bytes_read); 94 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 95 return result; 96 } 97 if (memcmp(header.signature, GPT_SIGNATURE, 98 sizeof(header.signature)) != 0) { 99 return -EINVAL; 100 } 101 102 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 103 list.entry_count = header.list_num; 104 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 105 list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 106 } 107 return 0; 108 } 109 110 static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, 111 int part_number) 112 { 113 size_t bytes_read; 114 uintptr_t offset; 115 int result; 116 117 assert(mbr_entry != NULL); 118 /* MBR partition table is in LBA0. */ 119 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 120 if (result != 0) { 121 WARN("Failed to seek (%i)\n", result); 122 return result; 123 } 124 result = io_read(image_handle, (uintptr_t)&mbr_sector, 125 PLAT_PARTITION_BLOCK_SIZE, &bytes_read); 126 if (result != 0) { 127 WARN("Failed to read data (%i)\n", result); 128 return result; 129 } 130 131 /* Check MBR boot signature. */ 132 if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 133 (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 134 return -ENOENT; 135 } 136 offset = (uintptr_t)&mbr_sector + 137 MBR_PRIMARY_ENTRY_OFFSET + 138 MBR_PRIMARY_ENTRY_SIZE * part_number; 139 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 140 141 return 0; 142 } 143 144 static int load_mbr_entries(uintptr_t image_handle) 145 { 146 mbr_entry_t mbr_entry; 147 int i; 148 149 list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; 150 151 for (i = 0; i < list.entry_count; i++) { 152 load_mbr_entry(image_handle, &mbr_entry, i); 153 list.list[i].start = mbr_entry.first_lba * 512; 154 list.list[i].length = mbr_entry.sector_nums * 512; 155 list.list[i].name[0] = mbr_entry.type; 156 } 157 158 return 0; 159 } 160 161 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 162 { 163 size_t bytes_read; 164 int result; 165 166 assert(entry != NULL); 167 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 168 &bytes_read); 169 if (sizeof(gpt_entry_t) != bytes_read) 170 return -EINVAL; 171 return result; 172 } 173 174 static int verify_partition_gpt(uintptr_t image_handle) 175 { 176 gpt_entry_t entry; 177 int result, i; 178 179 for (i = 0; i < list.entry_count; i++) { 180 result = load_gpt_entry(image_handle, &entry); 181 assert(result == 0); 182 result = parse_gpt_entry(&entry, &list.list[i]); 183 if (result != 0) { 184 break; 185 } 186 } 187 if (i == 0) { 188 return -EINVAL; 189 } 190 /* 191 * Only records the valid partition number that is loaded from 192 * partition table. 193 */ 194 list.entry_count = i; 195 dump_entries(list.entry_count); 196 197 return 0; 198 } 199 200 int load_partition_table(unsigned int image_id) 201 { 202 uintptr_t dev_handle, image_handle, image_spec = 0; 203 mbr_entry_t mbr_entry; 204 int result; 205 206 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 207 if (result != 0) { 208 WARN("Failed to obtain reference to image id=%u (%i)\n", 209 image_id, result); 210 return result; 211 } 212 213 result = io_open(dev_handle, image_spec, &image_handle); 214 if (result != 0) { 215 WARN("Failed to access image id=%u (%i)\n", image_id, result); 216 return result; 217 } 218 219 result = load_mbr_header(image_handle, &mbr_entry); 220 if (result != 0) { 221 WARN("Failed to access image id=%u (%i)\n", image_id, result); 222 return result; 223 } 224 if (mbr_entry.type == PARTITION_TYPE_GPT) { 225 result = load_gpt_header(image_handle); 226 assert(result == 0); 227 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); 228 assert(result == 0); 229 result = verify_partition_gpt(image_handle); 230 } else { 231 result = load_mbr_entries(image_handle); 232 } 233 234 io_close(image_handle); 235 return result; 236 } 237 238 const partition_entry_t *get_partition_entry(const char *name) 239 { 240 int i; 241 242 for (i = 0; i < list.entry_count; i++) { 243 if (strcmp(name, list.list[i].name) == 0) { 244 return &list.list[i]; 245 } 246 } 247 return NULL; 248 } 249 250 const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid) 251 { 252 int i; 253 254 for (i = 0; i < list.entry_count; i++) { 255 if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) { 256 return &list.list[i]; 257 } 258 } 259 260 return NULL; 261 } 262 263 const partition_entry_list_t *get_partition_entry_list(void) 264 { 265 return &list; 266 } 267 268 void partition_init(unsigned int image_id) 269 { 270 load_partition_table(image_id); 271 } 272