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