1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "gpt.h" 35 36 #include "spdk/crc32.h" 37 #include "spdk/endian.h" 38 #include "spdk/event.h" 39 40 #include "spdk_internal/log.h" 41 42 #define GPT_PRIMARY_PARTITION_TABLE_LBA 0x1 43 #define PRIMARY_PARTITION_NUMBER 4 44 #define GPT_PROTECTIVE_MBR 1 45 #define SPDK_MAX_NUM_PARTITION_ENTRIES 128 46 47 static uint64_t 48 spdk_gpt_get_expected_head_lba(struct spdk_gpt *gpt) 49 { 50 switch (gpt->parse_phase) { 51 case SPDK_GPT_PARSE_PHASE_PRIMARY: 52 return GPT_PRIMARY_PARTITION_TABLE_LBA; 53 case SPDK_GPT_PARSE_PHASE_SECONDARY: 54 return gpt->lba_end; 55 default: 56 assert(false); 57 } 58 return 0; 59 } 60 61 static struct spdk_gpt_header * 62 spdk_gpt_get_header_buf(struct spdk_gpt *gpt) 63 { 64 switch (gpt->parse_phase) { 65 case SPDK_GPT_PARSE_PHASE_PRIMARY: 66 return (struct spdk_gpt_header *) 67 (gpt->buf + GPT_PRIMARY_PARTITION_TABLE_LBA * gpt->sector_size); 68 case SPDK_GPT_PARSE_PHASE_SECONDARY: 69 return (struct spdk_gpt_header *) 70 (gpt->buf + (gpt->buf_size - gpt->sector_size)); 71 default: 72 assert(false); 73 } 74 return NULL; 75 } 76 77 static struct spdk_gpt_partition_entry * 78 spdk_gpt_get_partitions_buf(struct spdk_gpt *gpt, uint64_t total_partition_size, 79 uint64_t partition_start_lba) 80 { 81 uint64_t secondary_total_size; 82 83 switch (gpt->parse_phase) { 84 case SPDK_GPT_PARSE_PHASE_PRIMARY: 85 if ((total_partition_size + partition_start_lba * gpt->sector_size) > 86 gpt->buf_size) { 87 SPDK_ERRLOG("Buffer size is not enough\n"); 88 return NULL; 89 } 90 return (struct spdk_gpt_partition_entry *) 91 (gpt->buf + partition_start_lba * gpt->sector_size); 92 case SPDK_GPT_PARSE_PHASE_SECONDARY: 93 secondary_total_size = (gpt->lba_end - partition_start_lba + 1) * gpt->sector_size; 94 if (secondary_total_size > gpt->buf_size) { 95 SPDK_ERRLOG("Buffer size is not enough\n"); 96 return NULL; 97 } 98 return (struct spdk_gpt_partition_entry *) 99 (gpt->buf + (gpt->buf_size - secondary_total_size)); 100 default: 101 assert(false); 102 } 103 return NULL; 104 } 105 106 static int 107 spdk_gpt_read_partitions(struct spdk_gpt *gpt) 108 { 109 uint32_t total_partition_size, num_partition_entries, partition_entry_size; 110 uint64_t partition_start_lba; 111 struct spdk_gpt_header *head = gpt->header; 112 uint32_t crc32; 113 114 num_partition_entries = from_le32(&head->num_partition_entries); 115 if (num_partition_entries > SPDK_MAX_NUM_PARTITION_ENTRIES) { 116 SPDK_ERRLOG("Num_partition_entries=%u which exceeds max=%u\n", 117 num_partition_entries, SPDK_MAX_NUM_PARTITION_ENTRIES); 118 return -1; 119 } 120 121 partition_entry_size = from_le32(&head->size_of_partition_entry); 122 if (partition_entry_size != sizeof(struct spdk_gpt_partition_entry)) { 123 SPDK_ERRLOG("Partition_entry_size(%x) != expected(%lx)\n", 124 partition_entry_size, sizeof(struct spdk_gpt_partition_entry)); 125 return -1; 126 } 127 128 total_partition_size = num_partition_entries * partition_entry_size; 129 partition_start_lba = from_le64(&head->partition_entry_lba); 130 gpt->partitions = spdk_gpt_get_partitions_buf(gpt, total_partition_size, 131 partition_start_lba); 132 if (!gpt->partitions) { 133 SPDK_ERRLOG("Failed to get gpt partitions buf\n"); 134 return -1; 135 } 136 137 crc32 = spdk_crc32_ieee_update(gpt->partitions, total_partition_size, ~0); 138 crc32 ^= ~0; 139 140 if (crc32 != from_le32(&head->partition_entry_array_crc32)) { 141 SPDK_ERRLOG("GPT partition entry array crc32 did not match\n"); 142 return -1; 143 } 144 145 return 0; 146 } 147 148 static int 149 spdk_gpt_lba_range_check(struct spdk_gpt_header *head, uint64_t lba_end) 150 { 151 uint64_t usable_lba_start, usable_lba_end; 152 153 usable_lba_start = from_le64(&head->first_usable_lba); 154 usable_lba_end = from_le64(&head->last_usable_lba); 155 156 if (usable_lba_end < usable_lba_start) { 157 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") < usable_lba_start(%" PRIu64 ")\n", 158 usable_lba_end, usable_lba_start); 159 return -1; 160 } 161 162 if (usable_lba_end > lba_end) { 163 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") > lba_end(%" PRIu64 ")\n", 164 usable_lba_end, lba_end); 165 return -1; 166 } 167 168 if ((usable_lba_start < GPT_PRIMARY_PARTITION_TABLE_LBA) && 169 (GPT_PRIMARY_PARTITION_TABLE_LBA < usable_lba_end)) { 170 SPDK_ERRLOG("Head lba is not in the usable range\n"); 171 return -1; 172 } 173 174 return 0; 175 } 176 177 static int 178 spdk_gpt_read_header(struct spdk_gpt *gpt) 179 { 180 uint32_t head_size; 181 uint32_t new_crc, original_crc; 182 uint64_t my_lba, head_lba; 183 struct spdk_gpt_header *head; 184 185 head = spdk_gpt_get_header_buf(gpt); 186 if (!head) { 187 SPDK_ERRLOG("Failed to get gpt header buf\n"); 188 return -1; 189 } 190 191 head_size = from_le32(&head->header_size); 192 if (head_size < sizeof(*head) || head_size > gpt->sector_size) { 193 SPDK_ERRLOG("head_size=%u\n", head_size); 194 return -1; 195 } 196 197 original_crc = from_le32(&head->header_crc32); 198 head->header_crc32 = 0; 199 new_crc = spdk_crc32_ieee_update(head, from_le32(&head->header_size), ~0); 200 new_crc ^= ~0; 201 /* restore header crc32 */ 202 to_le32(&head->header_crc32, original_crc); 203 204 if (new_crc != original_crc) { 205 SPDK_ERRLOG("head crc32 does not match, provided=%u, caculated=%u\n", 206 original_crc, new_crc); 207 return -1; 208 } 209 210 if (memcmp(SPDK_GPT_SIGNATURE, head->gpt_signature, 211 sizeof(head->gpt_signature))) { 212 SPDK_ERRLOG("signature did not match\n"); 213 return -1; 214 } 215 216 head_lba = spdk_gpt_get_expected_head_lba(gpt); 217 my_lba = from_le64(&head->my_lba); 218 if (my_lba != head_lba) { 219 SPDK_ERRLOG("head my_lba(%" PRIu64 ") != expected(%" PRIu64 ")\n", 220 my_lba, head_lba); 221 return -1; 222 } 223 224 if (spdk_gpt_lba_range_check(head, gpt->lba_end)) { 225 SPDK_ERRLOG("lba range check error\n"); 226 return -1; 227 } 228 229 gpt->header = head; 230 return 0; 231 } 232 233 static int 234 spdk_gpt_check_mbr(struct spdk_gpt *gpt) 235 { 236 int i, primary_partition = 0; 237 uint32_t total_lba_size = 0, ret = 0, expected_start_lba; 238 struct spdk_mbr *mbr; 239 240 mbr = (struct spdk_mbr *)gpt->buf; 241 if (from_le16(&mbr->mbr_signature) != SPDK_MBR_SIGNATURE) { 242 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Signature mismatch, provided=%x," 243 "expected=%x\n", from_le16(&mbr->disk_signature), 244 SPDK_MBR_SIGNATURE); 245 return -1; 246 } 247 248 for (i = 0; i < PRIMARY_PARTITION_NUMBER; i++) { 249 if (mbr->partitions[i].os_type == SPDK_MBR_OS_TYPE_GPT_PROTECTIVE) { 250 primary_partition = i; 251 ret = GPT_PROTECTIVE_MBR; 252 break; 253 } 254 } 255 256 if (ret == GPT_PROTECTIVE_MBR) { 257 expected_start_lba = GPT_PRIMARY_PARTITION_TABLE_LBA; 258 if (from_le32(&mbr->partitions[primary_partition].start_lba) != expected_start_lba) { 259 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "start lba mismatch, provided=%u, expected=%u\n", 260 from_le32(&mbr->partitions[primary_partition].start_lba), 261 expected_start_lba); 262 return -1; 263 } 264 265 total_lba_size = from_le32(&mbr->partitions[primary_partition].size_lba); 266 if ((total_lba_size != ((uint32_t) gpt->total_sectors - 1)) && 267 (total_lba_size != 0xFFFFFFFF)) { 268 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, 269 "GPT Primary MBR size does not equal: (record_size %u != actual_size %u)!\n", 270 total_lba_size, (uint32_t) gpt->total_sectors - 1); 271 return -1; 272 } 273 } else { 274 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Currently only support GPT Protective MBR format\n"); 275 return -1; 276 } 277 278 return 0; 279 } 280 281 int 282 spdk_gpt_parse_mbr(struct spdk_gpt *gpt) 283 { 284 int rc; 285 286 if (!gpt || !gpt->buf) { 287 SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n"); 288 return -1; 289 } 290 291 rc = spdk_gpt_check_mbr(gpt); 292 if (rc) { 293 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Failed to detect gpt in MBR\n"); 294 return rc; 295 } 296 297 return 0; 298 } 299 300 int 301 spdk_gpt_parse_partition_table(struct spdk_gpt *gpt) 302 { 303 int rc; 304 305 rc = spdk_gpt_read_header(gpt); 306 if (rc) { 307 SPDK_ERRLOG("Failed to read gpt header\n"); 308 return rc; 309 } 310 311 rc = spdk_gpt_read_partitions(gpt); 312 if (rc) { 313 SPDK_ERRLOG("Failed to read gpt partitions\n"); 314 return rc; 315 } 316 317 return 0; 318 } 319 320 SPDK_LOG_REGISTER_COMPONENT("gpt_parse", SPDK_LOG_GPT_PARSE) 321