1 /* 2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <debug.h> 9 #include <gpt.h> 10 #include <io_storage.h> 11 #include <mbr.h> 12 #include <partition.h> 13 #include <platform.h> 14 #include <string.h> 15 16 static uint8_t mbr_sector[PARTITION_BLOCK_SIZE]; 17 partition_entry_list_t list; 18 19 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 20 static void dump_entries(int num) 21 { 22 char name[EFI_NAMELEN]; 23 int i, j, len; 24 25 VERBOSE("Partition table with %d entries:\n", num); 26 for (i = 0; i < num; i++) { 27 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 28 for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 29 name[len + j] = ' '; 30 } 31 name[EFI_NAMELEN - 1] = '\0'; 32 VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start, 33 list.list[i].start + list.list[i].length - 4); 34 } 35 } 36 #else 37 #define dump_entries(num) ((void)num) 38 #endif 39 40 /* 41 * Load the first sector that carries MBR header. 42 * The MBR boot signature should be always valid whether it's MBR or GPT. 43 */ 44 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 45 { 46 size_t bytes_read; 47 uintptr_t offset; 48 int result; 49 50 assert(mbr_entry != NULL); 51 /* MBR partition table is in LBA0. */ 52 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 53 if (result != 0) { 54 WARN("Failed to seek (%i)\n", result); 55 return result; 56 } 57 result = io_read(image_handle, (uintptr_t)&mbr_sector, 58 PARTITION_BLOCK_SIZE, &bytes_read); 59 if (result != 0) { 60 WARN("Failed to read data (%i)\n", result); 61 return result; 62 } 63 64 /* Check MBR boot signature. */ 65 if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 66 (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 67 return -ENOENT; 68 } 69 offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; 70 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 71 return 0; 72 } 73 74 /* 75 * Load GPT header and check the GPT signature. 76 * If partiton numbers could be found, check & update it. 77 */ 78 static int load_gpt_header(uintptr_t image_handle) 79 { 80 gpt_header_t header; 81 size_t bytes_read; 82 int result; 83 84 result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); 85 if (result != 0) { 86 return result; 87 } 88 result = io_read(image_handle, (uintptr_t)&header, 89 sizeof(gpt_header_t), &bytes_read); 90 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 91 return result; 92 } 93 if (memcmp(header.signature, GPT_SIGNATURE, 94 sizeof(header.signature)) != 0) { 95 return -EINVAL; 96 } 97 98 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 99 list.entry_count = header.list_num; 100 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 101 list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 102 } 103 return 0; 104 } 105 106 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 107 { 108 size_t bytes_read; 109 int result; 110 111 assert(entry != NULL); 112 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 113 &bytes_read); 114 if (sizeof(gpt_entry_t) != bytes_read) 115 return -EINVAL; 116 return result; 117 } 118 119 static int verify_partition_gpt(uintptr_t image_handle) 120 { 121 gpt_entry_t entry; 122 int result, i; 123 124 for (i = 0; i < list.entry_count; i++) { 125 result = load_gpt_entry(image_handle, &entry); 126 assert(result == 0); 127 result = parse_gpt_entry(&entry, &list.list[i]); 128 if (result != 0) { 129 break; 130 } 131 } 132 if (i == 0) { 133 return -EINVAL; 134 } 135 /* 136 * Only records the valid partition number that is loaded from 137 * partition table. 138 */ 139 list.entry_count = i; 140 dump_entries(list.entry_count); 141 142 return 0; 143 } 144 145 int load_partition_table(unsigned int image_id) 146 { 147 uintptr_t dev_handle, image_handle, image_spec = 0; 148 mbr_entry_t mbr_entry; 149 int result; 150 151 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 152 if (result != 0) { 153 WARN("Failed to obtain reference to image id=%u (%i)\n", 154 image_id, result); 155 return result; 156 } 157 158 result = io_open(dev_handle, image_spec, &image_handle); 159 if (result != 0) { 160 WARN("Failed to access image id=%u (%i)\n", image_id, result); 161 return result; 162 } 163 164 result = load_mbr_header(image_handle, &mbr_entry); 165 if (result != 0) { 166 WARN("Failed to access image id=%u (%i)\n", image_id, result); 167 return result; 168 } 169 if (mbr_entry.type == PARTITION_TYPE_GPT) { 170 result = load_gpt_header(image_handle); 171 assert(result == 0); 172 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); 173 assert(result == 0); 174 result = verify_partition_gpt(image_handle); 175 } else { 176 /* MBR type isn't supported yet. */ 177 result = -EINVAL; 178 goto exit; 179 } 180 exit: 181 io_close(image_handle); 182 return result; 183 } 184 185 const partition_entry_t *get_partition_entry(const char *name) 186 { 187 int i; 188 189 for (i = 0; i < list.entry_count; i++) { 190 if (strcmp(name, list.list[i].name) == 0) { 191 return &list.list[i]; 192 } 193 } 194 return NULL; 195 } 196 197 const partition_entry_list_t *get_partition_entry_list(void) 198 { 199 return &list; 200 } 201 202 void partition_init(unsigned int image_id) 203 { 204 load_partition_table(image_id); 205 } 206