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