1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2017 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "gpt.h" 7 8 #include "spdk/crc32.h" 9 #include "spdk/endian.h" 10 #include "spdk/event.h" 11 12 #include "spdk/log.h" 13 14 #define GPT_PRIMARY_PARTITION_TABLE_LBA 0x1 15 #define PRIMARY_PARTITION_NUMBER 4 16 #define GPT_PROTECTIVE_MBR 1 17 #define SPDK_MAX_NUM_PARTITION_ENTRIES 128 18 19 static uint64_t 20 gpt_get_expected_head_lba(struct spdk_gpt *gpt) 21 { 22 switch (gpt->parse_phase) { 23 case SPDK_GPT_PARSE_PHASE_PRIMARY: 24 return GPT_PRIMARY_PARTITION_TABLE_LBA; 25 case SPDK_GPT_PARSE_PHASE_SECONDARY: 26 return gpt->lba_end; 27 default: 28 assert(false); 29 } 30 return 0; 31 } 32 33 static struct spdk_gpt_header * 34 gpt_get_header_buf(struct spdk_gpt *gpt) 35 { 36 switch (gpt->parse_phase) { 37 case SPDK_GPT_PARSE_PHASE_PRIMARY: 38 return (struct spdk_gpt_header *) 39 (gpt->buf + GPT_PRIMARY_PARTITION_TABLE_LBA * gpt->sector_size); 40 case SPDK_GPT_PARSE_PHASE_SECONDARY: 41 return (struct spdk_gpt_header *) 42 (gpt->buf + (gpt->buf_size - gpt->sector_size)); 43 default: 44 assert(false); 45 } 46 return NULL; 47 } 48 49 static struct spdk_gpt_partition_entry * 50 gpt_get_partitions_buf(struct spdk_gpt *gpt, uint64_t total_partition_size, 51 uint64_t partition_start_lba) 52 { 53 uint64_t secondary_total_size; 54 55 switch (gpt->parse_phase) { 56 case SPDK_GPT_PARSE_PHASE_PRIMARY: 57 if ((total_partition_size + partition_start_lba * gpt->sector_size) > 58 gpt->buf_size) { 59 SPDK_ERRLOG("Buffer size is not enough\n"); 60 return NULL; 61 } 62 return (struct spdk_gpt_partition_entry *) 63 (gpt->buf + partition_start_lba * gpt->sector_size); 64 case SPDK_GPT_PARSE_PHASE_SECONDARY: 65 secondary_total_size = (gpt->lba_end - partition_start_lba + 1) * gpt->sector_size; 66 if (secondary_total_size > gpt->buf_size) { 67 SPDK_ERRLOG("Buffer size is not enough\n"); 68 return NULL; 69 } 70 return (struct spdk_gpt_partition_entry *) 71 (gpt->buf + (gpt->buf_size - secondary_total_size)); 72 default: 73 assert(false); 74 } 75 return NULL; 76 } 77 78 static int 79 gpt_read_partitions(struct spdk_gpt *gpt) 80 { 81 uint32_t total_partition_size, num_partition_entries, partition_entry_size; 82 uint64_t partition_start_lba; 83 struct spdk_gpt_header *head = gpt->header; 84 uint32_t crc32; 85 86 num_partition_entries = from_le32(&head->num_partition_entries); 87 if (num_partition_entries > SPDK_MAX_NUM_PARTITION_ENTRIES) { 88 SPDK_ERRLOG("Num_partition_entries=%u which exceeds max=%u\n", 89 num_partition_entries, SPDK_MAX_NUM_PARTITION_ENTRIES); 90 return -1; 91 } 92 93 partition_entry_size = from_le32(&head->size_of_partition_entry); 94 if (partition_entry_size != sizeof(struct spdk_gpt_partition_entry)) { 95 SPDK_ERRLOG("Partition_entry_size(%x) != expected(%zx)\n", 96 partition_entry_size, sizeof(struct spdk_gpt_partition_entry)); 97 return -1; 98 } 99 100 total_partition_size = num_partition_entries * partition_entry_size; 101 partition_start_lba = from_le64(&head->partition_entry_lba); 102 gpt->partitions = gpt_get_partitions_buf(gpt, total_partition_size, 103 partition_start_lba); 104 if (!gpt->partitions) { 105 SPDK_ERRLOG("Failed to get gpt partitions buf\n"); 106 return -1; 107 } 108 109 crc32 = spdk_crc32_ieee_update(gpt->partitions, total_partition_size, ~0); 110 crc32 ^= ~0; 111 112 if (crc32 != from_le32(&head->partition_entry_array_crc32)) { 113 SPDK_ERRLOG("GPT partition entry array crc32 did not match\n"); 114 return -1; 115 } 116 117 return 0; 118 } 119 120 static int 121 gpt_lba_range_check(struct spdk_gpt_header *head, uint64_t lba_end) 122 { 123 uint64_t usable_lba_start, usable_lba_end; 124 125 usable_lba_start = from_le64(&head->first_usable_lba); 126 usable_lba_end = from_le64(&head->last_usable_lba); 127 128 if (usable_lba_end < usable_lba_start) { 129 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") < usable_lba_start(%" PRIu64 ")\n", 130 usable_lba_end, usable_lba_start); 131 return -1; 132 } 133 134 if (usable_lba_end > lba_end) { 135 SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") > lba_end(%" PRIu64 ")\n", 136 usable_lba_end, lba_end); 137 return -1; 138 } 139 140 if ((usable_lba_start < GPT_PRIMARY_PARTITION_TABLE_LBA) && 141 (GPT_PRIMARY_PARTITION_TABLE_LBA < usable_lba_end)) { 142 SPDK_ERRLOG("Head lba is not in the usable range\n"); 143 return -1; 144 } 145 146 return 0; 147 } 148 149 static int 150 gpt_read_header(struct spdk_gpt *gpt) 151 { 152 uint32_t head_size; 153 uint32_t new_crc, original_crc; 154 uint64_t my_lba, head_lba; 155 struct spdk_gpt_header *head; 156 157 head = gpt_get_header_buf(gpt); 158 if (!head) { 159 SPDK_ERRLOG("Failed to get gpt header buf\n"); 160 return -1; 161 } 162 163 head_size = from_le32(&head->header_size); 164 if (head_size < sizeof(*head) || head_size > gpt->sector_size) { 165 SPDK_ERRLOG("head_size=%u\n", head_size); 166 return -1; 167 } 168 169 original_crc = from_le32(&head->header_crc32); 170 head->header_crc32 = 0; 171 new_crc = spdk_crc32_ieee_update(head, from_le32(&head->header_size), ~0); 172 new_crc ^= ~0; 173 /* restore header crc32 */ 174 to_le32(&head->header_crc32, original_crc); 175 176 if (new_crc != original_crc) { 177 SPDK_ERRLOG("head crc32 does not match, provided=%u, calculated=%u\n", 178 original_crc, new_crc); 179 return -1; 180 } 181 182 if (memcmp(SPDK_GPT_SIGNATURE, head->gpt_signature, 183 sizeof(head->gpt_signature))) { 184 SPDK_ERRLOG("signature did not match\n"); 185 return -1; 186 } 187 188 head_lba = gpt_get_expected_head_lba(gpt); 189 my_lba = from_le64(&head->my_lba); 190 if (my_lba != head_lba) { 191 SPDK_ERRLOG("head my_lba(%" PRIu64 ") != expected(%" PRIu64 ")\n", 192 my_lba, head_lba); 193 return -1; 194 } 195 196 if (gpt_lba_range_check(head, gpt->lba_end)) { 197 SPDK_ERRLOG("lba range check error\n"); 198 return -1; 199 } 200 201 gpt->header = head; 202 return 0; 203 } 204 205 static int 206 gpt_check_mbr(struct spdk_gpt *gpt) 207 { 208 int i, primary_partition = 0; 209 uint32_t total_lba_size = 0, ret = 0, expected_start_lba; 210 struct spdk_mbr *mbr; 211 212 mbr = (struct spdk_mbr *)gpt->buf; 213 if (from_le16(&mbr->mbr_signature) != SPDK_MBR_SIGNATURE) { 214 SPDK_DEBUGLOG(gpt_parse, "Signature mismatch, provided=%x," 215 "expected=%x\n", from_le16(&mbr->disk_signature), 216 SPDK_MBR_SIGNATURE); 217 return -1; 218 } 219 220 for (i = 0; i < PRIMARY_PARTITION_NUMBER; i++) { 221 if (mbr->partitions[i].os_type == SPDK_MBR_OS_TYPE_GPT_PROTECTIVE) { 222 primary_partition = i; 223 ret = GPT_PROTECTIVE_MBR; 224 break; 225 } 226 } 227 228 if (ret == GPT_PROTECTIVE_MBR) { 229 expected_start_lba = GPT_PRIMARY_PARTITION_TABLE_LBA; 230 if (from_le32(&mbr->partitions[primary_partition].start_lba) != expected_start_lba) { 231 SPDK_DEBUGLOG(gpt_parse, "start lba mismatch, provided=%u, expected=%u\n", 232 from_le32(&mbr->partitions[primary_partition].start_lba), 233 expected_start_lba); 234 return -1; 235 } 236 237 total_lba_size = from_le32(&mbr->partitions[primary_partition].size_lba); 238 if ((total_lba_size != ((uint32_t) gpt->total_sectors - 1)) && 239 (total_lba_size != 0xFFFFFFFF)) { 240 SPDK_DEBUGLOG(gpt_parse, 241 "GPT Primary MBR size does not equal: (record_size %u != actual_size %u)!\n", 242 total_lba_size, (uint32_t) gpt->total_sectors - 1); 243 return -1; 244 } 245 } else { 246 SPDK_DEBUGLOG(gpt_parse, "Currently only support GPT Protective MBR format\n"); 247 return -1; 248 } 249 250 return 0; 251 } 252 253 int 254 gpt_parse_mbr(struct spdk_gpt *gpt) 255 { 256 int rc; 257 258 if (!gpt || !gpt->buf) { 259 SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n"); 260 return -1; 261 } 262 263 rc = gpt_check_mbr(gpt); 264 if (rc) { 265 SPDK_DEBUGLOG(gpt_parse, "Failed to detect gpt in MBR\n"); 266 return rc; 267 } 268 269 return 0; 270 } 271 272 int 273 gpt_parse_partition_table(struct spdk_gpt *gpt) 274 { 275 int rc; 276 277 rc = gpt_read_header(gpt); 278 if (rc) { 279 SPDK_ERRLOG("Failed to read gpt header\n"); 280 return rc; 281 } 282 283 rc = gpt_read_partitions(gpt); 284 if (rc) { 285 SPDK_ERRLOG("Failed to read gpt partitions\n"); 286 return rc; 287 } 288 289 return 0; 290 } 291 292 SPDK_LOG_REGISTER_COMPONENT(gpt_parse) 293