1 /* 2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <debug.h> 33 #include <io_storage.h> 34 #include <gpt.h> 35 #include <mbr.h> 36 #include <partition.h> 37 #include <platform.h> 38 #include <string.h> 39 40 static uint8_t mbr_sector[PARTITION_BLOCK_SIZE]; 41 partition_entry_list_t list; 42 43 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 44 static void dump_entries(int num) 45 { 46 char name[EFI_NAMELEN]; 47 int i, j, len; 48 49 VERBOSE("Partition table with %d entries:\n", num); 50 for (i = 0; i < num; i++) { 51 len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 52 for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 53 name[len + j] = ' '; 54 } 55 name[EFI_NAMELEN - 1] = '\0'; 56 VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start, 57 list.list[i].start + list.list[i].length - 4); 58 } 59 } 60 #else 61 #define dump_entries(num) ((void)num) 62 #endif 63 64 /* 65 * Load the first sector that carries MBR header. 66 * The MBR boot signature should be always valid whether it's MBR or GPT. 67 */ 68 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 69 { 70 size_t bytes_read; 71 uintptr_t offset; 72 int result; 73 74 assert(mbr_entry != NULL); 75 /* MBR partition table is in LBA0. */ 76 result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 77 if (result != 0) { 78 WARN("Failed to seek (%i)\n", result); 79 return result; 80 } 81 result = io_read(image_handle, (uintptr_t)&mbr_sector, 82 PARTITION_BLOCK_SIZE, &bytes_read); 83 if (result != 0) { 84 WARN("Failed to read data (%i)\n", result); 85 return result; 86 } 87 88 /* Check MBR boot signature. */ 89 if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 90 (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 91 return -ENOENT; 92 } 93 offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; 94 memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 95 return 0; 96 } 97 98 /* 99 * Load GPT header and check the GPT signature. 100 * If partiton numbers could be found, check & update it. 101 */ 102 static int load_gpt_header(uintptr_t image_handle) 103 { 104 gpt_header_t header; 105 size_t bytes_read; 106 int result; 107 108 result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); 109 if (result != 0) { 110 return result; 111 } 112 result = io_read(image_handle, (uintptr_t)&header, 113 sizeof(gpt_header_t), &bytes_read); 114 if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 115 return result; 116 } 117 if (memcmp(header.signature, GPT_SIGNATURE, 118 sizeof(header.signature)) != 0) { 119 return -EINVAL; 120 } 121 122 /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 123 list.entry_count = header.list_num; 124 if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 125 list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 126 } 127 return 0; 128 } 129 130 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 131 { 132 size_t bytes_read; 133 int result; 134 135 assert(entry != NULL); 136 result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 137 &bytes_read); 138 if (sizeof(gpt_entry_t) != bytes_read) 139 return -EINVAL; 140 return result; 141 } 142 143 static int verify_partition_gpt(uintptr_t image_handle) 144 { 145 gpt_entry_t entry; 146 int result, i; 147 148 for (i = 0; i < list.entry_count; i++) { 149 result = load_gpt_entry(image_handle, &entry); 150 assert(result == 0); 151 result = parse_gpt_entry(&entry, &list.list[i]); 152 if (result != 0) { 153 break; 154 } 155 } 156 if (i == 0) { 157 return -EINVAL; 158 } 159 /* 160 * Only records the valid partition number that is loaded from 161 * partition table. 162 */ 163 list.entry_count = i; 164 dump_entries(list.entry_count); 165 166 return 0; 167 } 168 169 int load_partition_table(unsigned int image_id) 170 { 171 uintptr_t dev_handle, image_handle, image_spec = 0; 172 mbr_entry_t mbr_entry; 173 int result; 174 175 result = plat_get_image_source(image_id, &dev_handle, &image_spec); 176 if (result != 0) { 177 WARN("Failed to obtain reference to image id=%u (%i)\n", 178 image_id, result); 179 return result; 180 } 181 182 result = io_open(dev_handle, image_spec, &image_handle); 183 if (result != 0) { 184 WARN("Failed to access image id=%u (%i)\n", image_id, result); 185 return result; 186 } 187 188 result = load_mbr_header(image_handle, &mbr_entry); 189 if (result != 0) { 190 WARN("Failed to access image id=%u (%i)\n", image_id, result); 191 return result; 192 } 193 if (mbr_entry.type == PARTITION_TYPE_GPT) { 194 result = load_gpt_header(image_handle); 195 assert(result == 0); 196 result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); 197 assert(result == 0); 198 result = verify_partition_gpt(image_handle); 199 } else { 200 /* MBR type isn't supported yet. */ 201 result = -EINVAL; 202 goto exit; 203 } 204 exit: 205 io_close(image_handle); 206 return result; 207 } 208 209 const partition_entry_t *get_partition_entry(const char *name) 210 { 211 int i; 212 213 for (i = 0; i < list.entry_count; i++) { 214 if (strcmp(name, list.list[i].name) == 0) { 215 return &list.list[i]; 216 } 217 } 218 return NULL; 219 } 220 221 const partition_entry_list_t *get_partition_entry_list(void) 222 { 223 return &list; 224 } 225 226 void partition_init(unsigned int image_id) 227 { 228 load_partition_table(image_id); 229 } 230