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